From f8d040492f7669aa71df3b5a3d2adc3f48804798 Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Wed, 6 Feb 2019 12:51:18 -0800 Subject: [PATCH 01/54] Correct discussion links in CONTRIBUTING.md - add a link from README.md to CONTRIBUTING.md nit: remove extra blank lines --- CONTRIBUTING.md | 11 ++++------- README.md | 4 ++++ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 87a1e8276..190f5fe9d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,7 +2,6 @@ One of the easiest ways to contribute is to participate in discussions and discuss issues. You can also contribute by submitting pull requests with code changes. - ## Bugs and feature requests? For non-security related bugs please log a new issue in this repo. @@ -12,10 +11,10 @@ Security issues and bugs should be reported privately, via email, to the Microso ## Other discussions Our team members also monitor several other discussion forums: -* [ASP.NET Core forum](https://forums.asp.net/1255.aspx/1?ASP+NET+5) -* [StackOverflow](https://stackoverflow.com/) with the [`asp.net-core`](https://stackoverflow.com/questions/tagged/asp.net-core), [`asp.net-core-mvc`](https://stackoverflow.com/questions/tagged/asp.net-core-mvc), or [`entity-framework-core`](https://stackoverflow.com/questions/tagged/entity-framework-core) tags. -* [JabbR chat room](https://jabbr.net/#/rooms/AspNetCore) for real-time discussions with the community and the people who work on the project - +* [ASP.NET MVC forum](https://forums.asp.net/1146.aspx/1?MVC) +* [ASP.NET Web API forum](hhttps://forums.asp.net/1246.aspx/1?Web+API) +* [ASP.NET Web Pages forum](https://forums.asp.net/1224.aspx/1?ASP+NET+Web+Pages) +* [StackOverflow](https://stackoverflow.com/) with the [`asp.net`](https://stackoverflow.com/questions/tagged/asp.net), [`asp.net-mvc`](https://stackoverflow.com/questions/tagged/asp.net-mvc), [`asp.net-web-api`](https://stackoverflow.com/questions/tagged/asp.net-web-api), [`asp.net-webpages`](https://stackoverflow.com/questions/tagged/asp.net-webpages) or [`razor`](https://stackoverflow.com/questions/tagged/razor) tags. ## Filing issues When filing issues, please use our [bug filing templates](https://github.com/aspnet/Home/wiki/Functional-bug-template). @@ -32,7 +31,6 @@ Here are questions you can answer before you file a bug to make sure you're not GitHub supports [markdown](https://help.github.com/articles/github-flavored-markdown/), so when filing bugs make sure you check the formatting before clicking submit. - ## Contributing code and content You will need to sign a [Contributor License Agreement](https://cla2.dotnetfoundation.org/) before submitting your pull request. To complete the Contributor License Agreement (CLA), you will need to submit a request via the form and then electronically sign the Contributor License Agreement when you receive the email containing the link to the document. This needs to only be done once for any .NET Foundation OSS project. @@ -58,4 +56,3 @@ Addresses #bugnumber (in this specific format) - Tests only need to be present for issues that need to be verified by QA (e.g. not tasks) - If there is a scenario that is far too hard to test there does not need to be a test for it. - "Too hard" is determined by the team as a whole. - diff --git a/README.md b/README.md index 5e633d5e4..436ab251d 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,10 @@ This repo includes: The latest built and tested packages from this repo are available on this MyGet feed: https://dotnet.myget.org/gallery/aspnetwebstack-dev +### Contributing + +Check out the [contributing](CONTRIBUTING.md) page to see the best places to log issues and start discussions. + ### Tags and releases Git tag|Git branch|Other products|MVC package versions|Web API package (product) versions|Web Pages package versions From 242dcf8a260e532d7a0f9ef154b7d058cbffd4eb Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Wed, 6 Feb 2019 13:18:12 -0800 Subject: [PATCH 02/54] !fixup! CONTRIBUTING.md typo --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 190f5fe9d..89c98a590 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,7 +12,7 @@ Security issues and bugs should be reported privately, via email, to the Microso Our team members also monitor several other discussion forums: * [ASP.NET MVC forum](https://forums.asp.net/1146.aspx/1?MVC) -* [ASP.NET Web API forum](hhttps://forums.asp.net/1246.aspx/1?Web+API) +* [ASP.NET Web API forum](https://forums.asp.net/1246.aspx/1?Web+API) * [ASP.NET Web Pages forum](https://forums.asp.net/1224.aspx/1?ASP+NET+Web+Pages) * [StackOverflow](https://stackoverflow.com/) with the [`asp.net`](https://stackoverflow.com/questions/tagged/asp.net), [`asp.net-mvc`](https://stackoverflow.com/questions/tagged/asp.net-mvc), [`asp.net-web-api`](https://stackoverflow.com/questions/tagged/asp.net-web-api), [`asp.net-webpages`](https://stackoverflow.com/questions/tagged/asp.net-webpages) or [`razor`](https://stackoverflow.com/questions/tagged/razor) tags. From ea5b8854ade878237550b60f33d90c301d3f739c Mon Sep 17 00:00:00 2001 From: chinason Date: Sat, 30 Mar 2019 09:36:16 +0800 Subject: [PATCH 03/54] Update ReflectedHttpActionDescriptor.cs Remove duplicated methodCall --- .../Controllers/ReflectedHttpActionDescriptor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Web.Http/Controllers/ReflectedHttpActionDescriptor.cs b/src/System.Web.Http/Controllers/ReflectedHttpActionDescriptor.cs index d663000b6..f1714ff77 100644 --- a/src/System.Web.Http/Controllers/ReflectedHttpActionDescriptor.cs +++ b/src/System.Web.Http/Controllers/ReflectedHttpActionDescriptor.cs @@ -400,7 +400,7 @@ private static Func> GetExecutor(MethodInfo metho // Call method UnaryExpression instanceCast = (!methodInfo.IsStatic) ? Expression.Convert(instanceParameter, methodInfo.ReflectedType) : null; - MethodCallExpression methodCall = methodCall = Expression.Call(instanceCast, methodInfo, parameters); + MethodCallExpression methodCall = Expression.Call(instanceCast, methodInfo, parameters); // methodCall is "((MethodInstanceType) instance).method((T0) parameters[0], (T1) parameters[1], ...)" // Create function From ebef5b7d821b64ed5c48765d0caf6ce8a9bcfaf5 Mon Sep 17 00:00:00 2001 From: cendern Date: Thu, 25 Apr 2019 14:57:05 -0700 Subject: [PATCH 04/54] Update README.md The readme.md for the repo https://github.com/aspnet/Mvc says "This GitHub project has been archived. Ongoing development on this project can be found in https://github.com/aspnet/AspNetCore." --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 436ab251d..189d9dc15 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ ASP.NET MVC, Web API, Web Pages, and Razor AppVeyor: [![AppVeyor](https://ci.appveyor.com/api/projects/status/github/aspnet/aspnetwebstack?branch=master&svg=true)](https://ci.appveyor.com/project/aspnetci/aspnetwebstack/branch/master) -## Note: This repo is for ASP.NET MVC 5.x, Web API 2.x, and Web Pages 3.x. For ASP.NET Core MVC, check the [MVC repo](https://github.com/aspnet/Mvc). +## Note: This repo is for ASP.NET MVC 5.x, Web API 2.x, and Web Pages 3.x. For ASP.NET Core MVC, check the [AspNetCore repo](https://github.com/aspnet/AspNetCore). ASP.NET MVC is a web framework that gives you a powerful, patterns-based way to build dynamic websites and Web APIs. ASP.NET MVC enables a clean separation of concerns and gives you full control over markup. From ba26cfbfbf958d548e4c0a96e853250f13450dc6 Mon Sep 17 00:00:00 2001 From: Immo Landwerth Date: Thu, 9 Apr 2020 12:54:31 -0700 Subject: [PATCH 05/54] Link Code of Conduct (#277) --- CODE-OF-CONDUCT.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 CODE-OF-CONDUCT.md diff --git a/CODE-OF-CONDUCT.md b/CODE-OF-CONDUCT.md new file mode 100644 index 000000000..775f221c9 --- /dev/null +++ b/CODE-OF-CONDUCT.md @@ -0,0 +1,6 @@ +# Code of Conduct + +This project has adopted the code of conduct defined by the Contributor Covenant +to clarify expected behavior in our community. + +For more information, see the [.NET Foundation Code of Conduct](https://dotnetfoundation.org/code-of-conduct). From 42991b3d2537b702736463f76a10a4fcf2ea44c9 Mon Sep 17 00:00:00 2001 From: John Luo Date: Mon, 15 Mar 2021 10:12:36 -0700 Subject: [PATCH 06/54] Replace 'master' with 'main' (#295) --- .appveyor.yml | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index aef7f02c1..776f337d8 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -2,7 +2,7 @@ - git config --global core.autocrlf true branches: only: - - master + - main - /^(.*\/)?ci-.*$/ - /^rel\/.*/ configuration: diff --git a/README.md b/README.md index 189d9dc15..380713f64 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ ASP.NET MVC, Web API, Web Pages, and Razor === -AppVeyor: [![AppVeyor](https://ci.appveyor.com/api/projects/status/github/aspnet/aspnetwebstack?branch=master&svg=true)](https://ci.appveyor.com/project/aspnetci/aspnetwebstack/branch/master) +AppVeyor: [![AppVeyor](https://ci.appveyor.com/api/projects/status/github/aspnet/aspnetwebstack?branch=main&svg=true)](https://ci.appveyor.com/project/aspnetci/aspnetwebstack/branch/main) ## Note: This repo is for ASP.NET MVC 5.x, Web API 2.x, and Web Pages 3.x. For ASP.NET Core MVC, check the [AspNetCore repo](https://github.com/aspnet/AspNetCore). From ffbf707ddd657e93975131f462c8e4653836ba18 Mon Sep 17 00:00:00 2001 From: Doug Bunting <6431421+dougbu@users.noreply.github.com> Date: Tue, 27 Apr 2021 22:37:54 -0700 Subject: [PATCH 07/54] Move to a current .NET SDK --- global.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/global.json b/global.json index ea2669b29..3e8915949 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "2.1.403" + "version": "2.1.523" } -} \ No newline at end of file +} From bc83a3a7ec8354c0a5fa919a5317219f21e905a0 Mon Sep 17 00:00:00 2001 From: Doug Bunting <6431421+dougbu@users.noreply.github.com> Date: Sun, 2 May 2021 11:00:40 -0700 Subject: [PATCH 08/54] Rebrand to v3.2.8 / v5.2.8 (#298) - reformat README.md - merge 'Git tag' and 'Git branch' columns - remove old v3.2.4 / v5.2.4 information - add v3.2.7 / v5.2.7 information --- README.md | 19 ++++++++++--------- src/CommonAssemblyInfo.cs | 4 ++-- src/CommonAssemblyInfo.vb | 4 ++-- .../Areas/HelpPage/Views/Web.config | 2 +- .../VB/Areas/HelpPage/Views/Web.config | 2 +- .../Test/VersionTest.cs | 2 +- test/System.Web.WebPages.Test/App.config | 2 +- 7 files changed, 18 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 380713f64..f53c1b73f 100644 --- a/README.md +++ b/README.md @@ -24,12 +24,13 @@ Check out the [contributing](CONTRIBUTING.md) page to see the best places to log ### Tags and releases -Git tag|Git branch|Other products|MVC package versions|Web API package (product) versions|Web Pages package versions ---------|--------------|------------|------------|------------|------------ -[v2.0.4](https://github.com/aspnet/AspNetWebStack/tree/v2.0.4)|[v2.0-rtm](https://github.com/aspnet/AspNetWebStack/tree/v2.0-rtm)||4.0.40804|4.0.30506|2.0.30506 -[v2.1](https://github.com/aspnet/AspNetWebStack/tree/v2.1)||ASP.NET and Web Tools 2012.2, VS 2012 Update 2 (not on http://nuget.org)|v4 2012.2 Update RTM|v1 2012.2 Update RTM|v2 2012.2 Update RTM -[v3.0.2](https://github.com/aspnet/AspNetWebStack/tree/v3.0.2)|[v3-rtm](https://github.com/aspnet/AspNetWebStack/tree/v3-rtm)||5.0.2|5.0.1 (2.0.1)|3.0.1 -[v3.1.3](https://github.com/aspnet/AspNetWebStack/tree/v3.1.3)|[v3.1-rtm](https://github.com/aspnet/AspNetWebStack/tree/v3.1-rtm)||5.1.3|5.1.2 (2.1.2)|3.1.2 -[v3.2.4](https://github.com/aspnet/AspNetWebStack/tree/v3.2.4)|||5.2.4|5.2.4 (2.2.4)|3.2.4 -[v3.2.6](https://github.com/aspnet/AspNetWebStack/tree/v3.2.6)|||5.2.6|5.2.6|3.2.6 -||[master](https://github.com/aspnet/AspNetWebStack/tree/master)|New work e.g. MVC 5.2.7-preview1||| +Git tag or branch|Other products|MVC package versions|Web API package (product) versions|Web Pages package versions +--------|--------------|------------|------------|------------ +[v2.0.4](https://github.com/aspnet/AspNetWebStack/tree/v2.0.4)||4.0.40804|4.0.30506|2.0.30506 +[v2.1](https://github.com/aspnet/AspNetWebStack/tree/v2.1)|ASP.NET and Web Tools 2012.2, VS 2012 Update 2 (not on http://nuget.org)|v4 2012.2 Update RTM|v1 2012.2 Update RTM|v2 2012.2 Update RTM +[v3.0.2](https://github.com/aspnet/AspNetWebStack/tree/v3.0.2)||5.0.2|5.0.1 (2.0.1)|3.0.1 +[v3.1.3](https://github.com/aspnet/AspNetWebStack/tree/v3.1.3)||5.1.3|5.1.2 (2.1.2)|3.1.2 +[v3.2.6](https://github.com/aspnet/AspNetWebStack/tree/v3.2.6)||5.2.6|5.2.6|3.2.6 +[v3.2.7](https://github.com/aspnet/AspNetWebStack/tree/v3.2.7)||5.2.7|5.2.7|3.2.7 +[release/3.2.8](https://github.com/aspnet/AspNetWebStack/tree/release/3.2.8)|Work in progress on 5.2.8/3.2.8|||| +[main](https://github.com/aspnet/AspNetWebStack/tree/main)|New work e.g. MVC 5.2.9-preview1|||| diff --git a/src/CommonAssemblyInfo.cs b/src/CommonAssemblyInfo.cs index aa130a34b..ee493811f 100644 --- a/src/CommonAssemblyInfo.cs +++ b/src/CommonAssemblyInfo.cs @@ -28,8 +28,8 @@ #error Runtime projects cannot define more than one of ASPNETMVC, ASPNETWEBPAGES or ASPNETFACEBOOK #elif ASPNETMVC #if !BUILD_GENERATED_VERSION -[assembly: AssemblyVersion("5.2.7.0")] // ASPNETMVC -[assembly: AssemblyFileVersion("5.2.7.0")] // ASPNETMVC +[assembly: AssemblyVersion("5.2.8.0")] // ASPNETMVC +[assembly: AssemblyFileVersion("5.2.8.0")] // ASPNETMVC #endif [assembly: AssemblyProduct("Microsoft ASP.NET MVC")] #elif ASPNETWEBPAGES diff --git a/src/CommonAssemblyInfo.vb b/src/CommonAssemblyInfo.vb index 8310810f3..6d108b5ff 100644 --- a/src/CommonAssemblyInfo.vb +++ b/src/CommonAssemblyInfo.vb @@ -20,6 +20,6 @@ Imports System.Runtime.InteropServices ' Version numbers are automatically generated based on regular expressions. ' =========================================================================== - 'ASPNETMVC - 'ASPNETMVC + 'ASPNETMVC + 'ASPNETMVC \ No newline at end of file diff --git a/src/WebApiHelpPage/Areas/HelpPage/Views/Web.config b/src/WebApiHelpPage/Areas/HelpPage/Views/Web.config index 820e75486..6d4ddaf10 100644 --- a/src/WebApiHelpPage/Areas/HelpPage/Views/Web.config +++ b/src/WebApiHelpPage/Areas/HelpPage/Views/Web.config @@ -9,7 +9,7 @@ - + diff --git a/src/WebApiHelpPage/VB/Areas/HelpPage/Views/Web.config b/src/WebApiHelpPage/VB/Areas/HelpPage/Views/Web.config index 9a921ab54..6496e10d7 100644 --- a/src/WebApiHelpPage/VB/Areas/HelpPage/Views/Web.config +++ b/src/WebApiHelpPage/VB/Areas/HelpPage/Views/Web.config @@ -9,7 +9,7 @@ - + diff --git a/test/Microsoft.Web.Mvc.Test/Test/VersionTest.cs b/test/Microsoft.Web.Mvc.Test/Test/VersionTest.cs index 155f13f2f..8554639ae 100644 --- a/test/Microsoft.Web.Mvc.Test/Test/VersionTest.cs +++ b/test/Microsoft.Web.Mvc.Test/Test/VersionTest.cs @@ -13,7 +13,7 @@ public class VersionTest public void VerifyMVCVersionChangesAreIntentional() { Version mvcVersion = VersionTestHelper.GetVersionFromAssembly("System.Web.Mvc", typeof(Controller)); - Assert.Equal(new Version(5, 2, 7, 0), mvcVersion); + Assert.Equal(new Version(5, 2, 8, 0), mvcVersion); } } } diff --git a/test/System.Web.WebPages.Test/App.config b/test/System.Web.WebPages.Test/App.config index 0f0603365..61f560828 100644 --- a/test/System.Web.WebPages.Test/App.config +++ b/test/System.Web.WebPages.Test/App.config @@ -11,7 +11,7 @@ - + From a68a57535d0adeda2b1846764e5eafd02fdeb12d Mon Sep 17 00:00:00 2001 From: Doug Bunting <6431421+dougbu@users.noreply.github.com> Date: Mon, 10 May 2021 09:23:22 -0700 Subject: [PATCH 09/54] Rebrand to v3.2.9 / v5.2.9 (#299) * Move to a current .NET SDK - cherry-picked from release/3.2.8 commit ffbf707ddd65 * Rebrand to v3.2.9 / v5.2.9 - cherry-picked from release/3.2.8 commit bc83a3a7ec83 (#298) - then, switched to 3.2.9 instead of 3.2.8 - reformat README.md - merge 'Git tag' and 'Git branch' columns - remove old v3.2.4 / v5.2.4 information - add v3.2.7 / v5.2.7 information --- README.md | 19 ++++++++++--------- global.json | 4 ++-- src/CommonAssemblyInfo.cs | 4 ++-- src/CommonAssemblyInfo.vb | 4 ++-- .../Areas/HelpPage/Views/Web.config | 2 +- .../VB/Areas/HelpPage/Views/Web.config | 2 +- .../Test/VersionTest.cs | 2 +- test/System.Web.WebPages.Test/App.config | 2 +- 8 files changed, 20 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 380713f64..f53c1b73f 100644 --- a/README.md +++ b/README.md @@ -24,12 +24,13 @@ Check out the [contributing](CONTRIBUTING.md) page to see the best places to log ### Tags and releases -Git tag|Git branch|Other products|MVC package versions|Web API package (product) versions|Web Pages package versions ---------|--------------|------------|------------|------------|------------ -[v2.0.4](https://github.com/aspnet/AspNetWebStack/tree/v2.0.4)|[v2.0-rtm](https://github.com/aspnet/AspNetWebStack/tree/v2.0-rtm)||4.0.40804|4.0.30506|2.0.30506 -[v2.1](https://github.com/aspnet/AspNetWebStack/tree/v2.1)||ASP.NET and Web Tools 2012.2, VS 2012 Update 2 (not on http://nuget.org)|v4 2012.2 Update RTM|v1 2012.2 Update RTM|v2 2012.2 Update RTM -[v3.0.2](https://github.com/aspnet/AspNetWebStack/tree/v3.0.2)|[v3-rtm](https://github.com/aspnet/AspNetWebStack/tree/v3-rtm)||5.0.2|5.0.1 (2.0.1)|3.0.1 -[v3.1.3](https://github.com/aspnet/AspNetWebStack/tree/v3.1.3)|[v3.1-rtm](https://github.com/aspnet/AspNetWebStack/tree/v3.1-rtm)||5.1.3|5.1.2 (2.1.2)|3.1.2 -[v3.2.4](https://github.com/aspnet/AspNetWebStack/tree/v3.2.4)|||5.2.4|5.2.4 (2.2.4)|3.2.4 -[v3.2.6](https://github.com/aspnet/AspNetWebStack/tree/v3.2.6)|||5.2.6|5.2.6|3.2.6 -||[master](https://github.com/aspnet/AspNetWebStack/tree/master)|New work e.g. MVC 5.2.7-preview1||| +Git tag or branch|Other products|MVC package versions|Web API package (product) versions|Web Pages package versions +--------|--------------|------------|------------|------------ +[v2.0.4](https://github.com/aspnet/AspNetWebStack/tree/v2.0.4)||4.0.40804|4.0.30506|2.0.30506 +[v2.1](https://github.com/aspnet/AspNetWebStack/tree/v2.1)|ASP.NET and Web Tools 2012.2, VS 2012 Update 2 (not on http://nuget.org)|v4 2012.2 Update RTM|v1 2012.2 Update RTM|v2 2012.2 Update RTM +[v3.0.2](https://github.com/aspnet/AspNetWebStack/tree/v3.0.2)||5.0.2|5.0.1 (2.0.1)|3.0.1 +[v3.1.3](https://github.com/aspnet/AspNetWebStack/tree/v3.1.3)||5.1.3|5.1.2 (2.1.2)|3.1.2 +[v3.2.6](https://github.com/aspnet/AspNetWebStack/tree/v3.2.6)||5.2.6|5.2.6|3.2.6 +[v3.2.7](https://github.com/aspnet/AspNetWebStack/tree/v3.2.7)||5.2.7|5.2.7|3.2.7 +[release/3.2.8](https://github.com/aspnet/AspNetWebStack/tree/release/3.2.8)|Work in progress on 5.2.8/3.2.8|||| +[main](https://github.com/aspnet/AspNetWebStack/tree/main)|New work e.g. MVC 5.2.9-preview1|||| diff --git a/global.json b/global.json index ea2669b29..3e8915949 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "2.1.403" + "version": "2.1.523" } -} \ No newline at end of file +} diff --git a/src/CommonAssemblyInfo.cs b/src/CommonAssemblyInfo.cs index aa130a34b..23f575974 100644 --- a/src/CommonAssemblyInfo.cs +++ b/src/CommonAssemblyInfo.cs @@ -28,8 +28,8 @@ #error Runtime projects cannot define more than one of ASPNETMVC, ASPNETWEBPAGES or ASPNETFACEBOOK #elif ASPNETMVC #if !BUILD_GENERATED_VERSION -[assembly: AssemblyVersion("5.2.7.0")] // ASPNETMVC -[assembly: AssemblyFileVersion("5.2.7.0")] // ASPNETMVC +[assembly: AssemblyVersion("5.2.9.0")] // ASPNETMVC +[assembly: AssemblyFileVersion("5.2.9.0")] // ASPNETMVC #endif [assembly: AssemblyProduct("Microsoft ASP.NET MVC")] #elif ASPNETWEBPAGES diff --git a/src/CommonAssemblyInfo.vb b/src/CommonAssemblyInfo.vb index 8310810f3..591dc0d89 100644 --- a/src/CommonAssemblyInfo.vb +++ b/src/CommonAssemblyInfo.vb @@ -20,6 +20,6 @@ Imports System.Runtime.InteropServices ' Version numbers are automatically generated based on regular expressions. ' =========================================================================== - 'ASPNETMVC - 'ASPNETMVC + 'ASPNETMVC + 'ASPNETMVC \ No newline at end of file diff --git a/src/WebApiHelpPage/Areas/HelpPage/Views/Web.config b/src/WebApiHelpPage/Areas/HelpPage/Views/Web.config index 820e75486..c9f6f08cb 100644 --- a/src/WebApiHelpPage/Areas/HelpPage/Views/Web.config +++ b/src/WebApiHelpPage/Areas/HelpPage/Views/Web.config @@ -9,7 +9,7 @@ - + diff --git a/src/WebApiHelpPage/VB/Areas/HelpPage/Views/Web.config b/src/WebApiHelpPage/VB/Areas/HelpPage/Views/Web.config index 9a921ab54..8ff9486fe 100644 --- a/src/WebApiHelpPage/VB/Areas/HelpPage/Views/Web.config +++ b/src/WebApiHelpPage/VB/Areas/HelpPage/Views/Web.config @@ -9,7 +9,7 @@ - + diff --git a/test/Microsoft.Web.Mvc.Test/Test/VersionTest.cs b/test/Microsoft.Web.Mvc.Test/Test/VersionTest.cs index 155f13f2f..32e4bc1d7 100644 --- a/test/Microsoft.Web.Mvc.Test/Test/VersionTest.cs +++ b/test/Microsoft.Web.Mvc.Test/Test/VersionTest.cs @@ -13,7 +13,7 @@ public class VersionTest public void VerifyMVCVersionChangesAreIntentional() { Version mvcVersion = VersionTestHelper.GetVersionFromAssembly("System.Web.Mvc", typeof(Controller)); - Assert.Equal(new Version(5, 2, 7, 0), mvcVersion); + Assert.Equal(new Version(5, 2, 9, 0), mvcVersion); } } } diff --git a/test/System.Web.WebPages.Test/App.config b/test/System.Web.WebPages.Test/App.config index 0f0603365..e0565507e 100644 --- a/test/System.Web.WebPages.Test/App.config +++ b/test/System.Web.WebPages.Test/App.config @@ -11,7 +11,7 @@ - + From c55dd95aebb2069c8c381535628e952baef35eab Mon Sep 17 00:00:00 2001 From: Doug Bunting <6431421+dougbu@users.noreply.github.com> Date: Thu, 29 Jul 2021 11:35:00 -0700 Subject: [PATCH 10/54] [releaes/3.2.8] Get builds working again (#302) - test using netcoreapp2.1 - react to .NET Core breaking change - see https://docs.microsoft.com/en-us/dotnet/core/compatibility/2.1#path-apis-dont-throw-an-exception-for-invalid-characters - suppress NU5125 warnings - break the build because warnings are treated as errors - do not validate Expires header values - #263 --- .../Parsers/InternetMessageFormatHeaderParser.cs | 12 ++++++++---- src/WebApiHelpPage/VB/WebApiHelpPageVB.vbproj | 2 ++ src/WebApiHelpPage/WebApiHelpPage.csproj | 2 ++ test/Microsoft.TestCommon/PlatformInfo.cs | 2 +- ...ystem.Net.Http.Formatting.NetStandard.Test.csproj | 2 +- .../DataSets/HttpTestData.cs | 4 ++-- .../Formatting/BsonMediaTypeFormatterTests.cs | 2 +- .../DataContractJsonMediaTypeFormatterTests.cs | 2 +- .../Formatting/JsonMediaTypeFormatterTests.cs | 2 +- .../Formatting/JsonNetSerializationTest.cs | 2 +- .../Formatting/XmlMediaTypeFormatterTests.cs | 4 ++-- .../Internal/HttpValueCollectionTest.cs | 4 ++-- .../MultipartFileStreamProviderTests.cs | 10 ++++++++-- 13 files changed, 32 insertions(+), 18 deletions(-) diff --git a/src/System.Net.Http.Formatting/Formatting/Parsers/InternetMessageFormatHeaderParser.cs b/src/System.Net.Http.Formatting/Formatting/Parsers/InternetMessageFormatHeaderParser.cs index aebfa8c29..ebf22b9ba 100644 --- a/src/System.Net.Http.Formatting/Formatting/Parsers/InternetMessageFormatHeaderParser.cs +++ b/src/System.Net.Http.Formatting/Formatting/Parsers/InternetMessageFormatHeaderParser.cs @@ -10,8 +10,8 @@ namespace System.Net.Http.Formatting.Parsers { /// - /// Buffer-oriented RFC 5322 style Internet Message Format parser which can be used to pass header - /// fields used in HTTP and MIME message entities. + /// Buffer-oriented RFC 5322 style Internet Message Format parser which can be used to pass header + /// fields used in HTTP and MIME message entities. /// internal class InternetMessageFormatHeaderParser { @@ -76,7 +76,7 @@ private enum HeaderFieldState /// /// Parse a buffer of RFC 5322 style header fields and add them to the collection. - /// Bytes are parsed in a consuming manner from the beginning of the buffer meaning that the same bytes can not be + /// Bytes are parsed in a consuming manner from the beginning of the buffer meaning that the same bytes can not be /// present in the buffer. /// /// Request buffer from where request is read @@ -283,7 +283,7 @@ private static ParserState ParseHeaderFields( } /// - /// Maintains information about the current header field being parsed. + /// Maintains information about the current header field being parsed. /// private class CurrentHeaderFieldStore { @@ -320,6 +320,10 @@ public void CopyTo(HttpHeaders headers, bool ignoreHeaderValidation) { var name = _name.ToString(); var value = _value.ToString().Trim(CurrentHeaderFieldStore._linearWhiteSpace); + if (string.Equals("expires", name, StringComparison.OrdinalIgnoreCase)) + { + ignoreHeaderValidation = true; + } if (ignoreHeaderValidation) { diff --git a/src/WebApiHelpPage/VB/WebApiHelpPageVB.vbproj b/src/WebApiHelpPage/VB/WebApiHelpPageVB.vbproj index 5c1d45882..116d126b7 100644 --- a/src/WebApiHelpPage/VB/WebApiHelpPageVB.vbproj +++ b/src/WebApiHelpPage/VB/WebApiHelpPageVB.vbproj @@ -11,6 +11,8 @@ $(CodeAnalysis) ..\..\Strict.ruleset Windows + + $(NoWarn);NU5125 true diff --git a/src/WebApiHelpPage/WebApiHelpPage.csproj b/src/WebApiHelpPage/WebApiHelpPage.csproj index 15964d7c8..38c333f6b 100644 --- a/src/WebApiHelpPage/WebApiHelpPage.csproj +++ b/src/WebApiHelpPage/WebApiHelpPage.csproj @@ -13,6 +13,8 @@ ..\Strict.ruleset $(DefineConstants);ASPNETMVC 1591 + + $(NoWarn);NU5125 diff --git a/test/Microsoft.TestCommon/PlatformInfo.cs b/test/Microsoft.TestCommon/PlatformInfo.cs index 678ecff08..e3026e39e 100644 --- a/test/Microsoft.TestCommon/PlatformInfo.cs +++ b/test/Microsoft.TestCommon/PlatformInfo.cs @@ -26,7 +26,7 @@ private static Platform GetPlatform() { if (Type.GetType(_netCore20TypeName, throwOnError: false) != null) { - // Treat .NET Core 2.0 as a .NET 4.5 superset though internal types are different. + // Treat .NET Core 2.1 as a .NET 4.5 superset though internal types are different. return Platform.Net45; } diff --git a/test/System.Net.Http.Formatting.NetStandard.Test/System.Net.Http.Formatting.NetStandard.Test.csproj b/test/System.Net.Http.Formatting.NetStandard.Test/System.Net.Http.Formatting.NetStandard.Test.csproj index 31732bd10..6cfb16e25 100644 --- a/test/System.Net.Http.Formatting.NetStandard.Test/System.Net.Http.Formatting.NetStandard.Test.csproj +++ b/test/System.Net.Http.Formatting.NetStandard.Test/System.Net.Http.Formatting.NetStandard.Test.csproj @@ -1,7 +1,7 @@  - netcoreapp2.0;net461 + netcoreapp2.1;net461 System.Net.Http System.Net.Http.Formatting.NetStandard.Test ..\..\bin\$(Configuration)\Test\ diff --git a/test/System.Net.Http.Formatting.Test/DataSets/HttpTestData.cs b/test/System.Net.Http.Formatting.Test/DataSets/HttpTestData.cs index fb482788b..84178a3a6 100644 --- a/test/System.Net.Http.Formatting.Test/DataSets/HttpTestData.cs +++ b/test/System.Net.Http.Formatting.Test/DataSets/HttpTestData.cs @@ -302,11 +302,11 @@ public static TheoryDataSet ReadAndWriteCorrectCharacterEn { "This is a test 激光這兩個字是甚麼意思 string written using utf-8", "utf-8", true }, { "This is a test 激光這兩個字是甚麼意思 string written using utf-16", "utf-16", true }, { "This is a test 激光這兩個字是甚麼意思 string written using utf-32", "utf-32", false }, -#if !NETCOREAPP2_0 // shift_jis and iso-2022-kr are not supported when running on .NET Core 2.0. +#if !NETCOREAPP // shift_jis and iso-2022-kr are not supported when running on .NET Core 2.1. { "This is a test 激光這兩個字是甚麼意思 string written using shift_jis", "shift_jis", false }, #endif { "This is a test æøå string written using iso-8859-1", "iso-8859-1", false }, -#if !NETCOREAPP2_0 +#if !NETCOREAPP { "This is a test 레이저 단어 뜻 string written using iso-2022-kr", "iso-2022-kr", false }, #endif }; diff --git a/test/System.Net.Http.Formatting.Test/Formatting/BsonMediaTypeFormatterTests.cs b/test/System.Net.Http.Formatting.Test/Formatting/BsonMediaTypeFormatterTests.cs index d849df473..caf93e059 100644 --- a/test/System.Net.Http.Formatting.Test/Formatting/BsonMediaTypeFormatterTests.cs +++ b/test/System.Net.Http.Formatting.Test/Formatting/BsonMediaTypeFormatterTests.cs @@ -415,7 +415,7 @@ public async Task ReadFromStreamAsync_RoundTripsWriteToStreamAsync_DBNullAsNull( Assert.Null(readObj); } -#if !NETCOREAPP2_0 // DBNull not serializable on .NET Core 2.0 except at top level (using BsonMediaTypeformatter special case). +#if !NETCOREAPP // DBNull not serializable on .NET Core 2.1 except at top level (using BsonMediaTypeformatter special case). [Theory] [TestDataSet(typeof(JsonMediaTypeFormatterTests), "DBNullAsObjectTestDataCollection", TestDataVariations.AsDictionary)] public async Task ReadFromStreamAsync_RoundTripsWriteToStreamAsync_DBNullAsNull_Dictionary(Type variationType, object testData) diff --git a/test/System.Net.Http.Formatting.Test/Formatting/DataContractJsonMediaTypeFormatterTests.cs b/test/System.Net.Http.Formatting.Test/Formatting/DataContractJsonMediaTypeFormatterTests.cs index ad3311326..e576a6924 100644 --- a/test/System.Net.Http.Formatting.Test/Formatting/DataContractJsonMediaTypeFormatterTests.cs +++ b/test/System.Net.Http.Formatting.Test/Formatting/DataContractJsonMediaTypeFormatterTests.cs @@ -157,7 +157,7 @@ public async Task ReadFromStreamAsync_RoundTripsWriteToStreamAsync_KnownTypes(Ty } } -#if !NETCOREAPP2_0 // DBNull not serializable on .NET Core 2.0. +#if !NETCOREAPP // DBNull not serializable on .NET Core 2.1. // Test alternate null value [Fact] public async Task ReadFromStreamAsync_RoundTripsWriteToStreamAsync_DBNull() diff --git a/test/System.Net.Http.Formatting.Test/Formatting/JsonMediaTypeFormatterTests.cs b/test/System.Net.Http.Formatting.Test/Formatting/JsonMediaTypeFormatterTests.cs index 34d17d884..3d7898ddb 100644 --- a/test/System.Net.Http.Formatting.Test/Formatting/JsonMediaTypeFormatterTests.cs +++ b/test/System.Net.Http.Formatting.Test/Formatting/JsonMediaTypeFormatterTests.cs @@ -374,7 +374,7 @@ public async Task ReadFromStreamAsync_RoundTripsWriteToStreamAsync(Type variatio } } -#if !NETCOREAPP2_0 // DBNull not serializable on .NET Core 2.0. +#if !NETCOREAPP // DBNull not serializable on .NET Core 2.1. // Test alternate null value; always serialized as "null" [Theory] [TestDataSet(typeof(JsonMediaTypeFormatterTests), "DBNullAsObjectTestDataCollection", TestDataVariations.AllSingleInstances)] diff --git a/test/System.Net.Http.Formatting.Test/Formatting/JsonNetSerializationTest.cs b/test/System.Net.Http.Formatting.Test/Formatting/JsonNetSerializationTest.cs index b544752f0..bd0edfd20 100644 --- a/test/System.Net.Http.Formatting.Test/Formatting/JsonNetSerializationTest.cs +++ b/test/System.Net.Http.Formatting.Test/Formatting/JsonNetSerializationTest.cs @@ -258,7 +258,7 @@ public Task DeserializingDeepArraysThrows() // low surrogate not preceded by high surrogate [InlineData("ABC \\udc00\\ud800 DEF", "ABC \ufffd\ufffd DEF")] // make sure unencoded invalid surrogate characters don't make it through -#if NETCOREAPP2_0 // Json.NET uses its regular invalid Unicode character on .NET Core 2.0; '?' elsewhere. +#if NETCOREAPP // Json.NET uses its regular invalid Unicode character on .NET Core 2.1; '?' elsewhere. [InlineData("\udc00\ud800\ud800", "\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd")] #else [InlineData("\udc00\ud800\ud800", "??????")] diff --git a/test/System.Net.Http.Formatting.Test/Formatting/XmlMediaTypeFormatterTests.cs b/test/System.Net.Http.Formatting.Test/Formatting/XmlMediaTypeFormatterTests.cs index b1865376b..3d7fd1557 100644 --- a/test/System.Net.Http.Formatting.Test/Formatting/XmlMediaTypeFormatterTests.cs +++ b/test/System.Net.Http.Formatting.Test/Formatting/XmlMediaTypeFormatterTests.cs @@ -36,7 +36,7 @@ public class XmlMediaTypeFormatterTests : MediaTypeFormatterTestBase NotSupportedFilePaths { get @@ -44,6 +45,7 @@ public static TheoryDataSet NotSupportedFilePaths }; } } +#endif public static TheoryDataSet InvalidFilePaths { @@ -52,15 +54,17 @@ public static TheoryDataSet InvalidFilePaths return new TheoryDataSet { "", - " ", + " ", " ", - "\t\t \n ", +#if !NETCOREAPP // .NET Core does not enforce path validity in many APIs. + "\t\t \n ", "c:\\ab", "c:\\a\"b", "c:\\a\tb", "c:\\a|b", "c:\\a\bb", +#endif "c:\\a\0b", "c :\\a\0b", }; @@ -73,12 +77,14 @@ public void Constructor_ThrowsOnNullRootPath() Assert.ThrowsArgumentNull(() => { new MultipartFileStreamProvider(null); }, "rootPath"); } +#if !NETCOREAPP // .NET Core does not enforce path validity in many APIs. [Theory] [PropertyData("NotSupportedFilePaths")] public void Constructor_ThrowsOnNotSupportedRootPath(string notSupportedPath) { Assert.Throws(() => new MultipartFileStreamProvider(notSupportedPath, ValidBufferSize)); } +#endif [Theory] [PropertyData("InvalidFilePaths")] From 8c4e5b5da1f7f0c348978c99f9a477f7928f7258 Mon Sep 17 00:00:00 2001 From: Pranav Krishnamoorthy Date: Wed, 6 Oct 2021 23:37:15 +0000 Subject: [PATCH 11/54] Merged PR 18778: Constrain the MemoryStream size Constrain the MemoryStream size --- src/System.Web.Http.Owin/HttpMessageHandlerAdapter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Web.Http.Owin/HttpMessageHandlerAdapter.cs b/src/System.Web.Http.Owin/HttpMessageHandlerAdapter.cs index b8c6fc648..ac118a754 100644 --- a/src/System.Web.Http.Owin/HttpMessageHandlerAdapter.cs +++ b/src/System.Web.Http.Owin/HttpMessageHandlerAdapter.cs @@ -275,7 +275,7 @@ private static async Task CreateBufferedRequestContentAsync(IOwinRe } else { - buffer = new MemoryStream(contentLength.Value); + buffer = new MemoryStream(Math.Min(4 * 1024, contentLength.Value)); } cancellationToken.ThrowIfCancellationRequested(); From d1df0c8297eda63b3b3a9c6b0892f9e6ace49d9e Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 13 Jan 2022 15:49:37 -0800 Subject: [PATCH 12/54] Clean up doc comments for PushStreamContent (#311) Fixes https://github.com/aspnet/AspNetWebStack/issues/310 --- .../PushStreamContent.cs | 33 +++++++++++++------ 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/src/System.Net.Http.Formatting/PushStreamContent.cs b/src/System.Net.Http.Formatting/PushStreamContent.cs index a8df4f262..6896e6c39 100644 --- a/src/System.Net.Http.Formatting/PushStreamContent.cs +++ b/src/System.Net.Http.Formatting/PushStreamContent.cs @@ -14,7 +14,7 @@ namespace System.Net.Http { /// /// Provides an implementation that exposes an output - /// which can be written to directly. The ability to push data to the output stream differs from the + /// which can be written to directly. The ability to push data to the output stream differs from the /// where data is pulled and not pushed. /// public class PushStreamContent : HttpContent @@ -24,8 +24,8 @@ public class PushStreamContent : HttpContent /// /// Initializes a new instance of the class. The /// action is called when an output stream - /// has become available allowing the action to write to it directly. When the - /// stream is closed, it will signal to the content that is has completed and the + /// has become available allowing the action to write to it directly. When the + /// stream is closed, it will signal to the content that it has completed and the /// HTTP request or response will be completed. /// /// The action to call when an output stream is available. @@ -35,10 +35,11 @@ public PushStreamContent(Action onStreamA } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - /// The action to call when an output stream is available. The stream is automatically - /// closed when the return task is completed. + /// The action to call when an output stream is available. When the + /// output stream is closed or disposed, it will signal to the content that it has completed and the + /// HTTP request or response will be completed. public PushStreamContent(Func onStreamAvailable) : this(onStreamAvailable, (MediaTypeHeaderValue)null) { @@ -47,6 +48,8 @@ public PushStreamContent(Func onStr /// /// Initializes a new instance of the class with the given media type. /// + /// The action to call when an output stream is available. + /// The value of the Content-Type content header on an HTTP response. public PushStreamContent(Action onStreamAvailable, string mediaType) : this(Taskify(onStreamAvailable), new MediaTypeHeaderValue(mediaType)) { @@ -55,6 +58,10 @@ public PushStreamContent(Action onStreamA /// /// Initializes a new instance of the class with the given media type. /// + /// The action to call when an output stream is available. When the + /// output stream is closed or disposed, it will signal to the content that it has completed and the + /// HTTP request or response will be completed. + /// The value of the Content-Type content header on an HTTP response. public PushStreamContent(Func onStreamAvailable, string mediaType) : this(onStreamAvailable, new MediaTypeHeaderValue(mediaType)) { @@ -63,6 +70,8 @@ public PushStreamContent(Func onStr /// /// Initializes a new instance of the class with the given . /// + /// The action to call when an output stream is available. + /// The value of the Content-Type content header on an HTTP response. public PushStreamContent(Action onStreamAvailable, MediaTypeHeaderValue mediaType) : this(Taskify(onStreamAvailable), mediaType) { @@ -71,6 +80,10 @@ public PushStreamContent(Action onStreamA /// /// Initializes a new instance of the class with the given . /// + /// The action to call when an output stream is available. When the + /// output stream is closed or disposed, it will signal to the content that it has completed and the + /// HTTP request or response will be completed. + /// The value of the Content-Type content header on an HTTP response. public PushStreamContent(Func onStreamAvailable, MediaTypeHeaderValue mediaType) { if (onStreamAvailable == null) @@ -98,8 +111,8 @@ private static Func Taskify( } /// - /// When this method is called, it calls the action provided in the constructor with the output - /// stream to write to. Once the action has completed its work it closes the stream which will + /// When this method is called, it calls the action provided in the constructor with the output + /// stream to write to. Once the action has completed its work it closes the stream which will /// close this content instance and complete the HTTP request or response. /// /// The to which to write. @@ -142,8 +155,8 @@ public CompleteTaskOnCloseStream(Stream innerStream, TaskCompletionSource #if NETFX_CORE [SuppressMessage( - "Microsoft.Usage", - "CA2215:Dispose methods should call base class dispose", + "Microsoft.Usage", + "CA2215:Dispose methods should call base class dispose", Justification = "See comments, this is intentional.")] protected override void Dispose(bool disposing) { From ef4296eff8dac087d2b49e6a4af7eb6715f30dfc Mon Sep 17 00:00:00 2001 From: Pranav K Date: Fri, 14 Jan 2022 13:47:15 -0800 Subject: [PATCH 13/54] Configure max request line size limits to be the same as maxHeaderSize (#312) * Configure max request line size limits to be the same as maxHeaderSize As part of ReadAsHttpRequestMessageAsync, the parsing of the HTTP request line is limited by a non-configurable 2k limit. The size does not affect buffer sizes, only the maximum allowed length. This PR updates the ReadAsHttpRequestMessageAsync API to use the same limits for HTTP request line as the HTTP header line, the latter which is configurable by user code. In the default case, this means the HTTP request line size now supports a 16k limit before it throws. Fixes https://github.com/aspnet/AspNetWebStack/issues/307 --- .../HttpContentMessageExtensions.cs | 2 +- .../HttpContentMessageExtensionsTests.cs | 40 +++++++++++++++++-- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/src/System.Net.Http.Formatting/HttpContentMessageExtensions.cs b/src/System.Net.Http.Formatting/HttpContentMessageExtensions.cs index dd801b604..a7dcb869d 100644 --- a/src/System.Net.Http.Formatting/HttpContentMessageExtensions.cs +++ b/src/System.Net.Http.Formatting/HttpContentMessageExtensions.cs @@ -223,7 +223,7 @@ private static async Task ReadAsHttpRequestMessageAsyncCore( HttpUnsortedRequest httpRequest = new HttpUnsortedRequest(); HttpRequestHeaderParser parser = new HttpRequestHeaderParser(httpRequest, - HttpRequestHeaderParser.DefaultMaxRequestLineSize, maxHeaderSize); + Math.Max(HttpRequestHeaderParser.DefaultMaxRequestLineSize, maxHeaderSize), maxHeaderSize); ParserState parseStatus; byte[] buffer = new byte[bufferSize]; diff --git a/test/System.Net.Http.Formatting.Test/HttpContentMessageExtensionsTests.cs b/test/System.Net.Http.Formatting.Test/HttpContentMessageExtensionsTests.cs index 27273e4f2..7003cdbd5 100644 --- a/test/System.Net.Http.Formatting.Test/HttpContentMessageExtensionsTests.cs +++ b/test/System.Net.Http.Formatting.Test/HttpContentMessageExtensionsTests.cs @@ -482,16 +482,50 @@ public Task ReadAsHttpResponseMessageAsync_LargeHeaderSize() } [Fact] - public Task ReadAsHttpRequestMessageAsync_LargeHeaderSize() + public async Task ReadAsHttpRequestMessageAsync_LargeHeaderSize() { + string cookieValue = string.Format("{0}={1}", new String('a', 16 * 1024), new String('b', 16 * 1024)); string[] request = new[] { @"GET / HTTP/1.1", @"Host: msdn.microsoft.com", - String.Format("Cookie: {0}={1}", new String('a', 16 * 1024), new String('b', 16 * 1024)) + string.Format("Cookie: {0}", cookieValue), + }; + + HttpContent content = CreateContent(true, request, "sample body"); + var httpRequestMessage = await content.ReadAsHttpRequestMessageAsync(Uri.UriSchemeHttp, 64 * 1024, 64 * 1024); + + Assert.Equal(HttpMethod.Get, httpRequestMessage.Method); + Assert.Equal("/", httpRequestMessage.RequestUri.PathAndQuery); + Assert.Equal("msdn.microsoft.com", httpRequestMessage.Headers.Host); + IEnumerable actualCookieValue; + Assert.True(httpRequestMessage.Headers.TryGetValues("Cookie", out actualCookieValue)); + Assert.Equal(cookieValue, Assert.Single(actualCookieValue)); + } + + [Fact] + public async Task ReadAsHttpRequestMessageAsync_LargeHttpRequestLine() + { + string requestPath = string.Format("/myurl?{0}={1}", new string('a', 4 * 1024), new string('b', 4 * 1024)); + string cookieValue = string.Format("{0}={1}", new String('a', 4 * 1024), new String('b', 4 * 1024)); + string[] request = new[] + { + string.Format("GET {0} HTTP/1.1", requestPath), + @"Host: msdn.microsoft.com", + string.Format("Cookie: {0}", cookieValue), }; HttpContent content = CreateContent(true, request, "sample body"); - return content.ReadAsHttpRequestMessageAsync(Uri.UriSchemeHttp, 64 * 1024, 64 * 1024); + var httpRequestMessage = await content.ReadAsHttpRequestMessageAsync( + Uri.UriSchemeHttp, + bufferSize: 64 * 1024, + maxHeaderSize: 64 * 1024); + + Assert.Equal(HttpMethod.Get, httpRequestMessage.Method); + Assert.Equal(requestPath, httpRequestMessage.RequestUri.PathAndQuery); + Assert.Equal("msdn.microsoft.com", httpRequestMessage.Headers.Host); + IEnumerable actualCookieValue; + Assert.True(httpRequestMessage.Headers.TryGetValues("Cookie", out actualCookieValue)); + Assert.Equal(cookieValue, Assert.Single(actualCookieValue)); } [Theory] From 362b7be1e6df2cca6ff307f8fc303e6490dacc52 Mon Sep 17 00:00:00 2001 From: Doug Bunting <6431421+dougbu@users.noreply.github.com> Date: Wed, 30 Mar 2022 14:02:44 -0700 Subject: [PATCH 14/54] Remove deprecated `` element (#315) - remove `` as well - can't require a license w/o `` or `` - also, don't need to ignore NU5125 anymore --- src/WebApiHelpPage/VB/WebApiHelpPage.VB.nuspec | 2 -- src/WebApiHelpPage/VB/WebApiHelpPageVB.vbproj | 2 -- src/WebApiHelpPage/WebApiHelpPage.csproj | 2 -- src/WebApiHelpPage/WebApiHelpPage.nuspec | 4 +--- 4 files changed, 1 insertion(+), 9 deletions(-) diff --git a/src/WebApiHelpPage/VB/WebApiHelpPage.VB.nuspec b/src/WebApiHelpPage/VB/WebApiHelpPage.VB.nuspec index 6715ceca9..3e826d647 100644 --- a/src/WebApiHelpPage/VB/WebApiHelpPage.VB.nuspec +++ b/src/WebApiHelpPage/VB/WebApiHelpPage.VB.nuspec @@ -8,8 +8,6 @@ Microsoft http://www.asp.net/web-api - true - http://www.microsoft.com/web/webpi/eula/mvc4extensions_prerelease_eula.htm The ASP.NET Web API Help Page automatically generates help page content for the web APIs on your site. Visitors to your help page can use this content to learn how to call your web APIs. Everything generated by the help page is fully customizable using ASP.NET MVC and Razor. ASP.NET Web API Help Page is a great addition to any ASP.NET Web API project. The ASP.NET Web API Help Page automatically generates help page content for the web APIs on your site. diff --git a/src/WebApiHelpPage/VB/WebApiHelpPageVB.vbproj b/src/WebApiHelpPage/VB/WebApiHelpPageVB.vbproj index 116d126b7..5c1d45882 100644 --- a/src/WebApiHelpPage/VB/WebApiHelpPageVB.vbproj +++ b/src/WebApiHelpPage/VB/WebApiHelpPageVB.vbproj @@ -11,8 +11,6 @@ $(CodeAnalysis) ..\..\Strict.ruleset Windows - - $(NoWarn);NU5125 true diff --git a/src/WebApiHelpPage/WebApiHelpPage.csproj b/src/WebApiHelpPage/WebApiHelpPage.csproj index 38c333f6b..15964d7c8 100644 --- a/src/WebApiHelpPage/WebApiHelpPage.csproj +++ b/src/WebApiHelpPage/WebApiHelpPage.csproj @@ -13,8 +13,6 @@ ..\Strict.ruleset $(DefineConstants);ASPNETMVC 1591 - - $(NoWarn);NU5125 diff --git a/src/WebApiHelpPage/WebApiHelpPage.nuspec b/src/WebApiHelpPage/WebApiHelpPage.nuspec index aa69da71f..8c69a51b1 100644 --- a/src/WebApiHelpPage/WebApiHelpPage.nuspec +++ b/src/WebApiHelpPage/WebApiHelpPage.nuspec @@ -8,8 +8,6 @@ Microsoft http://www.asp.net/web-api - true - http://www.microsoft.com/web/webpi/eula/mvc4extensions_prerelease_eula.htm The ASP.NET Web API Help Page automatically generates help page content for the web APIs on your site. Visitors to your help page can use this content to learn how to call your web APIs. Everything generated by the help page is fully customizable using ASP.NET MVC and Razor. ASP.NET Web API Help Page is a great addition to any ASP.NET Web API project. The ASP.NET Web API Help Page automatically generates help page content for the web APIs on your site. @@ -22,7 +20,7 @@ en-US - Microsoft AspNet WebApi AspNetWebApi HelpPage + Microsoft AspNet WebApi AspNetWebApi HelpPage From f7321b3bc123da2f51deeeb55bbff477bc62afb9 Mon Sep 17 00:00:00 2001 From: Doug Bunting <6431421+dougbu@users.noreply.github.com> Date: Thu, 14 Apr 2022 17:53:25 -0700 Subject: [PATCH 15/54] Update README now 3.2.8 is live (#318) - remove mention of MyGet.org since we currently do not have available nightly builds - we hope to restore this availability soon though it's likely builds will remain infrequent --- README.md | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index f53c1b73f..f4c49434b 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,4 @@ -ASP.NET MVC, Web API, Web Pages, and Razor -=== - -AppVeyor: [![AppVeyor](https://ci.appveyor.com/api/projects/status/github/aspnet/aspnetwebstack?branch=main&svg=true)](https://ci.appveyor.com/project/aspnetci/aspnetwebstack/branch/main) +# ASP.NET MVC, Web API, Web Pages, and Razor ## Note: This repo is for ASP.NET MVC 5.x, Web API 2.x, and Web Pages 3.x. For ASP.NET Core MVC, check the [AspNetCore repo](https://github.com/aspnet/AspNetCore). @@ -14,10 +11,6 @@ This repo includes: * ASP.NET Web Pages 3.x * ASP.NET Razor 3.x -### Nightly builds - -The latest built and tested packages from this repo are available on this MyGet feed: https://dotnet.myget.org/gallery/aspnetwebstack-dev - ### Contributing Check out the [contributing](CONTRIBUTING.md) page to see the best places to log issues and start discussions. @@ -32,5 +25,5 @@ Git tag or branch|Other products|MVC package versions|Web API package (product) [v3.1.3](https://github.com/aspnet/AspNetWebStack/tree/v3.1.3)||5.1.3|5.1.2 (2.1.2)|3.1.2 [v3.2.6](https://github.com/aspnet/AspNetWebStack/tree/v3.2.6)||5.2.6|5.2.6|3.2.6 [v3.2.7](https://github.com/aspnet/AspNetWebStack/tree/v3.2.7)||5.2.7|5.2.7|3.2.7 -[release/3.2.8](https://github.com/aspnet/AspNetWebStack/tree/release/3.2.8)|Work in progress on 5.2.8/3.2.8|||| +[v3.2.8](https://github.com/aspnet/AspNetWebStack/tree/v3.2.8)||5.2.8|5.2.8|3.2.8 [main](https://github.com/aspnet/AspNetWebStack/tree/main)|New work e.g. MVC 5.2.9-preview1|||| From 646f45271ef9fabba056aea8bdd6457cf9827bd5 Mon Sep 17 00:00:00 2001 From: Doug Bunting <6431421+dougbu@users.noreply.github.com> Date: Thu, 14 Apr 2022 18:35:46 -0700 Subject: [PATCH 16/54] Merge tag 'v3.2.8' into 'main' (#319) - see https://github.com/aspnet/AspNetWebStack/releases/tag/v3.2.8 for prominent issues resolved as well as a more detailed list of changes Co-authored-by: Pranav Krishnamoorthy Co-authored-by: Pranav K Co-authored-by: dotnet-bot --- .../InternetMessageFormatHeaderParser.cs | 12 ++++-- .../HttpContentMessageExtensions.cs | 2 +- .../PushStreamContent.cs | 33 ++++++++++----- .../HttpMessageHandlerAdapter.cs | 2 +- .../VB/WebApiHelpPage.VB.nuspec | 2 - src/WebApiHelpPage/WebApiHelpPage.nuspec | 4 +- test/Microsoft.TestCommon/PlatformInfo.cs | 2 +- ...et.Http.Formatting.NetStandard.Test.csproj | 2 +- .../DataSets/HttpTestData.cs | 4 +- .../Formatting/BsonMediaTypeFormatterTests.cs | 2 +- ...DataContractJsonMediaTypeFormatterTests.cs | 2 +- .../Formatting/JsonMediaTypeFormatterTests.cs | 2 +- .../Formatting/JsonNetSerializationTest.cs | 2 +- .../Formatting/XmlMediaTypeFormatterTests.cs | 4 +- .../HttpContentMessageExtensionsTests.cs | 40 +++++++++++++++++-- .../Internal/HttpValueCollectionTest.cs | 4 +- .../MultipartFileStreamProviderTests.cs | 10 ++++- 17 files changed, 91 insertions(+), 38 deletions(-) diff --git a/src/System.Net.Http.Formatting/Formatting/Parsers/InternetMessageFormatHeaderParser.cs b/src/System.Net.Http.Formatting/Formatting/Parsers/InternetMessageFormatHeaderParser.cs index aebfa8c29..ebf22b9ba 100644 --- a/src/System.Net.Http.Formatting/Formatting/Parsers/InternetMessageFormatHeaderParser.cs +++ b/src/System.Net.Http.Formatting/Formatting/Parsers/InternetMessageFormatHeaderParser.cs @@ -10,8 +10,8 @@ namespace System.Net.Http.Formatting.Parsers { /// - /// Buffer-oriented RFC 5322 style Internet Message Format parser which can be used to pass header - /// fields used in HTTP and MIME message entities. + /// Buffer-oriented RFC 5322 style Internet Message Format parser which can be used to pass header + /// fields used in HTTP and MIME message entities. /// internal class InternetMessageFormatHeaderParser { @@ -76,7 +76,7 @@ private enum HeaderFieldState /// /// Parse a buffer of RFC 5322 style header fields and add them to the collection. - /// Bytes are parsed in a consuming manner from the beginning of the buffer meaning that the same bytes can not be + /// Bytes are parsed in a consuming manner from the beginning of the buffer meaning that the same bytes can not be /// present in the buffer. /// /// Request buffer from where request is read @@ -283,7 +283,7 @@ private static ParserState ParseHeaderFields( } /// - /// Maintains information about the current header field being parsed. + /// Maintains information about the current header field being parsed. /// private class CurrentHeaderFieldStore { @@ -320,6 +320,10 @@ public void CopyTo(HttpHeaders headers, bool ignoreHeaderValidation) { var name = _name.ToString(); var value = _value.ToString().Trim(CurrentHeaderFieldStore._linearWhiteSpace); + if (string.Equals("expires", name, StringComparison.OrdinalIgnoreCase)) + { + ignoreHeaderValidation = true; + } if (ignoreHeaderValidation) { diff --git a/src/System.Net.Http.Formatting/HttpContentMessageExtensions.cs b/src/System.Net.Http.Formatting/HttpContentMessageExtensions.cs index dd801b604..a7dcb869d 100644 --- a/src/System.Net.Http.Formatting/HttpContentMessageExtensions.cs +++ b/src/System.Net.Http.Formatting/HttpContentMessageExtensions.cs @@ -223,7 +223,7 @@ private static async Task ReadAsHttpRequestMessageAsyncCore( HttpUnsortedRequest httpRequest = new HttpUnsortedRequest(); HttpRequestHeaderParser parser = new HttpRequestHeaderParser(httpRequest, - HttpRequestHeaderParser.DefaultMaxRequestLineSize, maxHeaderSize); + Math.Max(HttpRequestHeaderParser.DefaultMaxRequestLineSize, maxHeaderSize), maxHeaderSize); ParserState parseStatus; byte[] buffer = new byte[bufferSize]; diff --git a/src/System.Net.Http.Formatting/PushStreamContent.cs b/src/System.Net.Http.Formatting/PushStreamContent.cs index a8df4f262..6896e6c39 100644 --- a/src/System.Net.Http.Formatting/PushStreamContent.cs +++ b/src/System.Net.Http.Formatting/PushStreamContent.cs @@ -14,7 +14,7 @@ namespace System.Net.Http { /// /// Provides an implementation that exposes an output - /// which can be written to directly. The ability to push data to the output stream differs from the + /// which can be written to directly. The ability to push data to the output stream differs from the /// where data is pulled and not pushed. /// public class PushStreamContent : HttpContent @@ -24,8 +24,8 @@ public class PushStreamContent : HttpContent /// /// Initializes a new instance of the class. The /// action is called when an output stream - /// has become available allowing the action to write to it directly. When the - /// stream is closed, it will signal to the content that is has completed and the + /// has become available allowing the action to write to it directly. When the + /// stream is closed, it will signal to the content that it has completed and the /// HTTP request or response will be completed. /// /// The action to call when an output stream is available. @@ -35,10 +35,11 @@ public PushStreamContent(Action onStreamA } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - /// The action to call when an output stream is available. The stream is automatically - /// closed when the return task is completed. + /// The action to call when an output stream is available. When the + /// output stream is closed or disposed, it will signal to the content that it has completed and the + /// HTTP request or response will be completed. public PushStreamContent(Func onStreamAvailable) : this(onStreamAvailable, (MediaTypeHeaderValue)null) { @@ -47,6 +48,8 @@ public PushStreamContent(Func onStr /// /// Initializes a new instance of the class with the given media type. /// + /// The action to call when an output stream is available. + /// The value of the Content-Type content header on an HTTP response. public PushStreamContent(Action onStreamAvailable, string mediaType) : this(Taskify(onStreamAvailable), new MediaTypeHeaderValue(mediaType)) { @@ -55,6 +58,10 @@ public PushStreamContent(Action onStreamA /// /// Initializes a new instance of the class with the given media type. /// + /// The action to call when an output stream is available. When the + /// output stream is closed or disposed, it will signal to the content that it has completed and the + /// HTTP request or response will be completed. + /// The value of the Content-Type content header on an HTTP response. public PushStreamContent(Func onStreamAvailable, string mediaType) : this(onStreamAvailable, new MediaTypeHeaderValue(mediaType)) { @@ -63,6 +70,8 @@ public PushStreamContent(Func onStr /// /// Initializes a new instance of the class with the given . /// + /// The action to call when an output stream is available. + /// The value of the Content-Type content header on an HTTP response. public PushStreamContent(Action onStreamAvailable, MediaTypeHeaderValue mediaType) : this(Taskify(onStreamAvailable), mediaType) { @@ -71,6 +80,10 @@ public PushStreamContent(Action onStreamA /// /// Initializes a new instance of the class with the given . /// + /// The action to call when an output stream is available. When the + /// output stream is closed or disposed, it will signal to the content that it has completed and the + /// HTTP request or response will be completed. + /// The value of the Content-Type content header on an HTTP response. public PushStreamContent(Func onStreamAvailable, MediaTypeHeaderValue mediaType) { if (onStreamAvailable == null) @@ -98,8 +111,8 @@ private static Func Taskify( } /// - /// When this method is called, it calls the action provided in the constructor with the output - /// stream to write to. Once the action has completed its work it closes the stream which will + /// When this method is called, it calls the action provided in the constructor with the output + /// stream to write to. Once the action has completed its work it closes the stream which will /// close this content instance and complete the HTTP request or response. /// /// The to which to write. @@ -142,8 +155,8 @@ public CompleteTaskOnCloseStream(Stream innerStream, TaskCompletionSource #if NETFX_CORE [SuppressMessage( - "Microsoft.Usage", - "CA2215:Dispose methods should call base class dispose", + "Microsoft.Usage", + "CA2215:Dispose methods should call base class dispose", Justification = "See comments, this is intentional.")] protected override void Dispose(bool disposing) { diff --git a/src/System.Web.Http.Owin/HttpMessageHandlerAdapter.cs b/src/System.Web.Http.Owin/HttpMessageHandlerAdapter.cs index b8c6fc648..ac118a754 100644 --- a/src/System.Web.Http.Owin/HttpMessageHandlerAdapter.cs +++ b/src/System.Web.Http.Owin/HttpMessageHandlerAdapter.cs @@ -275,7 +275,7 @@ private static async Task CreateBufferedRequestContentAsync(IOwinRe } else { - buffer = new MemoryStream(contentLength.Value); + buffer = new MemoryStream(Math.Min(4 * 1024, contentLength.Value)); } cancellationToken.ThrowIfCancellationRequested(); diff --git a/src/WebApiHelpPage/VB/WebApiHelpPage.VB.nuspec b/src/WebApiHelpPage/VB/WebApiHelpPage.VB.nuspec index 6715ceca9..3e826d647 100644 --- a/src/WebApiHelpPage/VB/WebApiHelpPage.VB.nuspec +++ b/src/WebApiHelpPage/VB/WebApiHelpPage.VB.nuspec @@ -8,8 +8,6 @@ Microsoft http://www.asp.net/web-api - true - http://www.microsoft.com/web/webpi/eula/mvc4extensions_prerelease_eula.htm The ASP.NET Web API Help Page automatically generates help page content for the web APIs on your site. Visitors to your help page can use this content to learn how to call your web APIs. Everything generated by the help page is fully customizable using ASP.NET MVC and Razor. ASP.NET Web API Help Page is a great addition to any ASP.NET Web API project. The ASP.NET Web API Help Page automatically generates help page content for the web APIs on your site. diff --git a/src/WebApiHelpPage/WebApiHelpPage.nuspec b/src/WebApiHelpPage/WebApiHelpPage.nuspec index aa69da71f..8c69a51b1 100644 --- a/src/WebApiHelpPage/WebApiHelpPage.nuspec +++ b/src/WebApiHelpPage/WebApiHelpPage.nuspec @@ -8,8 +8,6 @@ Microsoft http://www.asp.net/web-api - true - http://www.microsoft.com/web/webpi/eula/mvc4extensions_prerelease_eula.htm The ASP.NET Web API Help Page automatically generates help page content for the web APIs on your site. Visitors to your help page can use this content to learn how to call your web APIs. Everything generated by the help page is fully customizable using ASP.NET MVC and Razor. ASP.NET Web API Help Page is a great addition to any ASP.NET Web API project. The ASP.NET Web API Help Page automatically generates help page content for the web APIs on your site. @@ -22,7 +20,7 @@ en-US - Microsoft AspNet WebApi AspNetWebApi HelpPage + Microsoft AspNet WebApi AspNetWebApi HelpPage diff --git a/test/Microsoft.TestCommon/PlatformInfo.cs b/test/Microsoft.TestCommon/PlatformInfo.cs index 678ecff08..e3026e39e 100644 --- a/test/Microsoft.TestCommon/PlatformInfo.cs +++ b/test/Microsoft.TestCommon/PlatformInfo.cs @@ -26,7 +26,7 @@ private static Platform GetPlatform() { if (Type.GetType(_netCore20TypeName, throwOnError: false) != null) { - // Treat .NET Core 2.0 as a .NET 4.5 superset though internal types are different. + // Treat .NET Core 2.1 as a .NET 4.5 superset though internal types are different. return Platform.Net45; } diff --git a/test/System.Net.Http.Formatting.NetStandard.Test/System.Net.Http.Formatting.NetStandard.Test.csproj b/test/System.Net.Http.Formatting.NetStandard.Test/System.Net.Http.Formatting.NetStandard.Test.csproj index 31732bd10..6cfb16e25 100644 --- a/test/System.Net.Http.Formatting.NetStandard.Test/System.Net.Http.Formatting.NetStandard.Test.csproj +++ b/test/System.Net.Http.Formatting.NetStandard.Test/System.Net.Http.Formatting.NetStandard.Test.csproj @@ -1,7 +1,7 @@  - netcoreapp2.0;net461 + netcoreapp2.1;net461 System.Net.Http System.Net.Http.Formatting.NetStandard.Test ..\..\bin\$(Configuration)\Test\ diff --git a/test/System.Net.Http.Formatting.Test/DataSets/HttpTestData.cs b/test/System.Net.Http.Formatting.Test/DataSets/HttpTestData.cs index fb482788b..84178a3a6 100644 --- a/test/System.Net.Http.Formatting.Test/DataSets/HttpTestData.cs +++ b/test/System.Net.Http.Formatting.Test/DataSets/HttpTestData.cs @@ -302,11 +302,11 @@ public static TheoryDataSet ReadAndWriteCorrectCharacterEn { "This is a test 激光這兩個字是甚麼意思 string written using utf-8", "utf-8", true }, { "This is a test 激光這兩個字是甚麼意思 string written using utf-16", "utf-16", true }, { "This is a test 激光這兩個字是甚麼意思 string written using utf-32", "utf-32", false }, -#if !NETCOREAPP2_0 // shift_jis and iso-2022-kr are not supported when running on .NET Core 2.0. +#if !NETCOREAPP // shift_jis and iso-2022-kr are not supported when running on .NET Core 2.1. { "This is a test 激光這兩個字是甚麼意思 string written using shift_jis", "shift_jis", false }, #endif { "This is a test æøå string written using iso-8859-1", "iso-8859-1", false }, -#if !NETCOREAPP2_0 +#if !NETCOREAPP { "This is a test 레이저 단어 뜻 string written using iso-2022-kr", "iso-2022-kr", false }, #endif }; diff --git a/test/System.Net.Http.Formatting.Test/Formatting/BsonMediaTypeFormatterTests.cs b/test/System.Net.Http.Formatting.Test/Formatting/BsonMediaTypeFormatterTests.cs index d849df473..caf93e059 100644 --- a/test/System.Net.Http.Formatting.Test/Formatting/BsonMediaTypeFormatterTests.cs +++ b/test/System.Net.Http.Formatting.Test/Formatting/BsonMediaTypeFormatterTests.cs @@ -415,7 +415,7 @@ public async Task ReadFromStreamAsync_RoundTripsWriteToStreamAsync_DBNullAsNull( Assert.Null(readObj); } -#if !NETCOREAPP2_0 // DBNull not serializable on .NET Core 2.0 except at top level (using BsonMediaTypeformatter special case). +#if !NETCOREAPP // DBNull not serializable on .NET Core 2.1 except at top level (using BsonMediaTypeformatter special case). [Theory] [TestDataSet(typeof(JsonMediaTypeFormatterTests), "DBNullAsObjectTestDataCollection", TestDataVariations.AsDictionary)] public async Task ReadFromStreamAsync_RoundTripsWriteToStreamAsync_DBNullAsNull_Dictionary(Type variationType, object testData) diff --git a/test/System.Net.Http.Formatting.Test/Formatting/DataContractJsonMediaTypeFormatterTests.cs b/test/System.Net.Http.Formatting.Test/Formatting/DataContractJsonMediaTypeFormatterTests.cs index ad3311326..e576a6924 100644 --- a/test/System.Net.Http.Formatting.Test/Formatting/DataContractJsonMediaTypeFormatterTests.cs +++ b/test/System.Net.Http.Formatting.Test/Formatting/DataContractJsonMediaTypeFormatterTests.cs @@ -157,7 +157,7 @@ public async Task ReadFromStreamAsync_RoundTripsWriteToStreamAsync_KnownTypes(Ty } } -#if !NETCOREAPP2_0 // DBNull not serializable on .NET Core 2.0. +#if !NETCOREAPP // DBNull not serializable on .NET Core 2.1. // Test alternate null value [Fact] public async Task ReadFromStreamAsync_RoundTripsWriteToStreamAsync_DBNull() diff --git a/test/System.Net.Http.Formatting.Test/Formatting/JsonMediaTypeFormatterTests.cs b/test/System.Net.Http.Formatting.Test/Formatting/JsonMediaTypeFormatterTests.cs index 34d17d884..3d7898ddb 100644 --- a/test/System.Net.Http.Formatting.Test/Formatting/JsonMediaTypeFormatterTests.cs +++ b/test/System.Net.Http.Formatting.Test/Formatting/JsonMediaTypeFormatterTests.cs @@ -374,7 +374,7 @@ public async Task ReadFromStreamAsync_RoundTripsWriteToStreamAsync(Type variatio } } -#if !NETCOREAPP2_0 // DBNull not serializable on .NET Core 2.0. +#if !NETCOREAPP // DBNull not serializable on .NET Core 2.1. // Test alternate null value; always serialized as "null" [Theory] [TestDataSet(typeof(JsonMediaTypeFormatterTests), "DBNullAsObjectTestDataCollection", TestDataVariations.AllSingleInstances)] diff --git a/test/System.Net.Http.Formatting.Test/Formatting/JsonNetSerializationTest.cs b/test/System.Net.Http.Formatting.Test/Formatting/JsonNetSerializationTest.cs index b544752f0..bd0edfd20 100644 --- a/test/System.Net.Http.Formatting.Test/Formatting/JsonNetSerializationTest.cs +++ b/test/System.Net.Http.Formatting.Test/Formatting/JsonNetSerializationTest.cs @@ -258,7 +258,7 @@ public Task DeserializingDeepArraysThrows() // low surrogate not preceded by high surrogate [InlineData("ABC \\udc00\\ud800 DEF", "ABC \ufffd\ufffd DEF")] // make sure unencoded invalid surrogate characters don't make it through -#if NETCOREAPP2_0 // Json.NET uses its regular invalid Unicode character on .NET Core 2.0; '?' elsewhere. +#if NETCOREAPP // Json.NET uses its regular invalid Unicode character on .NET Core 2.1; '?' elsewhere. [InlineData("\udc00\ud800\ud800", "\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd")] #else [InlineData("\udc00\ud800\ud800", "??????")] diff --git a/test/System.Net.Http.Formatting.Test/Formatting/XmlMediaTypeFormatterTests.cs b/test/System.Net.Http.Formatting.Test/Formatting/XmlMediaTypeFormatterTests.cs index b1865376b..3d7fd1557 100644 --- a/test/System.Net.Http.Formatting.Test/Formatting/XmlMediaTypeFormatterTests.cs +++ b/test/System.Net.Http.Formatting.Test/Formatting/XmlMediaTypeFormatterTests.cs @@ -36,7 +36,7 @@ public class XmlMediaTypeFormatterTests : MediaTypeFormatterTestBase actualCookieValue; + Assert.True(httpRequestMessage.Headers.TryGetValues("Cookie", out actualCookieValue)); + Assert.Equal(cookieValue, Assert.Single(actualCookieValue)); + } + + [Fact] + public async Task ReadAsHttpRequestMessageAsync_LargeHttpRequestLine() + { + string requestPath = string.Format("/myurl?{0}={1}", new string('a', 4 * 1024), new string('b', 4 * 1024)); + string cookieValue = string.Format("{0}={1}", new String('a', 4 * 1024), new String('b', 4 * 1024)); + string[] request = new[] + { + string.Format("GET {0} HTTP/1.1", requestPath), + @"Host: msdn.microsoft.com", + string.Format("Cookie: {0}", cookieValue), }; HttpContent content = CreateContent(true, request, "sample body"); - return content.ReadAsHttpRequestMessageAsync(Uri.UriSchemeHttp, 64 * 1024, 64 * 1024); + var httpRequestMessage = await content.ReadAsHttpRequestMessageAsync( + Uri.UriSchemeHttp, + bufferSize: 64 * 1024, + maxHeaderSize: 64 * 1024); + + Assert.Equal(HttpMethod.Get, httpRequestMessage.Method); + Assert.Equal(requestPath, httpRequestMessage.RequestUri.PathAndQuery); + Assert.Equal("msdn.microsoft.com", httpRequestMessage.Headers.Host); + IEnumerable actualCookieValue; + Assert.True(httpRequestMessage.Headers.TryGetValues("Cookie", out actualCookieValue)); + Assert.Equal(cookieValue, Assert.Single(actualCookieValue)); } [Theory] diff --git a/test/System.Net.Http.Formatting.Test/Internal/HttpValueCollectionTest.cs b/test/System.Net.Http.Formatting.Test/Internal/HttpValueCollectionTest.cs index 8e06557b4..626c655aa 100644 --- a/test/System.Net.Http.Formatting.Test/Internal/HttpValueCollectionTest.cs +++ b/test/System.Net.Http.Formatting.Test/Internal/HttpValueCollectionTest.cs @@ -14,7 +14,7 @@ namespace System.Net.Http.Internal { public class HttpValueCollectionTest { -#if !NETCOREAPP2_0 // Unused on .NET Core 2.0. +#if !NETCOREAPP // Unused on .NET Core 2.1. private static readonly int _maxCollectionKeys = 1000; #endif @@ -148,7 +148,7 @@ public void Create_CreatesEmptyCollection() Assert.Empty(nvc); } -#if !NETCOREAPP2_0 // DBNull not serializable on .NET Core 2.0. +#if !NETCOREAPP // DBNull not serializable on .NET Core 2.1. // This set of tests requires running on a separate appdomain so we don't // touch the static property MediaTypeFormatter.MaxHttpCollectionKeys. [Fact] diff --git a/test/System.Net.Http.Formatting.Test/MultipartFileStreamProviderTests.cs b/test/System.Net.Http.Formatting.Test/MultipartFileStreamProviderTests.cs index 6e62bef0e..0cc9c5b7a 100644 --- a/test/System.Net.Http.Formatting.Test/MultipartFileStreamProviderTests.cs +++ b/test/System.Net.Http.Formatting.Test/MultipartFileStreamProviderTests.cs @@ -32,6 +32,7 @@ public class MultipartFileStreamProviderTests : MultipartStreamProviderTestBase< private const int ValidBufferSize = 0x111; private const string ValidPath = @"c:\some\path"; +#if !NETCOREAPP // .NET Core does not enforce path validity in many APIs. public static TheoryDataSet NotSupportedFilePaths { get @@ -44,6 +45,7 @@ public static TheoryDataSet NotSupportedFilePaths }; } } +#endif public static TheoryDataSet InvalidFilePaths { @@ -52,15 +54,17 @@ public static TheoryDataSet InvalidFilePaths return new TheoryDataSet { "", - " ", + " ", " ", - "\t\t \n ", +#if !NETCOREAPP // .NET Core does not enforce path validity in many APIs. + "\t\t \n ", "c:\\ab", "c:\\a\"b", "c:\\a\tb", "c:\\a|b", "c:\\a\bb", +#endif "c:\\a\0b", "c :\\a\0b", }; @@ -73,12 +77,14 @@ public void Constructor_ThrowsOnNullRootPath() Assert.ThrowsArgumentNull(() => { new MultipartFileStreamProvider(null); }, "rootPath"); } +#if !NETCOREAPP // .NET Core does not enforce path validity in many APIs. [Theory] [PropertyData("NotSupportedFilePaths")] public void Constructor_ThrowsOnNotSupportedRootPath(string notSupportedPath) { Assert.Throws(() => new MultipartFileStreamProvider(notSupportedPath, ValidBufferSize)); } +#endif [Theory] [PropertyData("InvalidFilePaths")] From 0c55c2eada5b43e9de6c701260938fef22e8f08e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8B=AC=E6=8F=BD=E4=B9=9D=E5=A4=A9-=E5=B0=8F=E8=BE=89?= =?UTF-8?q?=E8=BE=89?= <2791341417@qq.com> Date: Tue, 2 Aug 2022 09:31:08 +0800 Subject: [PATCH 17/54] Fix code bug (#356) - address #357 --- src/System.Web.Http/ModelBinding/ErrorParameterBinding.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/System.Web.Http/ModelBinding/ErrorParameterBinding.cs b/src/System.Web.Http/ModelBinding/ErrorParameterBinding.cs index 05334819d..57b9c0b77 100644 --- a/src/System.Web.Http/ModelBinding/ErrorParameterBinding.cs +++ b/src/System.Web.Http/ModelBinding/ErrorParameterBinding.cs @@ -20,7 +20,7 @@ public ErrorParameterBinding(HttpParameterDescriptor descriptor, string message) { if (message == null) { - throw Error.ArgumentNull(message); + throw Error.ArgumentNull("message"); } _message = message; } @@ -36,7 +36,7 @@ public override string ErrorMessage public override Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken) { // Caller should have already checked IsError before executing, so we shoulnd't be here. - return TaskHelpers.FromError(new InvalidOperationException()); + return TaskHelpers.FromError(new InvalidOperationException()); } } } From 2d70c7ebeaa84f815dad3906e8c73af2bc582cdf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 26 Aug 2022 15:22:06 -0700 Subject: [PATCH 18/54] Bump Microsoft.Owin in /test/System.Web.Http.Owin.Test (#358) Bumps [Microsoft.Owin](https://github.com/aspnet/AspNetKatana) from 2.0.2 to 4.1.1. - [Release notes](https://github.com/aspnet/AspNetKatana/releases) - [Commits](https://github.com/aspnet/AspNetKatana/compare/v2.0.2...v4.1.1) --- updated-dependencies: - dependency-name: Microsoft.Owin dependency-type: direct:production ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- test/System.Web.Http.Owin.Test/packages.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/System.Web.Http.Owin.Test/packages.config b/test/System.Web.Http.Owin.Test/packages.config index 257cb23d3..b565fd344 100644 --- a/test/System.Web.Http.Owin.Test/packages.config +++ b/test/System.Web.Http.Owin.Test/packages.config @@ -1,7 +1,7 @@  - + From f9e0cef755c75ed56e7da76522352e1fc06f66c1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 26 Aug 2022 15:23:13 -0700 Subject: [PATCH 19/54] Bump Microsoft.Owin from 2.0.2 to 4.1.1 in /src/System.Web.Http.Owin (#359) Bumps [Microsoft.Owin](https://github.com/aspnet/AspNetKatana) from 2.0.2 to 4.1.1. - [Release notes](https://github.com/aspnet/AspNetKatana/releases) - [Commits](https://github.com/aspnet/AspNetKatana/compare/v2.0.2...v4.1.1) --- updated-dependencies: - dependency-name: Microsoft.Owin dependency-type: direct:production ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/System.Web.Http.Owin/packages.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Web.Http.Owin/packages.config b/src/System.Web.Http.Owin/packages.config index 57b34eaa5..7d677d330 100644 --- a/src/System.Web.Http.Owin/packages.config +++ b/src/System.Web.Http.Owin/packages.config @@ -1,5 +1,5 @@  - + \ No newline at end of file From cd0186268be4679be68295e42428d8b18d8e09a1 Mon Sep 17 00:00:00 2001 From: Doug Bunting <6431421+dougbu@users.noreply.github.com> Date: Mon, 29 Aug 2022 19:28:52 -0700 Subject: [PATCH 20/54] Move `Microsoft.Owin*` packages to 4.2.2 (#360) - follow on from #358 - use the latest versions consistently - correct `%(Hintpath)` metadata - Dependabot doesn't fix this information automatically --- src/System.Web.Http.Owin/System.Web.Http.Owin.csproj | 2 +- src/System.Web.Http.Owin/packages.config | 2 +- .../System.Web.Http.Owin.Test.csproj | 10 +++++----- test/System.Web.Http.Owin.Test/packages.config | 6 +++--- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/System.Web.Http.Owin/System.Web.Http.Owin.csproj b/src/System.Web.Http.Owin/System.Web.Http.Owin.csproj index 40565650e..ae8d5176d 100644 --- a/src/System.Web.Http.Owin/System.Web.Http.Owin.csproj +++ b/src/System.Web.Http.Owin/System.Web.Http.Owin.csproj @@ -14,7 +14,7 @@ - ..\..\packages\Microsoft.Owin.2.0.2\lib\net45\Microsoft.Owin.dll + ..\..\packages\Microsoft.Owin.4.2.2\lib\net45\Microsoft.Owin.dll ..\..\packages\Owin.1.0\lib\net40\Owin.dll diff --git a/src/System.Web.Http.Owin/packages.config b/src/System.Web.Http.Owin/packages.config index 7d677d330..a288e84ae 100644 --- a/src/System.Web.Http.Owin/packages.config +++ b/src/System.Web.Http.Owin/packages.config @@ -1,5 +1,5 @@  - + \ No newline at end of file diff --git a/test/System.Web.Http.Owin.Test/System.Web.Http.Owin.Test.csproj b/test/System.Web.Http.Owin.Test/System.Web.Http.Owin.Test.csproj index 021820fb9..5d23d8018 100644 --- a/test/System.Web.Http.Owin.Test/System.Web.Http.Owin.Test.csproj +++ b/test/System.Web.Http.Owin.Test/System.Web.Http.Owin.Test.csproj @@ -19,15 +19,15 @@ True - ..\..\packages\Microsoft.Owin.2.0.2\lib\net45\Microsoft.Owin.dll + ..\..\packages\Microsoft.Owin.4.2.2\lib\net45\Microsoft.Owin.dll - + False - ..\..\packages\Microsoft.Owin.Host.HttpListener.2.0.2\lib\net45\Microsoft.Owin.Host.HttpListener.dll + ..\..\packages\Microsoft.Owin.Host.HttpListener.4.2.2\lib\net45\Microsoft.Owin.Host.HttpListener.dll - + False - ..\..\packages\Microsoft.Owin.Hosting.2.0.2\lib\net45\Microsoft.Owin.Hosting.dll + ..\..\packages\Microsoft.Owin.Hosting.4.2.2\lib\net45\Microsoft.Owin.Hosting.dll ..\..\packages\Moq.4.7.142\lib\net45\Moq.dll diff --git a/test/System.Web.Http.Owin.Test/packages.config b/test/System.Web.Http.Owin.Test/packages.config index b565fd344..60f5181dd 100644 --- a/test/System.Web.Http.Owin.Test/packages.config +++ b/test/System.Web.Http.Owin.Test/packages.config @@ -1,9 +1,9 @@  - - - + + + From eae5661279c595544c45478b998f7995729422cd Mon Sep 17 00:00:00 2001 From: Doug Bunting <6431421+dougbu@users.noreply.github.com> Date: Sat, 19 Nov 2022 15:32:34 -0800 Subject: [PATCH 21/54] Ease builds on CI and locally (#364) react to a smallish breaking change in newer Owin packages - add new test of `%` decoding to URI - do not restore RuntimePortable.sln directly - NuGet.exe is no longer happy w/ that solution - ignore binary logs - ensure the .NET Core 2.1 VS component is installed - allow use of any 2.1.5xx .NET SDK - add a few words to code analysis dictionary - exclude files generated for `net45` legacy projects don't cause problems when compiling for `netstandard2.0` - handle additional `ReflectionTypeLoadException`s when using the xUnit `msbuild` runner nits: - capitalize "MSBuild" consistently - reduce indentation slightly --- .gitignore | 1 + Runtime.msbuild | 46 ++++++++++++------- build.cmd | 4 +- global.json | 3 +- src/CodeAnalysisDictionary.xml | 7 +++ ...tem.Net.Http.Formatting.NetStandard.csproj | 2 +- ...et.Http.Formatting.NetStandard.Test.csproj | 2 +- .../Tracing/TracingTest.cs | 42 +++++++++++++---- .../HttpMessageHandlerAdapterTest.cs | 22 ++++++++- 9 files changed, 99 insertions(+), 30 deletions(-) diff --git a/.gitignore b/.gitignore index 11bf8ccc5..6cd7bfb72 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ packages NuGet.exe _[Ss]cripts +*.binlog *.exe *.dll *.nupkg diff --git a/Runtime.msbuild b/Runtime.msbuild index c3f2294e7..2e785ab2e 100644 --- a/Runtime.msbuild +++ b/Runtime.msbuild @@ -64,24 +64,38 @@ - - - - + + <_NuGetPackagesAndSolutions Include="src\System.Net.Http.Formatting.NetCore\packages.config; + test\System.Net.Http.Formatting.NetCore.Test\packages.config; + Runtime.sln" /> + + + <_NuGetPackagesAndSolutions Include="src\System.Net.Http.Formatting.NetCore\packages.config; + test\System.Net.Http.Formatting.NetCore.Test\packages.config" + Condition=" '$(BuildPortable)' == 'true' " /> + <_ProjectsToRestore Include="src\System.Net.Http.Formatting.NetStandard\System.Net.Http.Formatting.NetStandard.csproj; + test\System.Net.Http.Formatting.NetStandard.Test\System.Net.Http.Formatting.NetStandard.Test.csproj" + Condition=" '$(BuildPortable)' == 'true' " /> + - + + + - $(MsBuildThisFileDirectory)tools\src\Microsoft.Web.FxCop\ - $(MsBuildThisFileDirectory)packages\CustomFxCopRules + $(MSBuildThisFileDirectory)tools\src\Microsoft.Web.FxCop\ + $(MSBuildThisFileDirectory)packages\CustomFxCopRules - + @@ -89,11 +103,11 @@ + Projects="@(SolutionsToBuild)" + BuildInParallel="%(SolutionsToBuild.BuildInParallel)" + Targets="Build" + Condition=" '%(SolutionsToBuild.Portable)' != 'true' or '$(BuildPortable)' == 'true' " + Properties="Configuration=$(Configuration);CodeAnalysis=$(CodeAnalysis);StyleCopEnabled=$(StyleCopEnabled);VisualStudioVersion=$(VisualStudioVersion)" /> diff --git a/build.cmd b/build.cmd index e49e2cfb8..270103785 100644 --- a/build.cmd +++ b/build.cmd @@ -26,7 +26,9 @@ if not exist %vswhere% ( ) set InstallDir= -for /f "usebackq tokens=*" %%i in (`%vswhere% -version ^[15^,16^) -latest -prerelease -products * -requires Microsoft.Component.MSBuild -property installationPath`) do ( +for /f "usebackq tokens=*" %%i in (`%vswhere% -version ^[15^,16^) -latest -prerelease -products * ^ + -requires Microsoft.Component.MSBuild -requires Microsoft.Net.Core.Component.SDK.2.1 ^ + -property installationPath`) do ( set InstallDir=%%i ) if exist "%InstallDir%\MSBuild\15.0\Bin\MSBuild.exe" ( diff --git a/global.json b/global.json index 3e8915949..9ddc9bf9c 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,6 @@ { "sdk": { - "version": "2.1.523" + "version": "2.1.500", + "rollForward": "latestPatch" } } diff --git a/src/CodeAnalysisDictionary.xml b/src/CodeAnalysisDictionary.xml index fdd4e0ea7..26ab4a8af 100644 --- a/src/CodeAnalysisDictionary.xml +++ b/src/CodeAnalysisDictionary.xml @@ -55,6 +55,13 @@ ModelName BSON Untyped + Behavior + Callback + Canceled + Color + Fallback + Markup + Preflight WebPage diff --git a/src/System.Net.Http.Formatting.NetStandard/System.Net.Http.Formatting.NetStandard.csproj b/src/System.Net.Http.Formatting.NetStandard/System.Net.Http.Formatting.NetStandard.csproj index 0211316d3..400278d86 100644 --- a/src/System.Net.Http.Formatting.NetStandard/System.Net.Http.Formatting.NetStandard.csproj +++ b/src/System.Net.Http.Formatting.NetStandard/System.Net.Http.Formatting.NetStandard.csproj @@ -41,7 +41,7 @@ Common\UriQueryUtility.cs - + %(RecursiveDir)\%(Filename).cs diff --git a/test/System.Net.Http.Formatting.NetStandard.Test/System.Net.Http.Formatting.NetStandard.Test.csproj b/test/System.Net.Http.Formatting.NetStandard.Test/System.Net.Http.Formatting.NetStandard.Test.csproj index 6cfb16e25..dbbca8480 100644 --- a/test/System.Net.Http.Formatting.NetStandard.Test/System.Net.Http.Formatting.NetStandard.Test.csproj +++ b/test/System.Net.Http.Formatting.NetStandard.Test/System.Net.Http.Formatting.NetStandard.Test.csproj @@ -15,7 +15,7 @@ - + %(RecursiveDir)\%(Filename).cs diff --git a/test/System.Web.Http.Integration.Test/Tracing/TracingTest.cs b/test/System.Web.Http.Integration.Test/Tracing/TracingTest.cs index 39e6cffd9..bc5d1618b 100644 --- a/test/System.Web.Http.Integration.Test/Tracing/TracingTest.cs +++ b/test/System.Web.Http.Integration.Test/Tracing/TracingTest.cs @@ -380,12 +380,24 @@ private static IList UnexpectedTraces(IList expecte // artifact specific to testing in VS. (Attempting to load all types from xunit.runner.visualstudio.testadapter.dll // fails with recent xUnit.net packages. The assembly references Microsoft.VisualStudio.TestPlatform.ObjectModel.dll // which is not available with xUnit.net 2.0.x.) + // + // Similarly, ignore records for the same exception to allow test to succeed when using the xUnit MSBuild runner. + // In that case, missing types may come from System.Web and Microsoft.Build.Utilities.v4.0 as well as xunit.runner.msbuild.net452. if (actualRecord.Operation == null && actualRecord.Exception is ReflectionTypeLoadException && actualRecord.Message != null && - actualRecord.Message.StartsWith( - "Exception thrown while getting types from 'xunit.runner.visualstudio.testadapter, ", - StringComparison.Ordinal)) + (actualRecord.Message.StartsWith( + "Exception thrown while getting types from 'xunit.runner.visualstudio.testadapter, ", + StringComparison.Ordinal) || + actualRecord.Message.StartsWith( + "Exception thrown while getting types from 'xunit.runner.msbuild.", + StringComparison.Ordinal) || + actualRecord.Message.StartsWith( + "Exception thrown while getting types from 'System.Web, ", + StringComparison.Ordinal) || + actualRecord.Message.StartsWith( + "Exception thrown while getting types from 'Microsoft.Build.Utilities.", + StringComparison.Ordinal))) { continue; } @@ -397,8 +409,8 @@ actualRecord.Exception is ReflectionTypeLoadException && if (expectedTrace == null) { - unexpected.Add(string.Format("kind={0} category={1}, operator={2}, operation={3}", - actualRecord.Kind, actualRecord.Category, actualRecord.Operator, actualRecord.Operation)); + unexpected.Add(string.Format("kind={0} category={1}, operator={2}, operation={3}, message={4}", + actualRecord.Kind, actualRecord.Category, actualRecord.Operator, actualRecord.Operation, actualRecord.Message)); } } @@ -422,14 +434,26 @@ private static bool ConfirmTracingOrder(IList expectedRecor // artifact specific to testing in VS. (Attempting to load all types from xunit.runner.visualstudio.testadapter.dll // fails with recent xUnit.net packages. The assembly references Microsoft.VisualStudio.TestPlatform.ObjectModel.dll // which is not available with xUnit.net 2.0.x.) + // + // Similarly, ignore records for the same exception to allow test to succeed when using the xUnit MSBuild runner. + // In that case, missing types may come from System.Web and Microsoft.Build.Utilities.v4.0 as well as xunit.runner.msbuild.net452. var actualRecord = actualRecords.ElementAtOrDefault(traceBeginPos); - if (actualRecord != null && + while (actualRecord != null && actualRecord.Operation == null && actualRecord.Exception is ReflectionTypeLoadException && actualRecord.Message != null && - actualRecord.Message.StartsWith( - "Exception thrown while getting types from 'xunit.runner.visualstudio.testadapter, ", - StringComparison.Ordinal)) + (actualRecord.Message.StartsWith( + "Exception thrown while getting types from 'xunit.runner.visualstudio.testadapter, ", + StringComparison.Ordinal) || + actualRecord.Message.StartsWith( + "Exception thrown while getting types from 'xunit.runner.msbuild.", + StringComparison.Ordinal) || + actualRecord.Message.StartsWith( + "Exception thrown while getting types from 'System.Web, ", + StringComparison.Ordinal) || + actualRecord.Message.StartsWith( + "Exception thrown while getting types from 'Microsoft.Build.Utilities.", + StringComparison.Ordinal))) { traceBeginPos++; actualRecord = actualRecords.ElementAtOrDefault(traceBeginPos); diff --git a/test/System.Web.Http.Owin.Test/HttpMessageHandlerAdapterTest.cs b/test/System.Web.Http.Owin.Test/HttpMessageHandlerAdapterTest.cs index 8ddfce69d..b8b25e30f 100644 --- a/test/System.Web.Http.Owin.Test/HttpMessageHandlerAdapterTest.cs +++ b/test/System.Web.Http.Owin.Test/HttpMessageHandlerAdapterTest.cs @@ -429,7 +429,6 @@ public async Task Invoke_BuildsUriWithHostAndPort() [InlineData(@"-_.~+""<>^`{|}")] // random unicode characters [InlineData("激光這")] - [InlineData("%24")] [InlineData("?#")] public async Task Invoke_CreatesUri_ThatGeneratesCorrectlyDecodedStrings(string decodedId) { @@ -447,6 +446,27 @@ public async Task Invoke_CreatesUri_ThatGeneratesCorrectlyDecodedStrings(string Assert.Equal(decodedId, routeData.Values["id"]); } + [Theory] + [InlineData("%24", "$")] + [InlineData("%28%29", "()")] + [InlineData("%5B%5D", "[]")] + [InlineData("%7B%7D", "{}")] + public async Task Invoke_CreatesUri_ContainingCorrectlyDecodedStrings(string encoded, string decoded) + { + var handler = CreateOKHandlerStub(); + var bufferPolicySelector = CreateBufferPolicySelector(bufferInput: false, bufferOutput: false); + var environment = CreateOwinEnvironment("GET", "http", "localhost", "/vroot", "/api/customers/" + encoded); + var options = CreateValidOptions(handler, bufferPolicySelector); + var adapter = CreateProductUnderTest(options); + var route = new HttpRoute("api/customers/{id}"); + + await adapter.Invoke(new OwinContext(environment)); + IHttpRouteData routeData = route.GetRouteData("/vroot", handler.Request); + + Assert.NotNull(routeData); + Assert.Equal(decoded, routeData.Values["id"]); + } + [Fact] public async Task Invoke_AddsRequestHeadersToRequestMessage() { From 871710e99a9d03cf9cc232c32b389b9b996236b7 Mon Sep 17 00:00:00 2001 From: Doug Bunting <6431421+dougbu@users.noreply.github.com> Date: Sat, 19 Nov 2022 15:34:20 -0800 Subject: [PATCH 22/54] Ease builds on CI and locally (#364) - react to a smallish breaking change in newer Owin packages - add new test of `%` decoding to URI - do not restore RuntimePortable.sln directly - ignore binary logs - ensure the .NET Core 2.1 VS component is installed - allow use of any 2.1.5xx .NET SDK - add a few words to code analysis dictionary - exclude files generated for `net45` legacy projects don't cause problems when compiling for `netstandard2.0` - handle additional `ReflectionTypeLoadException`s when using the xUnit `msbuild` runner nits: - capitalize "MSBuild" consistently - reduce indentation slightly From 587d433f21daf85075e4e1d18f145825f5eabdea Mon Sep 17 00:00:00 2001 From: William Godbe Date: Mon, 21 Nov 2022 11:08:42 -0800 Subject: [PATCH 23/54] Enable CodeQl3000 (#365) * Add CodeQL pipeline * Fixup * Fix image * myget feeds * Fix nuget.config * Fix build invocation * fix nuget.config * Fix build steps * Spacing * Remove .DS_Store files --- .codeql.yml | 66 ++++ .config/tsaoptions.json | 12 + .nuget/NuGet.Config | 6 +- eng/common/templates/job/execute-sdl.yml | 134 +++++++++ eng/common/templates/job/job.yml | 230 ++++++++++++++ eng/common/templates/job/onelocbuild.yml | 107 +++++++ .../templates/job/publish-build-assets.yml | 150 ++++++++++ eng/common/templates/job/source-build.yml | 74 +++++ .../templates/job/source-index-stage1.yml | 67 +++++ eng/common/templates/jobs/codeql-build.yml | 31 ++ eng/common/templates/jobs/jobs.yml | 97 ++++++ eng/common/templates/jobs/source-build.yml | 46 +++ .../templates/post-build/common-variables.yml | 22 ++ .../templates/post-build/post-build.yml | 281 ++++++++++++++++++ .../post-build/setup-maestro-vars.yml | 70 +++++ .../post-build/trigger-subscription.yml | 13 + .../templates/steps/add-build-to-channel.yml | 13 + eng/common/templates/steps/build-reason.yml | 12 + eng/common/templates/steps/execute-codeql.yml | 32 ++ eng/common/templates/steps/execute-sdl.yml | 88 ++++++ eng/common/templates/steps/generate-sbom.yml | 48 +++ eng/common/templates/steps/publish-logs.yml | 23 ++ eng/common/templates/steps/retain-build.yml | 28 ++ eng/common/templates/steps/run-on-unix.yml | 7 + eng/common/templates/steps/run-on-windows.yml | 7 + .../steps/run-script-ifequalelse.yml | 33 ++ eng/common/templates/steps/send-to-helix.yml | 91 ++++++ eng/common/templates/steps/source-build.yml | 114 +++++++ eng/common/templates/steps/telemetry-end.yml | 102 +++++++ .../templates/steps/telemetry-start.yml | 241 +++++++++++++++ .../templates/variables/pool-providers.yml | 48 +++ .../templates/variables/sdl-variables.yml | 7 + 32 files changed, 2297 insertions(+), 3 deletions(-) create mode 100644 .codeql.yml create mode 100644 .config/tsaoptions.json create mode 100644 eng/common/templates/job/execute-sdl.yml create mode 100644 eng/common/templates/job/job.yml create mode 100644 eng/common/templates/job/onelocbuild.yml create mode 100644 eng/common/templates/job/publish-build-assets.yml create mode 100644 eng/common/templates/job/source-build.yml create mode 100644 eng/common/templates/job/source-index-stage1.yml create mode 100644 eng/common/templates/jobs/codeql-build.yml create mode 100644 eng/common/templates/jobs/jobs.yml create mode 100644 eng/common/templates/jobs/source-build.yml create mode 100644 eng/common/templates/post-build/common-variables.yml create mode 100644 eng/common/templates/post-build/post-build.yml create mode 100644 eng/common/templates/post-build/setup-maestro-vars.yml create mode 100644 eng/common/templates/post-build/trigger-subscription.yml create mode 100644 eng/common/templates/steps/add-build-to-channel.yml create mode 100644 eng/common/templates/steps/build-reason.yml create mode 100644 eng/common/templates/steps/execute-codeql.yml create mode 100644 eng/common/templates/steps/execute-sdl.yml create mode 100644 eng/common/templates/steps/generate-sbom.yml create mode 100644 eng/common/templates/steps/publish-logs.yml create mode 100644 eng/common/templates/steps/retain-build.yml create mode 100644 eng/common/templates/steps/run-on-unix.yml create mode 100644 eng/common/templates/steps/run-on-windows.yml create mode 100644 eng/common/templates/steps/run-script-ifequalelse.yml create mode 100644 eng/common/templates/steps/send-to-helix.yml create mode 100644 eng/common/templates/steps/source-build.yml create mode 100644 eng/common/templates/steps/telemetry-end.yml create mode 100644 eng/common/templates/steps/telemetry-start.yml create mode 100644 eng/common/templates/variables/pool-providers.yml create mode 100644 eng/common/templates/variables/sdl-variables.yml diff --git a/.codeql.yml b/.codeql.yml new file mode 100644 index 000000000..7ad4723f1 --- /dev/null +++ b/.codeql.yml @@ -0,0 +1,66 @@ +parameters: + # Optionally do not publish to TSA. Useful for e.g. verifying fixes before PR. +- name: TSAEnabled + displayName: Publish results to TSA + type: boolean + default: true + +variables: +- template: eng/common/templates/variables/pool-providers.yml + # CG is handled in the primary CI pipeline +- name: skipComponentGovernanceDetection + value: true + # Force CodeQL enabled so it may be run on any branch +- name: Codeql.Enabled + value: true + # Do not let CodeQL 3000 Extension gate scan frequency +- name: Codeql.Cadence + value: 0 +- name: Codeql.SourceRoot + value: src + # CodeQL needs this plumbed along as a variable to enable TSA +- name: Codeql.TSAEnabled + value: ${{ parameters.TSAEnabled }} +# Default expects tsaoptions.json under SourceRoot. +- name: Codeql.TSAOptionsPath + value: '$(Build.SourcesDirectory)/.config/tsaoptions.json' + + # Build variables +- name: _BuildConfig + value: Release + +trigger: none + +schedules: + - cron: 0 12 * * 1 + displayName: Weekly Monday CodeQL run + branches: + include: + - main + always: true + +jobs: +- job: codeql + displayName: CodeQL + pool: + name: NetCore1ESPool-Internal + demands: ImageOverride -equals windows.vs2017.amd64 + timeoutInMinutes: 90 + + steps: + + - task: UseDotNet@2 + inputs: + useGlobalJson: true + + - task: CodeQL3000Init@0 + displayName: CodeQL Initialize + + - script: .\build.cmd EnableSkipStrongNames + displayName: Windows Build - EnableSkipStrongNames + + - script: .\build.cmd + displayName: Windows Build + + - task: CodeQL3000Finalize@0 + displayName: CodeQL Finalize diff --git a/.config/tsaoptions.json b/.config/tsaoptions.json new file mode 100644 index 000000000..ae5e4f91d --- /dev/null +++ b/.config/tsaoptions.json @@ -0,0 +1,12 @@ +{ + "areaPath": "DevDiv\\ASP.NET Core", + "codebaseName": "AspNetWebStack", + "instanceUrl": "https://devdiv.visualstudio.com/", + "iterationPath": "DevDiv", + "notificationAliases": [ + "aspnetcore-build@microsoft.com" + ], + "projectName": "DEVDIV", + "repositoryName": "AspNetWebStack", + "template": "TFSDEVDIV" +} \ No newline at end of file diff --git a/.nuget/NuGet.Config b/.nuget/NuGet.Config index 6ff25f633..837d83954 100644 --- a/.nuget/NuGet.Config +++ b/.nuget/NuGet.Config @@ -4,8 +4,8 @@ - - - + + + \ No newline at end of file diff --git a/eng/common/templates/job/execute-sdl.yml b/eng/common/templates/job/execute-sdl.yml new file mode 100644 index 000000000..7aabaa180 --- /dev/null +++ b/eng/common/templates/job/execute-sdl.yml @@ -0,0 +1,134 @@ +parameters: + enable: 'false' # Whether the SDL validation job should execute or not + overrideParameters: '' # Optional: to override values for parameters. + additionalParameters: '' # Optional: parameters that need user specific values eg: '-SourceToolsList @("abc","def") -ArtifactToolsList @("ghi","jkl")' + # Optional: if specified, restore and use this version of Guardian instead of the default. + overrideGuardianVersion: '' + # Optional: if true, publish the '.gdn' folder as a pipeline artifact. This can help with in-depth + # diagnosis of problems with specific tool configurations. + publishGuardianDirectoryToPipeline: false + # The script to run to execute all SDL tools. Use this if you want to use a script to define SDL + # parameters rather than relying on YAML. It may be better to use a local script, because you can + # reproduce results locally without piecing together a command based on the YAML. + executeAllSdlToolsScript: 'eng/common/sdl/execute-all-sdl-tools.ps1' + # There is some sort of bug (has been reported) in Azure DevOps where if this parameter is named + # 'continueOnError', the parameter value is not correctly picked up. + # This can also be remedied by the caller (post-build.yml) if it does not use a nested parameter + sdlContinueOnError: false # optional: determines whether to continue the build if the step errors; + # optional: determines if build artifacts should be downloaded. + downloadArtifacts: true + # optional: determines if this job should search the directory of downloaded artifacts for + # 'tar.gz' and 'zip' archive files and extract them before running SDL validation tasks. + extractArchiveArtifacts: false + dependsOn: '' # Optional: dependencies of the job + artifactNames: '' # Optional: patterns supplied to DownloadBuildArtifacts + # Usage: + # artifactNames: + # - 'BlobArtifacts' + # - 'Artifacts_Windows_NT_Release' + # Optional: download a list of pipeline artifacts. 'downloadArtifacts' controls build artifacts, + # not pipeline artifacts, so doesn't affect the use of this parameter. + pipelineArtifactNames: [] + +jobs: +- job: Run_SDL + dependsOn: ${{ parameters.dependsOn }} + displayName: Run SDL tool + condition: and(succeededOrFailed(), eq( ${{ parameters.enable }}, 'true')) + variables: + - group: DotNet-VSTS-Bot + - name: AzDOProjectName + value: ${{ parameters.AzDOProjectName }} + - name: AzDOPipelineId + value: ${{ parameters.AzDOPipelineId }} + - name: AzDOBuildId + value: ${{ parameters.AzDOBuildId }} + - template: /eng/common/templates/variables/sdl-variables.yml + - name: GuardianVersion + value: ${{ coalesce(parameters.overrideGuardianVersion, '$(DefaultGuardianVersion)') }} + - template: /eng/common/templates/variables/pool-providers.yml + pool: + # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) + ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: + name: VSEngSS-MicroBuild2022-1ES + demands: Cmd + # If it's not devdiv, it's dnceng + ${{ if ne(variables['System.TeamProject'], 'DevDiv') }}: + name: $(DncEngInternalBuildPool) + demands: ImageOverride -equals windows.vs2019.amd64 + steps: + - checkout: self + clean: true + + # If the template caller didn't provide an AzDO parameter, set them all up as Maestro vars. + - ${{ if not(and(parameters.AzDOProjectName, parameters.AzDOPipelineId, parameters.AzDOBuildId)) }}: + - template: /eng/common/templates/post-build/setup-maestro-vars.yml + + - ${{ if ne(parameters.downloadArtifacts, 'false')}}: + - ${{ if ne(parameters.artifactNames, '') }}: + - ${{ each artifactName in parameters.artifactNames }}: + - task: DownloadBuildArtifacts@0 + displayName: Download Build Artifacts + inputs: + buildType: specific + buildVersionToDownload: specific + project: $(AzDOProjectName) + pipeline: $(AzDOPipelineId) + buildId: $(AzDOBuildId) + artifactName: ${{ artifactName }} + downloadPath: $(Build.ArtifactStagingDirectory)\artifacts + checkDownloadedFiles: true + - ${{ if eq(parameters.artifactNames, '') }}: + - task: DownloadBuildArtifacts@0 + displayName: Download Build Artifacts + inputs: + buildType: specific + buildVersionToDownload: specific + project: $(AzDOProjectName) + pipeline: $(AzDOPipelineId) + buildId: $(AzDOBuildId) + downloadType: specific files + itemPattern: "**" + downloadPath: $(Build.ArtifactStagingDirectory)\artifacts + checkDownloadedFiles: true + + - ${{ each artifactName in parameters.pipelineArtifactNames }}: + - task: DownloadPipelineArtifact@2 + displayName: Download Pipeline Artifacts + inputs: + buildType: specific + buildVersionToDownload: specific + project: $(AzDOProjectName) + pipeline: $(AzDOPipelineId) + buildId: $(AzDOBuildId) + artifactName: ${{ artifactName }} + downloadPath: $(Build.ArtifactStagingDirectory)\artifacts + checkDownloadedFiles: true + + - powershell: eng/common/sdl/extract-artifact-packages.ps1 + -InputPath $(Build.ArtifactStagingDirectory)\artifacts\BlobArtifacts + -ExtractPath $(Build.ArtifactStagingDirectory)\artifacts\BlobArtifacts + displayName: Extract Blob Artifacts + continueOnError: ${{ parameters.sdlContinueOnError }} + + - powershell: eng/common/sdl/extract-artifact-packages.ps1 + -InputPath $(Build.ArtifactStagingDirectory)\artifacts\PackageArtifacts + -ExtractPath $(Build.ArtifactStagingDirectory)\artifacts\PackageArtifacts + displayName: Extract Package Artifacts + continueOnError: ${{ parameters.sdlContinueOnError }} + + - ${{ if ne(parameters.extractArchiveArtifacts, 'false') }}: + - powershell: eng/common/sdl/extract-artifact-archives.ps1 + -InputPath $(Build.ArtifactStagingDirectory)\artifacts + -ExtractPath $(Build.ArtifactStagingDirectory)\artifacts + displayName: Extract Archive Artifacts + continueOnError: ${{ parameters.sdlContinueOnError }} + + - template: /eng/common/templates/steps/execute-sdl.yml + parameters: + overrideGuardianVersion: ${{ parameters.overrideGuardianVersion }} + executeAllSdlToolsScript: ${{ parameters.executeAllSdlToolsScript }} + overrideParameters: ${{ parameters.overrideParameters }} + additionalParameters: ${{ parameters.additionalParameters }} + publishGuardianDirectoryToPipeline: ${{ parameters.publishGuardianDirectoryToPipeline }} + sdlContinueOnError: ${{ parameters.sdlContinueOnError }} diff --git a/eng/common/templates/job/job.yml b/eng/common/templates/job/job.yml new file mode 100644 index 000000000..9f55d3f46 --- /dev/null +++ b/eng/common/templates/job/job.yml @@ -0,0 +1,230 @@ +# Internal resources (telemetry, microbuild) can only be accessed from non-public projects, +# and some (Microbuild) should only be applied to non-PR cases for internal builds. + +parameters: +# Job schema parameters - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#job + cancelTimeoutInMinutes: '' + condition: '' + container: '' + continueOnError: false + dependsOn: '' + displayName: '' + pool: '' + steps: [] + strategy: '' + timeoutInMinutes: '' + variables: [] + workspace: '' + +# Job base template specific parameters + # See schema documentation - https://github.com/dotnet/arcade/blob/master/Documentation/AzureDevOps/TemplateSchema.md + artifacts: '' + enableMicrobuild: false + enablePublishBuildArtifacts: false + enablePublishBuildAssets: false + enablePublishTestResults: false + enablePublishUsingPipelines: false + disableComponentGovernance: false + componentGovernanceIgnoreDirectories: '' + mergeTestResults: false + testRunTitle: '' + testResultsFormat: '' + name: '' + preSteps: [] + runAsPublic: false +# Sbom related params + enableSbom: true + PackageVersion: 7.0.0 + BuildDropPath: '$(Build.SourcesDirectory)/artifacts' + +jobs: +- job: ${{ parameters.name }} + + ${{ if ne(parameters.cancelTimeoutInMinutes, '') }}: + cancelTimeoutInMinutes: ${{ parameters.cancelTimeoutInMinutes }} + + ${{ if ne(parameters.condition, '') }}: + condition: ${{ parameters.condition }} + + ${{ if ne(parameters.container, '') }}: + container: ${{ parameters.container }} + + ${{ if ne(parameters.continueOnError, '') }}: + continueOnError: ${{ parameters.continueOnError }} + + ${{ if ne(parameters.dependsOn, '') }}: + dependsOn: ${{ parameters.dependsOn }} + + ${{ if ne(parameters.displayName, '') }}: + displayName: ${{ parameters.displayName }} + + ${{ if ne(parameters.pool, '') }}: + pool: ${{ parameters.pool }} + + ${{ if ne(parameters.strategy, '') }}: + strategy: ${{ parameters.strategy }} + + ${{ if ne(parameters.timeoutInMinutes, '') }}: + timeoutInMinutes: ${{ parameters.timeoutInMinutes }} + + variables: + - ${{ if ne(parameters.enableTelemetry, 'false') }}: + - name: DOTNET_CLI_TELEMETRY_PROFILE + value: '$(Build.Repository.Uri)' + - ${{ if eq(parameters.enableRichCodeNavigation, 'true') }}: + - name: EnableRichCodeNavigation + value: 'true' + - ${{ each variable in parameters.variables }}: + # handle name-value variable syntax + # example: + # - name: [key] + # value: [value] + - ${{ if ne(variable.name, '') }}: + - name: ${{ variable.name }} + value: ${{ variable.value }} + + # handle variable groups + - ${{ if ne(variable.group, '') }}: + - group: ${{ variable.group }} + + # handle key-value variable syntax. + # example: + # - [key]: [value] + - ${{ if and(eq(variable.name, ''), eq(variable.group, '')) }}: + - ${{ each pair in variable }}: + - name: ${{ pair.key }} + value: ${{ pair.value }} + + # DotNet-HelixApi-Access provides 'HelixApiAccessToken' for internal builds + - ${{ if and(eq(parameters.enableTelemetry, 'true'), eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: + - group: DotNet-HelixApi-Access + + ${{ if ne(parameters.workspace, '') }}: + workspace: ${{ parameters.workspace }} + + steps: + - ${{ if ne(parameters.preSteps, '') }}: + - ${{ each preStep in parameters.preSteps }}: + - ${{ preStep }} + + - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: + - ${{ if eq(parameters.enableMicrobuild, 'true') }}: + - task: MicroBuildSigningPlugin@3 + displayName: Install MicroBuild plugin + inputs: + signType: $(_SignType) + zipSources: false + feedSource: https://dnceng.pkgs.visualstudio.com/_packaging/MicroBuildToolset/nuget/v3/index.json + env: + TeamName: $(_TeamName) + continueOnError: ${{ parameters.continueOnError }} + condition: and(succeeded(), in(variables['_SignType'], 'real', 'test'), eq(variables['Agent.Os'], 'Windows_NT')) + + - ${{ if and(eq(parameters.runAsPublic, 'false'), eq(variables['System.TeamProject'], 'internal')) }}: + - task: NuGetAuthenticate@0 + + - ${{ if or(eq(parameters.artifacts.download, 'true'), ne(parameters.artifacts.download, '')) }}: + - task: DownloadPipelineArtifact@2 + inputs: + buildType: current + artifactName: ${{ coalesce(parameters.artifacts.download.name, 'Artifacts_$(Agent.OS)_$(_BuildConfig)') }} + targetPath: ${{ coalesce(parameters.artifacts.download.path, 'artifacts') }} + itemPattern: ${{ coalesce(parameters.artifacts.download.pattern, '**') }} + + - ${{ each step in parameters.steps }}: + - ${{ step }} + + - ${{ if eq(parameters.enableRichCodeNavigation, true) }}: + - task: RichCodeNavIndexer@0 + displayName: RichCodeNav Upload + inputs: + languages: ${{ coalesce(parameters.richCodeNavigationLanguage, 'csharp') }} + environment: ${{ coalesce(parameters.richCodeNavigationEnvironment, 'production') }} + richNavLogOutputDirectory: $(Build.SourcesDirectory)/artifacts/bin + uploadRichNavArtifacts: ${{ coalesce(parameters.richCodeNavigationUploadArtifacts, false) }} + continueOnError: true + + - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest'), ne(parameters.disableComponentGovernance, 'true')) }}: + - task: ComponentGovernanceComponentDetection@0 + continueOnError: true + inputs: + ignoreDirectories: ${{ parameters.componentGovernanceIgnoreDirectories }} + + - ${{ if eq(parameters.enableMicrobuild, 'true') }}: + - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: + - task: MicroBuildCleanup@1 + displayName: Execute Microbuild cleanup tasks + condition: and(always(), in(variables['_SignType'], 'real', 'test'), eq(variables['Agent.Os'], 'Windows_NT')) + continueOnError: ${{ parameters.continueOnError }} + env: + TeamName: $(_TeamName) + + - ${{ if ne(parameters.artifacts.publish, '') }}: + - ${{ if or(eq(parameters.artifacts.publish.artifacts, 'true'), ne(parameters.artifacts.publish.artifacts, '')) }}: + - task: CopyFiles@2 + displayName: Gather binaries for publish to artifacts + inputs: + SourceFolder: 'artifacts/bin' + Contents: '**' + TargetFolder: '$(Build.ArtifactStagingDirectory)/artifacts/bin' + - task: CopyFiles@2 + displayName: Gather packages for publish to artifacts + inputs: + SourceFolder: 'artifacts/packages' + Contents: '**' + TargetFolder: '$(Build.ArtifactStagingDirectory)/artifacts/packages' + - task: PublishBuildArtifacts@1 + displayName: Publish pipeline artifacts + inputs: + PathtoPublish: '$(Build.ArtifactStagingDirectory)/artifacts' + PublishLocation: Container + ArtifactName: ${{ coalesce(parameters.artifacts.publish.artifacts.name , 'Artifacts_$(Agent.Os)_$(_BuildConfig)') }} + continueOnError: true + condition: always() + - ${{ if or(eq(parameters.artifacts.publish.logs, 'true'), ne(parameters.artifacts.publish.logs, '')) }}: + - publish: artifacts/log + artifact: ${{ coalesce(parameters.artifacts.publish.logs.name, 'Logs_Build_$(Agent.Os)_$(_BuildConfig)') }} + displayName: Publish logs + continueOnError: true + condition: always() + + - ${{ if ne(parameters.enablePublishBuildArtifacts, 'false') }}: + - task: PublishBuildArtifacts@1 + displayName: Publish Logs + inputs: + PathtoPublish: '$(Build.SourcesDirectory)/artifacts/log/$(_BuildConfig)' + PublishLocation: Container + ArtifactName: ${{ coalesce(parameters.enablePublishBuildArtifacts.artifactName, '$(Agent.Os)_$(Agent.JobName)' ) }} + continueOnError: true + condition: always() + + - ${{ if or(and(eq(parameters.enablePublishTestResults, 'true'), eq(parameters.testResultsFormat, '')), eq(parameters.testResultsFormat, 'xunit')) }}: + - task: PublishTestResults@2 + displayName: Publish XUnit Test Results + inputs: + testResultsFormat: 'xUnit' + testResultsFiles: '*.xml' + searchFolder: '$(Build.SourcesDirectory)/artifacts/TestResults/$(_BuildConfig)' + testRunTitle: ${{ coalesce(parameters.testRunTitle, parameters.name, '$(System.JobName)') }}-xunit + mergeTestResults: ${{ parameters.mergeTestResults }} + continueOnError: true + condition: always() + - ${{ if or(and(eq(parameters.enablePublishTestResults, 'true'), eq(parameters.testResultsFormat, '')), eq(parameters.testResultsFormat, 'vstest')) }}: + - task: PublishTestResults@2 + displayName: Publish TRX Test Results + inputs: + testResultsFormat: 'VSTest' + testResultsFiles: '*.trx' + searchFolder: '$(Build.SourcesDirectory)/artifacts/TestResults/$(_BuildConfig)' + testRunTitle: ${{ coalesce(parameters.testRunTitle, parameters.name, '$(System.JobName)') }}-trx + mergeTestResults: ${{ parameters.mergeTestResults }} + continueOnError: true + condition: always() + + - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest'), eq(parameters.enableSbom, 'true')) }}: + - template: /eng/common/templates/steps/generate-sbom.yml + parameters: + PackageVersion: ${{ parameters.packageVersion}} + BuildDropPath: ${{ parameters.buildDropPath }} + IgnoreDirectories: ${{ parameters.componentGovernanceIgnoreDirectories }} + diff --git a/eng/common/templates/job/onelocbuild.yml b/eng/common/templates/job/onelocbuild.yml new file mode 100644 index 000000000..c2cabcf9e --- /dev/null +++ b/eng/common/templates/job/onelocbuild.yml @@ -0,0 +1,107 @@ +parameters: + # Optional: dependencies of the job + dependsOn: '' + + # Optional: A defined YAML pool - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#pool + pool: '' + + CeapexPat: $(dn-bot-ceapex-package-r) # PAT for the loc AzDO instance https://dev.azure.com/ceapex + GithubPat: $(BotAccount-dotnet-bot-repo-PAT) + + SourcesDirectory: $(Build.SourcesDirectory) + CreatePr: true + AutoCompletePr: false + ReusePr: true + UseLfLineEndings: true + UseCheckedInLocProjectJson: false + LanguageSet: VS_Main_Languages + LclSource: lclFilesInRepo + LclPackageId: '' + RepoType: gitHub + GitHubOrg: dotnet + MirrorRepo: '' + MirrorBranch: main + condition: '' + JobNameSuffix: '' + +jobs: +- job: OneLocBuild${{ parameters.JobNameSuffix }} + + dependsOn: ${{ parameters.dependsOn }} + + displayName: OneLocBuild${{ parameters.JobNameSuffix }} + + variables: + - group: OneLocBuildVariables # Contains the CeapexPat and GithubPat + - name: _GenerateLocProjectArguments + value: -SourcesDirectory ${{ parameters.SourcesDirectory }} + -LanguageSet "${{ parameters.LanguageSet }}" + -CreateNeutralXlfs + - ${{ if eq(parameters.UseCheckedInLocProjectJson, 'true') }}: + - name: _GenerateLocProjectArguments + value: ${{ variables._GenerateLocProjectArguments }} -UseCheckedInLocProjectJson + - template: /eng/common/templates/variables/pool-providers.yml + + ${{ if ne(parameters.pool, '') }}: + pool: ${{ parameters.pool }} + ${{ if eq(parameters.pool, '') }}: + pool: + # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) + ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: + name: VSEngSS-MicroBuild2022-1ES + demands: Cmd + # If it's not devdiv, it's dnceng + ${{ if ne(variables['System.TeamProject'], 'DevDiv') }}: + name: $(DncEngInternalBuildPool) + demands: ImageOverride -equals windows.vs2019.amd64 + + steps: + - task: Powershell@2 + inputs: + filePath: $(Build.SourcesDirectory)/eng/common/generate-locproject.ps1 + arguments: $(_GenerateLocProjectArguments) + displayName: Generate LocProject.json + condition: ${{ parameters.condition }} + + - task: OneLocBuild@2 + displayName: OneLocBuild + env: + SYSTEM_ACCESSTOKEN: $(System.AccessToken) + inputs: + locProj: eng/Localize/LocProject.json + outDir: $(Build.ArtifactStagingDirectory) + lclSource: ${{ parameters.LclSource }} + lclPackageId: ${{ parameters.LclPackageId }} + isCreatePrSelected: ${{ parameters.CreatePr }} + isAutoCompletePrSelected: ${{ parameters.AutoCompletePr }} + ${{ if eq(parameters.CreatePr, true) }}: + isUseLfLineEndingsSelected: ${{ parameters.UseLfLineEndings }} + ${{ if eq(parameters.RepoType, 'gitHub') }}: + isShouldReusePrSelected: ${{ parameters.ReusePr }} + packageSourceAuth: patAuth + patVariable: ${{ parameters.CeapexPat }} + ${{ if eq(parameters.RepoType, 'gitHub') }}: + repoType: ${{ parameters.RepoType }} + gitHubPatVariable: "${{ parameters.GithubPat }}" + ${{ if ne(parameters.MirrorRepo, '') }}: + isMirrorRepoSelected: true + gitHubOrganization: ${{ parameters.GitHubOrg }} + mirrorRepo: ${{ parameters.MirrorRepo }} + mirrorBranch: ${{ parameters.MirrorBranch }} + condition: ${{ parameters.condition }} + + - task: PublishBuildArtifacts@1 + displayName: Publish Localization Files + inputs: + PathtoPublish: '$(Build.ArtifactStagingDirectory)/loc' + PublishLocation: Container + ArtifactName: Loc + condition: ${{ parameters.condition }} + + - task: PublishBuildArtifacts@1 + displayName: Publish LocProject.json + inputs: + PathtoPublish: '$(Build.SourcesDirectory)/eng/Localize/' + PublishLocation: Container + ArtifactName: Loc + condition: ${{ parameters.condition }} \ No newline at end of file diff --git a/eng/common/templates/job/publish-build-assets.yml b/eng/common/templates/job/publish-build-assets.yml new file mode 100644 index 000000000..d7b634962 --- /dev/null +++ b/eng/common/templates/job/publish-build-assets.yml @@ -0,0 +1,150 @@ +parameters: + configuration: 'Debug' + + # Optional: condition for the job to run + condition: '' + + # Optional: 'true' if future jobs should run even if this job fails + continueOnError: false + + # Optional: dependencies of the job + dependsOn: '' + + # Optional: Include PublishBuildArtifacts task + enablePublishBuildArtifacts: false + + # Optional: A defined YAML pool - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#pool + pool: {} + + # Optional: should run as a public build even in the internal project + # if 'true', the build won't run any of the internal only steps, even if it is running in non-public projects. + runAsPublic: false + + # Optional: whether the build's artifacts will be published using release pipelines or direct feed publishing + publishUsingPipelines: false + + # Optional: whether the build's artifacts will be published using release pipelines or direct feed publishing + publishAssetsImmediately: false + + artifactsPublishingAdditionalParameters: '' + + signingValidationAdditionalParameters: '' + +jobs: +- job: Asset_Registry_Publish + + dependsOn: ${{ parameters.dependsOn }} + + ${{ if eq(parameters.publishAssetsImmediately, 'true') }}: + displayName: Publish Assets + ${{ else }}: + displayName: Publish to Build Asset Registry + + variables: + - template: /eng/common/templates/variables/pool-providers.yml + - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: + - group: Publish-Build-Assets + - group: AzureDevOps-Artifact-Feeds-Pats + - name: runCodesignValidationInjection + value: false + - ${{ if eq(parameters.publishAssetsImmediately, 'true') }}: + - template: /eng/common/templates/post-build/common-variables.yml + + pool: + # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) + ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: + name: VSEngSS-MicroBuild2022-1ES + demands: Cmd + # If it's not devdiv, it's dnceng + ${{ if ne(variables['System.TeamProject'], 'DevDiv') }}: + name: $(DncEngInternalBuildPool) + demands: ImageOverride -equals windows.vs2019.amd64 + + steps: + - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: + - task: DownloadBuildArtifacts@0 + displayName: Download artifact + inputs: + artifactName: AssetManifests + downloadPath: '$(Build.StagingDirectory)/Download' + checkDownloadedFiles: true + condition: ${{ parameters.condition }} + continueOnError: ${{ parameters.continueOnError }} + + - task: NuGetAuthenticate@0 + + - task: PowerShell@2 + displayName: Publish Build Assets + inputs: + filePath: eng\common\sdk-task.ps1 + arguments: -task PublishBuildAssets -restore -msbuildEngine dotnet + /p:ManifestsPath='$(Build.StagingDirectory)/Download/AssetManifests' + /p:BuildAssetRegistryToken=$(MaestroAccessToken) + /p:MaestroApiEndpoint=https://maestro-prod.westus2.cloudapp.azure.com + /p:PublishUsingPipelines=${{ parameters.publishUsingPipelines }} + /p:OfficialBuildId=$(Build.BuildNumber) + condition: ${{ parameters.condition }} + continueOnError: ${{ parameters.continueOnError }} + + - task: powershell@2 + displayName: Create ReleaseConfigs Artifact + inputs: + targetType: inline + script: | + Add-Content -Path "$(Build.StagingDirectory)/ReleaseConfigs.txt" -Value $(BARBuildId) + Add-Content -Path "$(Build.StagingDirectory)/ReleaseConfigs.txt" -Value "$(DefaultChannels)" + Add-Content -Path "$(Build.StagingDirectory)/ReleaseConfigs.txt" -Value $(IsStableBuild) + + - task: PublishBuildArtifacts@1 + displayName: Publish ReleaseConfigs Artifact + inputs: + PathtoPublish: '$(Build.StagingDirectory)/ReleaseConfigs.txt' + PublishLocation: Container + ArtifactName: ReleaseConfigs + + - task: powershell@2 + displayName: Check if SymbolPublishingExclusionsFile.txt exists + inputs: + targetType: inline + script: | + $symbolExclusionfile = "$(Build.SourcesDirectory)/eng/SymbolPublishingExclusionsFile.txt" + if(Test-Path -Path $symbolExclusionfile) + { + Write-Host "SymbolExclusionFile exists" + Write-Host "##vso[task.setvariable variable=SymbolExclusionFile]true" + } + else{ + Write-Host "Symbols Exclusion file does not exists" + Write-Host "##vso[task.setvariable variable=SymbolExclusionFile]false" + } + + - task: PublishBuildArtifacts@1 + displayName: Publish SymbolPublishingExclusionsFile Artifact + condition: eq(variables['SymbolExclusionFile'], 'true') + inputs: + PathtoPublish: '$(Build.SourcesDirectory)/eng/SymbolPublishingExclusionsFile.txt' + PublishLocation: Container + ArtifactName: ReleaseConfigs + + - ${{ if eq(parameters.publishAssetsImmediately, 'true') }}: + - template: /eng/common/templates/post-build/setup-maestro-vars.yml + parameters: + BARBuildId: ${{ parameters.BARBuildId }} + PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} + + - task: PowerShell@2 + displayName: Publish Using Darc + inputs: + filePath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1 + arguments: -BuildId $(BARBuildId) + -PublishingInfraVersion 3 + -AzdoToken '$(publishing-dnceng-devdiv-code-r-build-re)' + -MaestroToken '$(MaestroApiAccessToken)' + -WaitPublishingFinish true + -ArtifactsPublishingAdditionalParameters '${{ parameters.artifactsPublishingAdditionalParameters }}' + -SymbolPublishingAdditionalParameters '${{ parameters.symbolPublishingAdditionalParameters }}' + + - ${{ if eq(parameters.enablePublishBuildArtifacts, 'true') }}: + - template: /eng/common/templates/steps/publish-logs.yml + parameters: + JobLabel: 'Publish_Artifacts_Logs' diff --git a/eng/common/templates/job/source-build.yml b/eng/common/templates/job/source-build.yml new file mode 100644 index 000000000..e40bf3520 --- /dev/null +++ b/eng/common/templates/job/source-build.yml @@ -0,0 +1,74 @@ +parameters: + # This template adds arcade-powered source-build to CI. The template produces a server job with a + # default ID 'Source_Build_Complete' to put in a dependency list if necessary. + + # Specifies the prefix for source-build jobs added to pipeline. Use this if disambiguation needed. + jobNamePrefix: 'Source_Build' + + # Defines the platform on which to run the job. By default, a linux-x64 machine, suitable for + # managed-only repositories. This is an object with these properties: + # + # name: '' + # The name of the job. This is included in the job ID. + # targetRID: '' + # The name of the target RID to use, instead of the one auto-detected by Arcade. + # nonPortable: false + # Enables non-portable mode. This means a more specific RID (e.g. fedora.32-x64 rather than + # linux-x64), and compiling against distro-provided packages rather than portable ones. + # skipPublishValidation: false + # Disables publishing validation. By default, a check is performed to ensure no packages are + # published by source-build. + # container: '' + # A container to use. Runs in docker. + # pool: {} + # A pool to use. Runs directly on an agent. + # buildScript: '' + # Specifies the build script to invoke to perform the build in the repo. The default + # './build.sh' should work for typical Arcade repositories, but this is customizable for + # difficult situations. + # jobProperties: {} + # A list of job properties to inject at the top level, for potential extensibility beyond + # container and pool. + platform: {} + +jobs: +- job: ${{ parameters.jobNamePrefix }}_${{ parameters.platform.name }} + displayName: Source-Build (${{ parameters.platform.name }}) + + ${{ each property in parameters.platform.jobProperties }}: + ${{ property.key }}: ${{ property.value }} + + ${{ if ne(parameters.platform.container, '') }}: + container: ${{ parameters.platform.container }} + + ${{ if eq(parameters.platform.pool, '') }}: + # The default VM host AzDO pool. This should be capable of running Docker containers: almost all + # source-build builds run in Docker, including the default managed platform. + # /eng/common/templates/variables/pool-providers.yml can't be used here (some customers declare variables already), so duplicate its logic + pool: + # Main environments + ${{ if and(eq(variables['System.TeamProject'], 'public'), ne(contains(coalesce(variables['System.PullRequest.TargetBranch'], variables['Build.SourceBranch'], 'refs/heads/main'), 'release'), true)) }}: + name: NetCore-Public + demands: ImageOverride -equals Build.Ubuntu.1804.Amd64.Open + ${{ if and(eq(variables['System.TeamProject'], 'internal'), ne(contains(coalesce(variables['System.PullRequest.TargetBranch'], variables['Build.SourceBranch'], 'refs/heads/main'), 'release'), true)) }}: + name: NetCore1ESPool-Internal + demands: ImageOverride -equals Build.Ubuntu.1804.Amd64 + + # Servicing build environments + ${{ if and(eq(variables['System.TeamProject'], 'public'), contains(coalesce(variables['System.PullRequest.TargetBranch'], variables['Build.SourceBranch'], 'refs/heads/main'), 'release')) }}: + name: NetCore-Svc-Public + demands: ImageOverride -equals Build.Ubuntu.1804.Amd64.Open + ${{ if and(eq(variables['System.TeamProject'], 'internal'), contains(coalesce(variables['System.PullRequest.TargetBranch'], variables['Build.SourceBranch'], 'refs/heads/main'), 'release')) }}: + name: NetCore1ESPool-Svc-Internal + demands: ImageOverride -equals Build.Ubuntu.1804.Amd64 + + ${{ if ne(parameters.platform.pool, '') }}: + pool: ${{ parameters.platform.pool }} + + workspace: + clean: all + + steps: + - template: /eng/common/templates/steps/source-build.yml + parameters: + platform: ${{ parameters.platform }} diff --git a/eng/common/templates/job/source-index-stage1.yml b/eng/common/templates/job/source-index-stage1.yml new file mode 100644 index 000000000..09c506d11 --- /dev/null +++ b/eng/common/templates/job/source-index-stage1.yml @@ -0,0 +1,67 @@ +parameters: + runAsPublic: false + sourceIndexPackageVersion: 1.0.1-20220804.1 + sourceIndexPackageSource: https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json + sourceIndexBuildCommand: powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -Command "eng/common/build.ps1 -restore -build -binarylog -ci" + preSteps: [] + binlogPath: artifacts/log/Debug/Build.binlog + condition: '' + dependsOn: '' + pool: '' + +jobs: +- job: SourceIndexStage1 + dependsOn: ${{ parameters.dependsOn }} + condition: ${{ parameters.condition }} + variables: + - name: SourceIndexPackageVersion + value: ${{ parameters.sourceIndexPackageVersion }} + - name: SourceIndexPackageSource + value: ${{ parameters.sourceIndexPackageSource }} + - name: BinlogPath + value: ${{ parameters.binlogPath }} + - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: + - group: source-dot-net stage1 variables + - template: /eng/common/templates/variables/pool-providers.yml + + ${{ if ne(parameters.pool, '') }}: + pool: ${{ parameters.pool }} + ${{ if eq(parameters.pool, '') }}: + pool: + ${{ if eq(variables['System.TeamProject'], 'public') }}: + name: $(DncEngPublicBuildPool) + demands: ImageOverride -equals windows.vs2019.amd64.open + ${{ if eq(variables['System.TeamProject'], 'internal') }}: + name: $(DncEngInternalBuildPool) + demands: ImageOverride -equals windows.vs2019.amd64 + + steps: + - ${{ each preStep in parameters.preSteps }}: + - ${{ preStep }} + + - task: UseDotNet@2 + displayName: Use .NET Core sdk 3.1 + inputs: + packageType: sdk + version: 3.1.x + installationPath: $(Agent.TempDirectory)/dotnet + workingDirectory: $(Agent.TempDirectory) + + - script: | + $(Agent.TempDirectory)/dotnet/dotnet tool install BinLogToSln --version $(SourceIndexPackageVersion) --add-source $(SourceIndexPackageSource) --tool-path $(Agent.TempDirectory)/.source-index/tools + $(Agent.TempDirectory)/dotnet/dotnet tool install UploadIndexStage1 --version $(SourceIndexPackageVersion) --add-source $(SourceIndexPackageSource) --tool-path $(Agent.TempDirectory)/.source-index/tools + displayName: Download Tools + # Set working directory to temp directory so 'dotnet' doesn't try to use global.json and use the repo's sdk. + workingDirectory: $(Agent.TempDirectory) + + - script: ${{ parameters.sourceIndexBuildCommand }} + displayName: Build Repository + + - script: $(Agent.TempDirectory)/.source-index/tools/BinLogToSln -i $(BinlogPath) -r $(Build.SourcesDirectory) -n $(Build.Repository.Name) -o .source-index/stage1output + displayName: Process Binlog into indexable sln + + - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: + - script: $(Agent.TempDirectory)/.source-index/tools/UploadIndexStage1 -i .source-index/stage1output -n $(Build.Repository.Name) + displayName: Upload stage1 artifacts to source index + env: + BLOB_CONTAINER_URL: $(source-dot-net-stage1-blob-container-url) diff --git a/eng/common/templates/jobs/codeql-build.yml b/eng/common/templates/jobs/codeql-build.yml new file mode 100644 index 000000000..f7dc5ea4a --- /dev/null +++ b/eng/common/templates/jobs/codeql-build.yml @@ -0,0 +1,31 @@ +parameters: + # See schema documentation in /Documentation/AzureDevOps/TemplateSchema.md + continueOnError: false + # Required: A collection of jobs to run - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#job + jobs: [] + # Optional: if specified, restore and use this version of Guardian instead of the default. + overrideGuardianVersion: '' + +jobs: +- template: /eng/common/templates/jobs/jobs.yml + parameters: + enableMicrobuild: false + enablePublishBuildArtifacts: false + enablePublishTestResults: false + enablePublishBuildAssets: false + enablePublishUsingPipelines: false + enableTelemetry: true + + variables: + - group: Publish-Build-Assets + # The Guardian version specified in 'eng/common/sdl/packages.config'. This value must be kept in + # sync with the packages.config file. + - name: DefaultGuardianVersion + value: 0.109.0 + - name: GuardianPackagesConfigFile + value: $(Build.SourcesDirectory)\eng\common\sdl\packages.config + - name: GuardianVersion + value: ${{ coalesce(parameters.overrideGuardianVersion, '$(DefaultGuardianVersion)') }} + + jobs: ${{ parameters.jobs }} + diff --git a/eng/common/templates/jobs/jobs.yml b/eng/common/templates/jobs/jobs.yml new file mode 100644 index 000000000..289bb2396 --- /dev/null +++ b/eng/common/templates/jobs/jobs.yml @@ -0,0 +1,97 @@ +parameters: + # See schema documentation in /Documentation/AzureDevOps/TemplateSchema.md + continueOnError: false + + # Optional: Include PublishBuildArtifacts task + enablePublishBuildArtifacts: false + + # Optional: Enable publishing using release pipelines + enablePublishUsingPipelines: false + + # Optional: Enable running the source-build jobs to build repo from source + enableSourceBuild: false + + # Optional: Parameters for source-build template. + # See /eng/common/templates/jobs/source-build.yml for options + sourceBuildParameters: [] + + graphFileGeneration: + # Optional: Enable generating the graph files at the end of the build + enabled: false + # Optional: Include toolset dependencies in the generated graph files + includeToolset: false + + # Required: A collection of jobs to run - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#job + jobs: [] + + # Optional: Override automatically derived dependsOn value for "publish build assets" job + publishBuildAssetsDependsOn: '' + + # Optional: Publish the assets as soon as the publish to BAR stage is complete, rather doing so in a separate stage. + publishAssetsImmediately: false + + # Optional: If using publishAssetsImmediately and additional parameters are needed, can be used to send along additional parameters (normally sent to post-build.yml) + artifactsPublishingAdditionalParameters: '' + signingValidationAdditionalParameters: '' + + # Optional: should run as a public build even in the internal project + # if 'true', the build won't run any of the internal only steps, even if it is running in non-public projects. + runAsPublic: false + + enableSourceIndex: false + sourceIndexParams: {} + +# Internal resources (telemetry, microbuild) can only be accessed from non-public projects, +# and some (Microbuild) should only be applied to non-PR cases for internal builds. + +jobs: +- ${{ each job in parameters.jobs }}: + - template: ../job/job.yml + parameters: + # pass along parameters + ${{ each parameter in parameters }}: + ${{ if ne(parameter.key, 'jobs') }}: + ${{ parameter.key }}: ${{ parameter.value }} + + # pass along job properties + ${{ each property in job }}: + ${{ if ne(property.key, 'job') }}: + ${{ property.key }}: ${{ property.value }} + + name: ${{ job.job }} + +- ${{ if eq(parameters.enableSourceBuild, true) }}: + - template: /eng/common/templates/jobs/source-build.yml + parameters: + allCompletedJobId: Source_Build_Complete + ${{ each parameter in parameters.sourceBuildParameters }}: + ${{ parameter.key }}: ${{ parameter.value }} + +- ${{ if eq(parameters.enableSourceIndex, 'true') }}: + - template: ../job/source-index-stage1.yml + parameters: + runAsPublic: ${{ parameters.runAsPublic }} + ${{ each parameter in parameters.sourceIndexParams }}: + ${{ parameter.key }}: ${{ parameter.value }} + +- ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: + - ${{ if or(eq(parameters.enablePublishBuildAssets, true), eq(parameters.artifacts.publish.manifests, 'true'), ne(parameters.artifacts.publish.manifests, '')) }}: + - template: ../job/publish-build-assets.yml + parameters: + continueOnError: ${{ parameters.continueOnError }} + dependsOn: + - ${{ if ne(parameters.publishBuildAssetsDependsOn, '') }}: + - ${{ each job in parameters.publishBuildAssetsDependsOn }}: + - ${{ job.job }} + - ${{ if eq(parameters.publishBuildAssetsDependsOn, '') }}: + - ${{ each job in parameters.jobs }}: + - ${{ job.job }} + - ${{ if eq(parameters.enableSourceBuild, true) }}: + - Source_Build_Complete + + runAsPublic: ${{ parameters.runAsPublic }} + publishUsingPipelines: ${{ parameters.enablePublishUsingPipelines }} + publishAssetsImmediately: ${{ parameters.publishAssetsImmediately }} + enablePublishBuildArtifacts: ${{ parameters.enablePublishBuildArtifacts }} + artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} + signingValidationAdditionalParameters: ${{ parameters.signingValidationAdditionalParameters }} diff --git a/eng/common/templates/jobs/source-build.yml b/eng/common/templates/jobs/source-build.yml new file mode 100644 index 000000000..a15b07eb5 --- /dev/null +++ b/eng/common/templates/jobs/source-build.yml @@ -0,0 +1,46 @@ +parameters: + # This template adds arcade-powered source-build to CI. A job is created for each platform, as + # well as an optional server job that completes when all platform jobs complete. + + # The name of the "join" job for all source-build platforms. If set to empty string, the job is + # not included. Existing repo pipelines can use this job depend on all source-build jobs + # completing without maintaining a separate list of every single job ID: just depend on this one + # server job. By default, not included. Recommended name if used: 'Source_Build_Complete'. + allCompletedJobId: '' + + # See /eng/common/templates/job/source-build.yml + jobNamePrefix: 'Source_Build' + + # This is the default platform provided by Arcade, intended for use by a managed-only repo. + defaultManagedPlatform: + name: 'Managed' + container: 'mcr.microsoft.com/dotnet-buildtools/prereqs:centos-stream8' + + # Defines the platforms on which to run build jobs. One job is created for each platform, and the + # object in this array is sent to the job template as 'platform'. If no platforms are specified, + # one job runs on 'defaultManagedPlatform'. + platforms: [] + +jobs: + +- ${{ if ne(parameters.allCompletedJobId, '') }}: + - job: ${{ parameters.allCompletedJobId }} + displayName: Source-Build Complete + pool: server + dependsOn: + - ${{ each platform in parameters.platforms }}: + - ${{ parameters.jobNamePrefix }}_${{ platform.name }} + - ${{ if eq(length(parameters.platforms), 0) }}: + - ${{ parameters.jobNamePrefix }}_${{ parameters.defaultManagedPlatform.name }} + +- ${{ each platform in parameters.platforms }}: + - template: /eng/common/templates/job/source-build.yml + parameters: + jobNamePrefix: ${{ parameters.jobNamePrefix }} + platform: ${{ platform }} + +- ${{ if eq(length(parameters.platforms), 0) }}: + - template: /eng/common/templates/job/source-build.yml + parameters: + jobNamePrefix: ${{ parameters.jobNamePrefix }} + platform: ${{ parameters.defaultManagedPlatform }} diff --git a/eng/common/templates/post-build/common-variables.yml b/eng/common/templates/post-build/common-variables.yml new file mode 100644 index 000000000..c24193acf --- /dev/null +++ b/eng/common/templates/post-build/common-variables.yml @@ -0,0 +1,22 @@ +variables: + - group: Publish-Build-Assets + + # Whether the build is internal or not + - name: IsInternalBuild + value: ${{ and(ne(variables['System.TeamProject'], 'public'), contains(variables['Build.SourceBranch'], 'internal')) }} + + # Default Maestro++ API Endpoint and API Version + - name: MaestroApiEndPoint + value: "https://maestro-prod.westus2.cloudapp.azure.com" + - name: MaestroApiAccessToken + value: $(MaestroAccessToken) + - name: MaestroApiVersion + value: "2020-02-20" + + - name: SourceLinkCLIVersion + value: 3.0.0 + - name: SymbolToolVersion + value: 1.0.1 + + - name: runCodesignValidationInjection + value: false diff --git a/eng/common/templates/post-build/post-build.yml b/eng/common/templates/post-build/post-build.yml new file mode 100644 index 000000000..ef720f9d7 --- /dev/null +++ b/eng/common/templates/post-build/post-build.yml @@ -0,0 +1,281 @@ +parameters: + # Which publishing infra should be used. THIS SHOULD MATCH THE VERSION ON THE BUILD MANIFEST. + # Publishing V1 is no longer supported + # Publishing V2 is no longer supported + # Publishing V3 is the default + - name: publishingInfraVersion + displayName: Which version of publishing should be used to promote the build definition? + type: number + default: 3 + values: + - 3 + + - name: BARBuildId + displayName: BAR Build Id + type: number + default: 0 + + - name: PromoteToChannelIds + displayName: Channel to promote BARBuildId to + type: string + default: '' + + - name: enableSourceLinkValidation + displayName: Enable SourceLink validation + type: boolean + default: false + + - name: enableSigningValidation + displayName: Enable signing validation + type: boolean + default: true + + - name: enableSymbolValidation + displayName: Enable symbol validation + type: boolean + default: false + + - name: enableNugetValidation + displayName: Enable NuGet validation + type: boolean + default: true + + - name: publishInstallersAndChecksums + displayName: Publish installers and checksums + type: boolean + default: true + + - name: SDLValidationParameters + type: object + default: + enable: false + publishGdn: false + continueOnError: false + params: '' + artifactNames: '' + downloadArtifacts: true + + # These parameters let the user customize the call to sdk-task.ps1 for publishing + # symbols & general artifacts as well as for signing validation + - name: symbolPublishingAdditionalParameters + displayName: Symbol publishing additional parameters + type: string + default: '' + + - name: artifactsPublishingAdditionalParameters + displayName: Artifact publishing additional parameters + type: string + default: '' + + - name: signingValidationAdditionalParameters + displayName: Signing validation additional parameters + type: string + default: '' + + # Which stages should finish execution before post-build stages start + - name: validateDependsOn + type: object + default: + - build + + - name: publishDependsOn + type: object + default: + - Validate + + # Optional: Call asset publishing rather than running in a separate stage + - name: publishAssetsImmediately + type: boolean + default: false + +stages: +- ${{ if or(eq( parameters.enableNugetValidation, 'true'), eq(parameters.enableSigningValidation, 'true'), eq(parameters.enableSourceLinkValidation, 'true'), eq(parameters.SDLValidationParameters.enable, 'true')) }}: + - stage: Validate + dependsOn: ${{ parameters.validateDependsOn }} + displayName: Validate Build Assets + variables: + - template: common-variables.yml + - template: /eng/common/templates/variables/pool-providers.yml + jobs: + - job: + displayName: NuGet Validation + condition: and(succeededOrFailed(), eq( ${{ parameters.enableNugetValidation }}, 'true')) + pool: + # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) + ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: + name: VSEngSS-MicroBuild2022-1ES + demands: Cmd + # If it's not devdiv, it's dnceng + ${{ else }}: + name: $(DncEngInternalBuildPool) + demands: ImageOverride -equals windows.vs2019.amd64 + + steps: + - template: setup-maestro-vars.yml + parameters: + BARBuildId: ${{ parameters.BARBuildId }} + PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} + + - task: DownloadBuildArtifacts@0 + displayName: Download Package Artifacts + inputs: + buildType: specific + buildVersionToDownload: specific + project: $(AzDOProjectName) + pipeline: $(AzDOPipelineId) + buildId: $(AzDOBuildId) + artifactName: PackageArtifacts + checkDownloadedFiles: true + + - task: PowerShell@2 + displayName: Validate + inputs: + filePath: $(Build.SourcesDirectory)/eng/common/post-build/nuget-validation.ps1 + arguments: -PackagesPath $(Build.ArtifactStagingDirectory)/PackageArtifacts/ + -ToolDestinationPath $(Agent.BuildDirectory)/Extract/ + + - job: + displayName: Signing Validation + condition: and( eq( ${{ parameters.enableSigningValidation }}, 'true'), ne( variables['PostBuildSign'], 'true')) + pool: + # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) + ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: + name: VSEngSS-MicroBuild2022-1ES + demands: Cmd + # If it's not devdiv, it's dnceng + ${{ else }}: + name: $(DncEngInternalBuildPool) + demands: ImageOverride -equals windows.vs2019.amd64 + steps: + - template: setup-maestro-vars.yml + parameters: + BARBuildId: ${{ parameters.BARBuildId }} + PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} + + - task: DownloadBuildArtifacts@0 + displayName: Download Package Artifacts + inputs: + buildType: specific + buildVersionToDownload: specific + project: $(AzDOProjectName) + pipeline: $(AzDOPipelineId) + buildId: $(AzDOBuildId) + artifactName: PackageArtifacts + checkDownloadedFiles: true + itemPattern: | + ** + !**/Microsoft.SourceBuild.Intermediate.*.nupkg + + # This is necessary whenever we want to publish/restore to an AzDO private feed + # Since sdk-task.ps1 tries to restore packages we need to do this authentication here + # otherwise it'll complain about accessing a private feed. + - task: NuGetAuthenticate@0 + displayName: 'Authenticate to AzDO Feeds' + + # Signing validation will optionally work with the buildmanifest file which is downloaded from + # Azure DevOps above. + - task: PowerShell@2 + displayName: Validate + inputs: + filePath: eng\common\sdk-task.ps1 + arguments: -task SigningValidation -restore -msbuildEngine vs + /p:PackageBasePath='$(Build.ArtifactStagingDirectory)/PackageArtifacts' + /p:SignCheckExclusionsFile='$(Build.SourcesDirectory)/eng/SignCheckExclusionsFile.txt' + ${{ parameters.signingValidationAdditionalParameters }} + + - template: ../steps/publish-logs.yml + parameters: + StageLabel: 'Validation' + JobLabel: 'Signing' + + - job: + displayName: SourceLink Validation + condition: eq( ${{ parameters.enableSourceLinkValidation }}, 'true') + pool: + # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) + ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: + name: VSEngSS-MicroBuild2022-1ES + demands: Cmd + # If it's not devdiv, it's dnceng + ${{ else }}: + name: $(DncEngInternalBuildPool) + demands: ImageOverride -equals windows.vs2019.amd64 + steps: + - template: setup-maestro-vars.yml + parameters: + BARBuildId: ${{ parameters.BARBuildId }} + PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} + + - task: DownloadBuildArtifacts@0 + displayName: Download Blob Artifacts + inputs: + buildType: specific + buildVersionToDownload: specific + project: $(AzDOProjectName) + pipeline: $(AzDOPipelineId) + buildId: $(AzDOBuildId) + artifactName: BlobArtifacts + checkDownloadedFiles: true + + - task: PowerShell@2 + displayName: Validate + inputs: + filePath: $(Build.SourcesDirectory)/eng/common/post-build/sourcelink-validation.ps1 + arguments: -InputPath $(Build.ArtifactStagingDirectory)/BlobArtifacts/ + -ExtractPath $(Agent.BuildDirectory)/Extract/ + -GHRepoName $(Build.Repository.Name) + -GHCommit $(Build.SourceVersion) + -SourcelinkCliVersion $(SourceLinkCLIVersion) + continueOnError: true + + - template: /eng/common/templates/job/execute-sdl.yml + parameters: + enable: ${{ parameters.SDLValidationParameters.enable }} + publishGuardianDirectoryToPipeline: ${{ parameters.SDLValidationParameters.publishGdn }} + additionalParameters: ${{ parameters.SDLValidationParameters.params }} + continueOnError: ${{ parameters.SDLValidationParameters.continueOnError }} + artifactNames: ${{ parameters.SDLValidationParameters.artifactNames }} + downloadArtifacts: ${{ parameters.SDLValidationParameters.downloadArtifacts }} + +- ${{ if ne(parameters.publishAssetsImmediately, 'true') }}: + - stage: publish_using_darc + ${{ if or(eq(parameters.enableNugetValidation, 'true'), eq(parameters.enableSigningValidation, 'true'), eq(parameters.enableSourceLinkValidation, 'true'), eq(parameters.SDLValidationParameters.enable, 'true')) }}: + dependsOn: ${{ parameters.publishDependsOn }} + ${{ else }}: + dependsOn: ${{ parameters.validateDependsOn }} + displayName: Publish using Darc + variables: + - template: common-variables.yml + - template: /eng/common/templates/variables/pool-providers.yml + jobs: + - job: + displayName: Publish Using Darc + timeoutInMinutes: 120 + pool: + # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) + ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: + name: VSEngSS-MicroBuild2022-1ES + demands: Cmd + # If it's not devdiv, it's dnceng + ${{ else }}: + name: $(DncEngInternalBuildPool) + demands: ImageOverride -equals windows.vs2019.amd64 + steps: + - template: setup-maestro-vars.yml + parameters: + BARBuildId: ${{ parameters.BARBuildId }} + PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} + + - task: NuGetAuthenticate@0 + + - task: PowerShell@2 + displayName: Publish Using Darc + inputs: + filePath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1 + arguments: -BuildId $(BARBuildId) + -PublishingInfraVersion ${{ parameters.publishingInfraVersion }} + -AzdoToken '$(publishing-dnceng-devdiv-code-r-build-re)' + -MaestroToken '$(MaestroApiAccessToken)' + -WaitPublishingFinish true + -ArtifactsPublishingAdditionalParameters '${{ parameters.artifactsPublishingAdditionalParameters }}' + -SymbolPublishingAdditionalParameters '${{ parameters.symbolPublishingAdditionalParameters }}' diff --git a/eng/common/templates/post-build/setup-maestro-vars.yml b/eng/common/templates/post-build/setup-maestro-vars.yml new file mode 100644 index 000000000..0c87f149a --- /dev/null +++ b/eng/common/templates/post-build/setup-maestro-vars.yml @@ -0,0 +1,70 @@ +parameters: + BARBuildId: '' + PromoteToChannelIds: '' + +steps: + - ${{ if eq(coalesce(parameters.PromoteToChannelIds, 0), 0) }}: + - task: DownloadBuildArtifacts@0 + displayName: Download Release Configs + inputs: + buildType: current + artifactName: ReleaseConfigs + checkDownloadedFiles: true + + - task: PowerShell@2 + name: setReleaseVars + displayName: Set Release Configs Vars + inputs: + targetType: inline + pwsh: true + script: | + try { + if (!$Env:PromoteToMaestroChannels -or $Env:PromoteToMaestroChannels.Trim() -eq '') { + $Content = Get-Content $(Build.StagingDirectory)/ReleaseConfigs/ReleaseConfigs.txt + + $BarId = $Content | Select -Index 0 + $Channels = $Content | Select -Index 1 + $IsStableBuild = $Content | Select -Index 2 + + $AzureDevOpsProject = $Env:System_TeamProject + $AzureDevOpsBuildDefinitionId = $Env:System_DefinitionId + $AzureDevOpsBuildId = $Env:Build_BuildId + } + else { + $buildApiEndpoint = "${Env:MaestroApiEndPoint}/api/builds/${Env:BARBuildId}?api-version=${Env:MaestroApiVersion}" + + $apiHeaders = New-Object 'System.Collections.Generic.Dictionary[[String],[String]]' + $apiHeaders.Add('Accept', 'application/json') + $apiHeaders.Add('Authorization',"Bearer ${Env:MAESTRO_API_TOKEN}") + + $buildInfo = try { Invoke-WebRequest -Method Get -Uri $buildApiEndpoint -Headers $apiHeaders | ConvertFrom-Json } catch { Write-Host "Error: $_" } + + $BarId = $Env:BARBuildId + $Channels = $Env:PromoteToMaestroChannels -split "," + $Channels = $Channels -join "][" + $Channels = "[$Channels]" + + $IsStableBuild = $buildInfo.stable + $AzureDevOpsProject = $buildInfo.azureDevOpsProject + $AzureDevOpsBuildDefinitionId = $buildInfo.azureDevOpsBuildDefinitionId + $AzureDevOpsBuildId = $buildInfo.azureDevOpsBuildId + } + + Write-Host "##vso[task.setvariable variable=BARBuildId]$BarId" + Write-Host "##vso[task.setvariable variable=TargetChannels]$Channels" + Write-Host "##vso[task.setvariable variable=IsStableBuild]$IsStableBuild" + + Write-Host "##vso[task.setvariable variable=AzDOProjectName]$AzureDevOpsProject" + Write-Host "##vso[task.setvariable variable=AzDOPipelineId]$AzureDevOpsBuildDefinitionId" + Write-Host "##vso[task.setvariable variable=AzDOBuildId]$AzureDevOpsBuildId" + } + catch { + Write-Host $_ + Write-Host $_.Exception + Write-Host $_.ScriptStackTrace + exit 1 + } + env: + MAESTRO_API_TOKEN: $(MaestroApiAccessToken) + BARBuildId: ${{ parameters.BARBuildId }} + PromoteToMaestroChannels: ${{ parameters.PromoteToChannelIds }} diff --git a/eng/common/templates/post-build/trigger-subscription.yml b/eng/common/templates/post-build/trigger-subscription.yml new file mode 100644 index 000000000..da669030d --- /dev/null +++ b/eng/common/templates/post-build/trigger-subscription.yml @@ -0,0 +1,13 @@ +parameters: + ChannelId: 0 + +steps: +- task: PowerShell@2 + displayName: Triggering subscriptions + inputs: + filePath: $(Build.SourcesDirectory)/eng/common/post-build/trigger-subscriptions.ps1 + arguments: -SourceRepo $(Build.Repository.Uri) + -ChannelId ${{ parameters.ChannelId }} + -MaestroApiAccessToken $(MaestroAccessToken) + -MaestroApiEndPoint $(MaestroApiEndPoint) + -MaestroApiVersion $(MaestroApiVersion) diff --git a/eng/common/templates/steps/add-build-to-channel.yml b/eng/common/templates/steps/add-build-to-channel.yml new file mode 100644 index 000000000..f67a210d6 --- /dev/null +++ b/eng/common/templates/steps/add-build-to-channel.yml @@ -0,0 +1,13 @@ +parameters: + ChannelId: 0 + +steps: +- task: PowerShell@2 + displayName: Add Build to Channel + inputs: + filePath: $(Build.SourcesDirectory)/eng/common/post-build/add-build-to-channel.ps1 + arguments: -BuildId $(BARBuildId) + -ChannelId ${{ parameters.ChannelId }} + -MaestroApiAccessToken $(MaestroApiAccessToken) + -MaestroApiEndPoint $(MaestroApiEndPoint) + -MaestroApiVersion $(MaestroApiVersion) diff --git a/eng/common/templates/steps/build-reason.yml b/eng/common/templates/steps/build-reason.yml new file mode 100644 index 000000000..eba58109b --- /dev/null +++ b/eng/common/templates/steps/build-reason.yml @@ -0,0 +1,12 @@ +# build-reason.yml +# Description: runs steps if build.reason condition is valid. conditions is a string of valid build reasons +# to include steps (',' separated). +parameters: + conditions: '' + steps: [] + +steps: + - ${{ if and( not(startsWith(parameters.conditions, 'not')), contains(parameters.conditions, variables['build.reason'])) }}: + - ${{ parameters.steps }} + - ${{ if and( startsWith(parameters.conditions, 'not'), not(contains(parameters.conditions, variables['build.reason']))) }}: + - ${{ parameters.steps }} diff --git a/eng/common/templates/steps/execute-codeql.yml b/eng/common/templates/steps/execute-codeql.yml new file mode 100644 index 000000000..3930b1630 --- /dev/null +++ b/eng/common/templates/steps/execute-codeql.yml @@ -0,0 +1,32 @@ +parameters: + # Language that should be analyzed. Defaults to csharp + language: csharp + # Build Commands + buildCommands: '' + overrideParameters: '' # Optional: to override values for parameters. + additionalParameters: '' # Optional: parameters that need user specific values eg: '-SourceToolsList @("abc","def") -ArtifactToolsList @("ghi","jkl")' + # Optional: if specified, restore and use this version of Guardian instead of the default. + overrideGuardianVersion: '' + # Optional: if true, publish the '.gdn' folder as a pipeline artifact. This can help with in-depth + # diagnosis of problems with specific tool configurations. + publishGuardianDirectoryToPipeline: false + # The script to run to execute all SDL tools. Use this if you want to use a script to define SDL + # parameters rather than relying on YAML. It may be better to use a local script, because you can + # reproduce results locally without piecing together a command based on the YAML. + executeAllSdlToolsScript: 'eng/common/sdl/execute-all-sdl-tools.ps1' + # There is some sort of bug (has been reported) in Azure DevOps where if this parameter is named + # 'continueOnError', the parameter value is not correctly picked up. + # This can also be remedied by the caller (post-build.yml) if it does not use a nested parameter + # optional: determines whether to continue the build if the step errors; + sdlContinueOnError: false + +steps: +- template: /eng/common/templates/steps/execute-sdl.yml + parameters: + overrideGuardianVersion: ${{ parameters.overrideGuardianVersion }} + executeAllSdlToolsScript: ${{ parameters.executeAllSdlToolsScript }} + overrideParameters: ${{ parameters.overrideParameters }} + additionalParameters: '${{ parameters.additionalParameters }} + -CodeQLAdditionalRunConfigParams @("BuildCommands < ${{ parameters.buildCommands }}", "Language < ${{ parameters.language }}")' + publishGuardianDirectoryToPipeline: ${{ parameters.publishGuardianDirectoryToPipeline }} + sdlContinueOnError: ${{ parameters.sdlContinueOnError }} \ No newline at end of file diff --git a/eng/common/templates/steps/execute-sdl.yml b/eng/common/templates/steps/execute-sdl.yml new file mode 100644 index 000000000..9dd5709f6 --- /dev/null +++ b/eng/common/templates/steps/execute-sdl.yml @@ -0,0 +1,88 @@ +parameters: + overrideGuardianVersion: '' + executeAllSdlToolsScript: '' + overrideParameters: '' + additionalParameters: '' + publishGuardianDirectoryToPipeline: false + sdlContinueOnError: false + condition: '' + +steps: +- task: NuGetAuthenticate@1 + inputs: + nuGetServiceConnections: GuardianConnect + +- task: NuGetToolInstaller@1 + displayName: 'Install NuGet.exe' + +- ${{ if ne(parameters.overrideGuardianVersion, '') }}: + - pwsh: | + Set-Location -Path $(Build.SourcesDirectory)\eng\common\sdl + . .\sdl.ps1 + $guardianCliLocation = Install-Gdn -Path $(Build.SourcesDirectory)\.artifacts -Version ${{ parameters.overrideGuardianVersion }} + Write-Host "##vso[task.setvariable variable=GuardianCliLocation]$guardianCliLocation" + displayName: Install Guardian (Overridden) + +- ${{ if eq(parameters.overrideGuardianVersion, '') }}: + - pwsh: | + Set-Location -Path $(Build.SourcesDirectory)\eng\common\sdl + . .\sdl.ps1 + $guardianCliLocation = Install-Gdn -Path $(Build.SourcesDirectory)\.artifacts + Write-Host "##vso[task.setvariable variable=GuardianCliLocation]$guardianCliLocation" + displayName: Install Guardian + +- ${{ if ne(parameters.overrideParameters, '') }}: + - powershell: ${{ parameters.executeAllSdlToolsScript }} ${{ parameters.overrideParameters }} + displayName: Execute SDL + continueOnError: ${{ parameters.sdlContinueOnError }} + condition: ${{ parameters.condition }} + +- ${{ if eq(parameters.overrideParameters, '') }}: + - powershell: ${{ parameters.executeAllSdlToolsScript }} + -GuardianCliLocation $(GuardianCliLocation) + -NugetPackageDirectory $(Build.SourcesDirectory)\.packages + -AzureDevOpsAccessToken $(dn-bot-dotnet-build-rw-code-rw) + ${{ parameters.additionalParameters }} + displayName: Execute SDL + continueOnError: ${{ parameters.sdlContinueOnError }} + condition: ${{ parameters.condition }} + +- ${{ if ne(parameters.publishGuardianDirectoryToPipeline, 'false') }}: + # We want to publish the Guardian results and configuration for easy diagnosis. However, the + # '.gdn' dir is a mix of configuration, results, extracted dependencies, and Guardian default + # tooling files. Some of these files are large and aren't useful during an investigation, so + # exclude them by simply deleting them before publishing. (As of writing, there is no documented + # way to selectively exclude a dir from the pipeline artifact publish task.) + - task: DeleteFiles@1 + displayName: Delete Guardian dependencies to avoid uploading + inputs: + SourceFolder: $(Agent.BuildDirectory)/.gdn + Contents: | + c + i + condition: succeededOrFailed() + + - publish: $(Agent.BuildDirectory)/.gdn + artifact: GuardianConfiguration + displayName: Publish GuardianConfiguration + condition: succeededOrFailed() + + # Publish the SARIF files in a container named CodeAnalysisLogs to enable integration + # with the "SARIF SAST Scans Tab" Azure DevOps extension + - task: CopyFiles@2 + displayName: Copy SARIF files + inputs: + flattenFolders: true + sourceFolder: $(Agent.BuildDirectory)/.gdn/rc/ + contents: '**/*.sarif' + targetFolder: $(Build.SourcesDirectory)/CodeAnalysisLogs + condition: succeededOrFailed() + + # Use PublishBuildArtifacts because the SARIF extension only checks this case + # see microsoft/sarif-azuredevops-extension#4 + - task: PublishBuildArtifacts@1 + displayName: Publish SARIF files to CodeAnalysisLogs container + inputs: + pathToPublish: $(Build.SourcesDirectory)/CodeAnalysisLogs + artifactName: CodeAnalysisLogs + condition: succeededOrFailed() \ No newline at end of file diff --git a/eng/common/templates/steps/generate-sbom.yml b/eng/common/templates/steps/generate-sbom.yml new file mode 100644 index 000000000..a06373f38 --- /dev/null +++ b/eng/common/templates/steps/generate-sbom.yml @@ -0,0 +1,48 @@ +# BuildDropPath - The root folder of the drop directory for which the manifest file will be generated. +# PackageName - The name of the package this SBOM represents. +# PackageVersion - The version of the package this SBOM represents. +# ManifestDirPath - The path of the directory where the generated manifest files will be placed +# IgnoreDirectories - Directories to ignore for SBOM generation. This will be passed through to the CG component detector. + +parameters: + PackageVersion: 7.0.0 + BuildDropPath: '$(Build.SourcesDirectory)/artifacts' + PackageName: '.NET' + ManifestDirPath: $(Build.ArtifactStagingDirectory)/sbom + IgnoreDirectories: '' + sbomContinueOnError: true + +steps: +- task: PowerShell@2 + displayName: Prep for SBOM generation in (Non-linux) + condition: or(eq(variables['Agent.Os'], 'Windows_NT'), eq(variables['Agent.Os'], 'Darwin')) + inputs: + filePath: ./eng/common/generate-sbom-prep.ps1 + arguments: ${{parameters.manifestDirPath}} + +# Chmodding is a workaround for https://github.com/dotnet/arcade/issues/8461 +- script: | + chmod +x ./eng/common/generate-sbom-prep.sh + ./eng/common/generate-sbom-prep.sh ${{parameters.manifestDirPath}} + displayName: Prep for SBOM generation in (Linux) + condition: eq(variables['Agent.Os'], 'Linux') + continueOnError: ${{ parameters.sbomContinueOnError }} + +- task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0 + displayName: 'Generate SBOM manifest' + continueOnError: ${{ parameters.sbomContinueOnError }} + inputs: + PackageName: ${{ parameters.packageName }} + BuildDropPath: ${{ parameters.buildDropPath }} + PackageVersion: ${{ parameters.packageVersion }} + ManifestDirPath: ${{ parameters.manifestDirPath }} + ${{ if ne(parameters.IgnoreDirectories, '') }}: + AdditionalComponentDetectorArgs: '--IgnoreDirectories ${{ parameters.IgnoreDirectories }}' + +- task: PublishPipelineArtifact@1 + displayName: Publish SBOM manifest + continueOnError: ${{parameters.sbomContinueOnError}} + inputs: + targetPath: '${{parameters.manifestDirPath}}' + artifactName: $(ARTIFACT_NAME) + diff --git a/eng/common/templates/steps/publish-logs.yml b/eng/common/templates/steps/publish-logs.yml new file mode 100644 index 000000000..88f238f36 --- /dev/null +++ b/eng/common/templates/steps/publish-logs.yml @@ -0,0 +1,23 @@ +parameters: + StageLabel: '' + JobLabel: '' + +steps: +- task: Powershell@2 + displayName: Prepare Binlogs to Upload + inputs: + targetType: inline + script: | + New-Item -ItemType Directory $(Build.SourcesDirectory)/PostBuildLogs/${{parameters.StageLabel}}/${{parameters.JobLabel}}/ + Move-Item -Path $(Build.SourcesDirectory)/artifacts/log/Debug/* $(Build.SourcesDirectory)/PostBuildLogs/${{parameters.StageLabel}}/${{parameters.JobLabel}}/ + continueOnError: true + condition: always() + +- task: PublishBuildArtifacts@1 + displayName: Publish Logs + inputs: + PathtoPublish: '$(Build.SourcesDirectory)/PostBuildLogs' + PublishLocation: Container + ArtifactName: PostBuildLogs + continueOnError: true + condition: always() diff --git a/eng/common/templates/steps/retain-build.yml b/eng/common/templates/steps/retain-build.yml new file mode 100644 index 000000000..83d97a26a --- /dev/null +++ b/eng/common/templates/steps/retain-build.yml @@ -0,0 +1,28 @@ +parameters: + # Optional azure devops PAT with build execute permissions for the build's organization, + # only needed if the build that should be retained ran on a different organization than + # the pipeline where this template is executing from + Token: '' + # Optional BuildId to retain, defaults to the current running build + BuildId: '' + # Azure devops Organization URI for the build in the https://dev.azure.com/ format. + # Defaults to the organization the current pipeline is running on + AzdoOrgUri: '$(System.CollectionUri)' + # Azure devops project for the build. Defaults to the project the current pipeline is running on + AzdoProject: '$(System.TeamProject)' + +steps: + - task: powershell@2 + inputs: + targetType: 'filePath' + filePath: eng/common/retain-build.ps1 + pwsh: true + arguments: > + -AzdoOrgUri: ${{parameters.AzdoOrgUri}} + -AzdoProject ${{parameters.AzdoProject}} + -Token ${{coalesce(parameters.Token, '$env:SYSTEM_ACCESSTOKEN') }} + -BuildId ${{coalesce(parameters.BuildId, '$env:BUILD_ID')}} + displayName: Enable permanent build retention + env: + SYSTEM_ACCESSTOKEN: $(System.AccessToken) + BUILD_ID: $(Build.BuildId) \ No newline at end of file diff --git a/eng/common/templates/steps/run-on-unix.yml b/eng/common/templates/steps/run-on-unix.yml new file mode 100644 index 000000000..e1733814f --- /dev/null +++ b/eng/common/templates/steps/run-on-unix.yml @@ -0,0 +1,7 @@ +parameters: + agentOs: '' + steps: [] + +steps: +- ${{ if ne(parameters.agentOs, 'Windows_NT') }}: + - ${{ parameters.steps }} diff --git a/eng/common/templates/steps/run-on-windows.yml b/eng/common/templates/steps/run-on-windows.yml new file mode 100644 index 000000000..73e7e9c27 --- /dev/null +++ b/eng/common/templates/steps/run-on-windows.yml @@ -0,0 +1,7 @@ +parameters: + agentOs: '' + steps: [] + +steps: +- ${{ if eq(parameters.agentOs, 'Windows_NT') }}: + - ${{ parameters.steps }} diff --git a/eng/common/templates/steps/run-script-ifequalelse.yml b/eng/common/templates/steps/run-script-ifequalelse.yml new file mode 100644 index 000000000..3d1242f55 --- /dev/null +++ b/eng/common/templates/steps/run-script-ifequalelse.yml @@ -0,0 +1,33 @@ +parameters: + # if parameter1 equals parameter 2, run 'ifScript' command, else run 'elsescript' command + parameter1: '' + parameter2: '' + ifScript: '' + elseScript: '' + + # name of script step + name: Script + + # display name of script step + displayName: If-Equal-Else Script + + # environment + env: {} + + # conditional expression for step execution + condition: '' + +steps: +- ${{ if and(ne(parameters.ifScript, ''), eq(parameters.parameter1, parameters.parameter2)) }}: + - script: ${{ parameters.ifScript }} + name: ${{ parameters.name }} + displayName: ${{ parameters.displayName }} + env: ${{ parameters.env }} + condition: ${{ parameters.condition }} + +- ${{ if and(ne(parameters.elseScript, ''), ne(parameters.parameter1, parameters.parameter2)) }}: + - script: ${{ parameters.elseScript }} + name: ${{ parameters.name }} + displayName: ${{ parameters.displayName }} + env: ${{ parameters.env }} + condition: ${{ parameters.condition }} \ No newline at end of file diff --git a/eng/common/templates/steps/send-to-helix.yml b/eng/common/templates/steps/send-to-helix.yml new file mode 100644 index 000000000..3eb7e2d5f --- /dev/null +++ b/eng/common/templates/steps/send-to-helix.yml @@ -0,0 +1,91 @@ +# Please remember to update the documentation if you make changes to these parameters! +parameters: + HelixSource: 'pr/default' # required -- sources must start with pr/, official/, prodcon/, or agent/ + HelixType: 'tests/default/' # required -- Helix telemetry which identifies what type of data this is; should include "test" for clarity and must end in '/' + HelixBuild: $(Build.BuildNumber) # required -- the build number Helix will use to identify this -- automatically set to the AzDO build number + HelixTargetQueues: '' # required -- semicolon-delimited list of Helix queues to test on; see https://helix.dot.net/ for a list of queues + HelixAccessToken: '' # required -- access token to make Helix API requests; should be provided by the appropriate variable group + HelixConfiguration: '' # optional -- additional property attached to a job + HelixPreCommands: '' # optional -- commands to run before Helix work item execution + HelixPostCommands: '' # optional -- commands to run after Helix work item execution + WorkItemDirectory: '' # optional -- a payload directory to zip up and send to Helix; requires WorkItemCommand; incompatible with XUnitProjects + WorkItemCommand: '' # optional -- a command to execute on the payload; requires WorkItemDirectory; incompatible with XUnitProjects + WorkItemTimeout: '' # optional -- a timeout in TimeSpan.Parse-ready value (e.g. 00:02:00) for the work item command; requires WorkItemDirectory; incompatible with XUnitProjects + CorrelationPayloadDirectory: '' # optional -- a directory to zip up and send to Helix as a correlation payload + XUnitProjects: '' # optional -- semicolon-delimited list of XUnitProjects to parse and send to Helix; requires XUnitRuntimeTargetFramework, XUnitPublishTargetFramework, XUnitRunnerVersion, and IncludeDotNetCli=true + XUnitWorkItemTimeout: '' # optional -- the workitem timeout in seconds for all workitems created from the xUnit projects specified by XUnitProjects + XUnitPublishTargetFramework: '' # optional -- framework to use to publish your xUnit projects + XUnitRuntimeTargetFramework: '' # optional -- framework to use for the xUnit console runner + XUnitRunnerVersion: '' # optional -- version of the xUnit nuget package you wish to use on Helix; required for XUnitProjects + IncludeDotNetCli: false # optional -- true will download a version of the .NET CLI onto the Helix machine as a correlation payload; requires DotNetCliPackageType and DotNetCliVersion + DotNetCliPackageType: '' # optional -- either 'sdk', 'runtime' or 'aspnetcore-runtime'; determines whether the sdk or runtime will be sent to Helix; see https://raw.githubusercontent.com/dotnet/core/main/release-notes/releases-index.json + DotNetCliVersion: '' # optional -- version of the CLI to send to Helix; based on this: https://raw.githubusercontent.com/dotnet/core/main/release-notes/releases-index.json + WaitForWorkItemCompletion: true # optional -- true will make the task wait until work items have been completed and fail the build if work items fail. False is "fire and forget." + IsExternal: false # [DEPRECATED] -- doesn't do anything, jobs are external if HelixAccessToken is empty and Creator is set + HelixBaseUri: 'https://helix.dot.net/' # optional -- sets the Helix API base URI (allows targeting https://helix.int-dot.net ) + Creator: '' # optional -- if the build is external, use this to specify who is sending the job + DisplayNamePrefix: 'Run Tests' # optional -- rename the beginning of the displayName of the steps in AzDO + condition: succeeded() # optional -- condition for step to execute; defaults to succeeded() + continueOnError: false # optional -- determines whether to continue the build if the step errors; defaults to false + +steps: + - powershell: 'powershell "$env:BUILD_SOURCESDIRECTORY\eng\common\msbuild.ps1 $env:BUILD_SOURCESDIRECTORY\eng\common\helixpublish.proj /restore /p:TreatWarningsAsErrors=false /t:Test /bl:$env:BUILD_SOURCESDIRECTORY\artifacts\log\$env:BuildConfig\SendToHelix.binlog"' + displayName: ${{ parameters.DisplayNamePrefix }} (Windows) + env: + BuildConfig: $(_BuildConfig) + HelixSource: ${{ parameters.HelixSource }} + HelixType: ${{ parameters.HelixType }} + HelixBuild: ${{ parameters.HelixBuild }} + HelixConfiguration: ${{ parameters.HelixConfiguration }} + HelixTargetQueues: ${{ parameters.HelixTargetQueues }} + HelixAccessToken: ${{ parameters.HelixAccessToken }} + HelixPreCommands: ${{ parameters.HelixPreCommands }} + HelixPostCommands: ${{ parameters.HelixPostCommands }} + WorkItemDirectory: ${{ parameters.WorkItemDirectory }} + WorkItemCommand: ${{ parameters.WorkItemCommand }} + WorkItemTimeout: ${{ parameters.WorkItemTimeout }} + CorrelationPayloadDirectory: ${{ parameters.CorrelationPayloadDirectory }} + XUnitProjects: ${{ parameters.XUnitProjects }} + XUnitWorkItemTimeout: ${{ parameters.XUnitWorkItemTimeout }} + XUnitPublishTargetFramework: ${{ parameters.XUnitPublishTargetFramework }} + XUnitRuntimeTargetFramework: ${{ parameters.XUnitRuntimeTargetFramework }} + XUnitRunnerVersion: ${{ parameters.XUnitRunnerVersion }} + IncludeDotNetCli: ${{ parameters.IncludeDotNetCli }} + DotNetCliPackageType: ${{ parameters.DotNetCliPackageType }} + DotNetCliVersion: ${{ parameters.DotNetCliVersion }} + WaitForWorkItemCompletion: ${{ parameters.WaitForWorkItemCompletion }} + HelixBaseUri: ${{ parameters.HelixBaseUri }} + Creator: ${{ parameters.Creator }} + SYSTEM_ACCESSTOKEN: $(System.AccessToken) + condition: and(${{ parameters.condition }}, eq(variables['Agent.Os'], 'Windows_NT')) + continueOnError: ${{ parameters.continueOnError }} + - script: $BUILD_SOURCESDIRECTORY/eng/common/msbuild.sh $BUILD_SOURCESDIRECTORY/eng/common/helixpublish.proj /restore /p:TreatWarningsAsErrors=false /t:Test /bl:$BUILD_SOURCESDIRECTORY/artifacts/log/$BuildConfig/SendToHelix.binlog + displayName: ${{ parameters.DisplayNamePrefix }} (Unix) + env: + BuildConfig: $(_BuildConfig) + HelixSource: ${{ parameters.HelixSource }} + HelixType: ${{ parameters.HelixType }} + HelixBuild: ${{ parameters.HelixBuild }} + HelixConfiguration: ${{ parameters.HelixConfiguration }} + HelixTargetQueues: ${{ parameters.HelixTargetQueues }} + HelixAccessToken: ${{ parameters.HelixAccessToken }} + HelixPreCommands: ${{ parameters.HelixPreCommands }} + HelixPostCommands: ${{ parameters.HelixPostCommands }} + WorkItemDirectory: ${{ parameters.WorkItemDirectory }} + WorkItemCommand: ${{ parameters.WorkItemCommand }} + WorkItemTimeout: ${{ parameters.WorkItemTimeout }} + CorrelationPayloadDirectory: ${{ parameters.CorrelationPayloadDirectory }} + XUnitProjects: ${{ parameters.XUnitProjects }} + XUnitWorkItemTimeout: ${{ parameters.XUnitWorkItemTimeout }} + XUnitPublishTargetFramework: ${{ parameters.XUnitPublishTargetFramework }} + XUnitRuntimeTargetFramework: ${{ parameters.XUnitRuntimeTargetFramework }} + XUnitRunnerVersion: ${{ parameters.XUnitRunnerVersion }} + IncludeDotNetCli: ${{ parameters.IncludeDotNetCli }} + DotNetCliPackageType: ${{ parameters.DotNetCliPackageType }} + DotNetCliVersion: ${{ parameters.DotNetCliVersion }} + WaitForWorkItemCompletion: ${{ parameters.WaitForWorkItemCompletion }} + HelixBaseUri: ${{ parameters.HelixBaseUri }} + Creator: ${{ parameters.Creator }} + SYSTEM_ACCESSTOKEN: $(System.AccessToken) + condition: and(${{ parameters.condition }}, ne(variables['Agent.Os'], 'Windows_NT')) + continueOnError: ${{ parameters.continueOnError }} diff --git a/eng/common/templates/steps/source-build.yml b/eng/common/templates/steps/source-build.yml new file mode 100644 index 000000000..a97a185a3 --- /dev/null +++ b/eng/common/templates/steps/source-build.yml @@ -0,0 +1,114 @@ +parameters: + # This template adds arcade-powered source-build to CI. + + # This is a 'steps' template, and is intended for advanced scenarios where the existing build + # infra has a careful build methodology that must be followed. For example, a repo + # (dotnet/runtime) might choose to clone the GitHub repo only once and store it as a pipeline + # artifact for all subsequent jobs to use, to reduce dependence on a strong network connection to + # GitHub. Using this steps template leaves room for that infra to be included. + + # Defines the platform on which to run the steps. See 'eng/common/templates/job/source-build.yml' + # for details. The entire object is described in the 'job' template for simplicity, even though + # the usage of the properties on this object is split between the 'job' and 'steps' templates. + platform: {} + +steps: +# Build. Keep it self-contained for simple reusability. (No source-build-specific job variables.) +- script: | + set -x + df -h + + # If building on the internal project, the artifact feeds variable may be available (usually only if needed) + # In that case, call the feed setup script to add internal feeds corresponding to public ones. + # In addition, add an msbuild argument to copy the WIP from the repo to the target build location. + # This is because SetupNuGetSources.sh will alter the current NuGet.config file, and we need to preserve those + # changes. + internalRestoreArgs= + if [ '$(dn-bot-dnceng-artifact-feeds-rw)' != '$''(dn-bot-dnceng-artifact-feeds-rw)' ]; then + # Temporarily work around https://github.com/dotnet/arcade/issues/7709 + chmod +x $(Build.SourcesDirectory)/eng/common/SetupNugetSources.sh + $(Build.SourcesDirectory)/eng/common/SetupNugetSources.sh $(Build.SourcesDirectory)/NuGet.config $(dn-bot-dnceng-artifact-feeds-rw) + internalRestoreArgs='/p:CopyWipIntoInnerSourceBuildRepo=true' + + # The 'Copy WIP' feature of source build uses git stash to apply changes from the original repo. + # This only works if there is a username/email configured, which won't be the case in most CI runs. + git config --get user.email + if [ $? -ne 0 ]; then + git config user.email dn-bot@microsoft.com + git config user.name dn-bot + fi + fi + + # If building on the internal project, the internal storage variable may be available (usually only if needed) + # In that case, add variables to allow the download of internal runtimes if the specified versions are not found + # in the default public locations. + internalRuntimeDownloadArgs= + if [ '$(dotnetbuilds-internal-container-read-token-base64)' != '$''(dotnetbuilds-internal-container-read-token-base64)' ]; then + internalRuntimeDownloadArgs='/p:DotNetRuntimeSourceFeed=https://dotnetbuilds.blob.core.windows.net/internal /p:DotNetRuntimeSourceFeedKey=$(dotnetbuilds-internal-container-read-token-base64) --runtimesourcefeed https://dotnetbuilds.blob.core.windows.net/internal --runtimesourcefeedkey $(dotnetbuilds-internal-container-read-token-base64)' + fi + + buildConfig=Release + # Check if AzDO substitutes in a build config from a variable, and use it if so. + if [ '$(_BuildConfig)' != '$''(_BuildConfig)' ]; then + buildConfig='$(_BuildConfig)' + fi + + officialBuildArgs= + if [ '${{ and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}' = 'True' ]; then + officialBuildArgs='/p:DotNetPublishUsingPipelines=true /p:OfficialBuildId=$(BUILD.BUILDNUMBER)' + fi + + targetRidArgs= + if [ '${{ parameters.platform.targetRID }}' != '' ]; then + targetRidArgs='/p:TargetRid=${{ parameters.platform.targetRID }}' + fi + + runtimeOsArgs= + if [ '${{ parameters.platform.runtimeOS }}' != '' ]; then + runtimeOsArgs='/p:RuntimeOS=${{ parameters.platform.runtimeOS }}' + fi + + publishArgs= + if [ '${{ parameters.platform.skipPublishValidation }}' != 'true' ]; then + publishArgs='--publish' + fi + + assetManifestFileName=SourceBuild_RidSpecific.xml + if [ '${{ parameters.platform.name }}' != '' ]; then + assetManifestFileName=SourceBuild_${{ parameters.platform.name }}.xml + fi + + ${{ coalesce(parameters.platform.buildScript, './build.sh') }} --ci \ + --configuration $buildConfig \ + --restore --build --pack $publishArgs -bl \ + $officialBuildArgs \ + $internalRuntimeDownloadArgs \ + $internalRestoreArgs \ + $targetRidArgs \ + $runtimeOsArgs \ + /p:SourceBuildNonPortable=${{ parameters.platform.nonPortable }} \ + /p:ArcadeBuildFromSource=true \ + /p:AssetManifestFileName=$assetManifestFileName + displayName: Build + +# Upload build logs for diagnosis. +- task: CopyFiles@2 + displayName: Prepare BuildLogs staging directory + inputs: + SourceFolder: '$(Build.SourcesDirectory)' + Contents: | + **/*.log + **/*.binlog + artifacts/source-build/self/prebuilt-report/** + TargetFolder: '$(Build.StagingDirectory)/BuildLogs' + CleanTargetFolder: true + continueOnError: true + condition: succeededOrFailed() + +- task: PublishPipelineArtifact@1 + displayName: Publish BuildLogs + inputs: + targetPath: '$(Build.StagingDirectory)/BuildLogs' + artifactName: BuildLogs_SourceBuild_${{ parameters.platform.name }}_Attempt$(System.JobAttempt) + continueOnError: true + condition: succeededOrFailed() diff --git a/eng/common/templates/steps/telemetry-end.yml b/eng/common/templates/steps/telemetry-end.yml new file mode 100644 index 000000000..fadc04ca1 --- /dev/null +++ b/eng/common/templates/steps/telemetry-end.yml @@ -0,0 +1,102 @@ +parameters: + maxRetries: 5 + retryDelay: 10 # in seconds + +steps: +- bash: | + if [ "$AGENT_JOBSTATUS" = "Succeeded" ] || [ "$AGENT_JOBSTATUS" = "PartiallySucceeded" ]; then + errorCount=0 + else + errorCount=1 + fi + warningCount=0 + + curlStatus=1 + retryCount=0 + # retry loop to harden against spotty telemetry connections + # we don't retry successes and 4xx client errors + until [[ $curlStatus -eq 0 || ( $curlStatus -ge 400 && $curlStatus -le 499 ) || $retryCount -ge $MaxRetries ]] + do + if [ $retryCount -gt 0 ]; then + echo "Failed to send telemetry to Helix; waiting $RetryDelay seconds before retrying..." + sleep $RetryDelay + fi + + # create a temporary file for curl output + res=`mktemp` + + curlResult=` + curl --verbose --output $res --write-out "%{http_code}"\ + -H 'Content-Type: application/json' \ + -H "X-Helix-Job-Token: $Helix_JobToken" \ + -H 'Content-Length: 0' \ + -X POST -G "https://helix.dot.net/api/2018-03-14/telemetry/job/build/$Helix_WorkItemId/finish" \ + --data-urlencode "errorCount=$errorCount" \ + --data-urlencode "warningCount=$warningCount"` + curlStatus=$? + + if [ $curlStatus -eq 0 ]; then + if [ $curlResult -gt 299 ] || [ $curlResult -lt 200 ]; then + curlStatus=$curlResult + fi + fi + + let retryCount++ + done + + if [ $curlStatus -ne 0 ]; then + echo "Failed to Send Build Finish information after $retryCount retries" + vstsLogOutput="vso[task.logissue type=error;sourcepath=templates/steps/telemetry-end.yml;code=1;]Failed to Send Build Finish information: $curlStatus" + echo "##$vstsLogOutput" + exit 1 + fi + displayName: Send Unix Build End Telemetry + env: + # defined via VSTS variables in start-job.sh + Helix_JobToken: $(Helix_JobToken) + Helix_WorkItemId: $(Helix_WorkItemId) + MaxRetries: ${{ parameters.maxRetries }} + RetryDelay: ${{ parameters.retryDelay }} + condition: and(always(), ne(variables['Agent.Os'], 'Windows_NT')) +- powershell: | + if (($env:Agent_JobStatus -eq 'Succeeded') -or ($env:Agent_JobStatus -eq 'PartiallySucceeded')) { + $ErrorCount = 0 + } else { + $ErrorCount = 1 + } + $WarningCount = 0 + + # Basic retry loop to harden against server flakiness + $retryCount = 0 + while ($retryCount -lt $env:MaxRetries) { + try { + Invoke-RestMethod -Uri "https://helix.dot.net/api/2018-03-14/telemetry/job/build/$env:Helix_WorkItemId/finish?errorCount=$ErrorCount&warningCount=$WarningCount" -Method Post -ContentType "application/json" -Body "" ` + -Headers @{ 'X-Helix-Job-Token'=$env:Helix_JobToken } + break + } + catch { + $statusCode = $_.Exception.Response.StatusCode.value__ + if ($statusCode -ge 400 -and $statusCode -le 499) { + Write-Host "##vso[task.logissue]error Failed to send telemetry to Helix (status code $statusCode); not retrying (4xx client error)" + Write-Host "##vso[task.logissue]error ", $_.Exception.GetType().FullName, $_.Exception.Message + exit 1 + } + Write-Host "Failed to send telemetry to Helix (status code $statusCode); waiting $env:RetryDelay seconds before retrying..." + $retryCount++ + sleep $env:RetryDelay + continue + } + } + + if ($retryCount -ge $env:MaxRetries) { + Write-Host "##vso[task.logissue]error Failed to send telemetry to Helix after $retryCount retries." + exit 1 + } + displayName: Send Windows Build End Telemetry + env: + # defined via VSTS variables in start-job.ps1 + Helix_JobToken: $(Helix_JobToken) + Helix_WorkItemId: $(Helix_WorkItemId) + MaxRetries: ${{ parameters.maxRetries }} + RetryDelay: ${{ parameters.retryDelay }} + condition: and(always(),eq(variables['Agent.Os'], 'Windows_NT')) diff --git a/eng/common/templates/steps/telemetry-start.yml b/eng/common/templates/steps/telemetry-start.yml new file mode 100644 index 000000000..32c01ef0b --- /dev/null +++ b/eng/common/templates/steps/telemetry-start.yml @@ -0,0 +1,241 @@ +parameters: + helixSource: 'undefined_defaulted_in_telemetry.yml' + helixType: 'undefined_defaulted_in_telemetry.yml' + buildConfig: '' + runAsPublic: false + maxRetries: 5 + retryDelay: 10 # in seconds + +steps: +- ${{ if and(eq(parameters.runAsPublic, 'false'), not(eq(variables['System.TeamProject'], 'public'))) }}: + - task: AzureKeyVault@1 + inputs: + azureSubscription: 'HelixProd_KeyVault' + KeyVaultName: HelixProdKV + SecretsFilter: 'HelixApiAccessToken' + condition: always() +- bash: | + # create a temporary file + jobInfo=`mktemp` + + # write job info content to temporary file + cat > $jobInfo < Date: Tue, 22 Nov 2022 14:33:37 -0800 Subject: [PATCH 24/54] Enable public Azure DevOps builds (#366) - add azure-pipelines.yml - clean workspace when checking out the repo - build about the same matrix as we have on TeamCity in Main.Integration builds - run tests only in Release job by default - do component governance work only in Release job - do not inject CodeQL3000 tasks (when building main) - publish test results - jobs usually take less than 10 minutes - change build.cmd to enable overrides of its command line parameters nits: - touch up .codeql.yml to avoid test code and include portable projects --- .codeql.yml | 3 +- azure-pipelines.yml | 92 +++++++++++++++++++++++++++++++++++++++++++++ build.cmd | 2 +- 3 files changed, 94 insertions(+), 3 deletions(-) create mode 100644 azure-pipelines.yml diff --git a/.codeql.yml b/.codeql.yml index 7ad4723f1..462a0be40 100644 --- a/.codeql.yml +++ b/.codeql.yml @@ -6,7 +6,6 @@ parameters: default: true variables: -- template: eng/common/templates/variables/pool-providers.yml # CG is handled in the primary CI pipeline - name: skipComponentGovernanceDetection value: true @@ -59,7 +58,7 @@ jobs: - script: .\build.cmd EnableSkipStrongNames displayName: Windows Build - EnableSkipStrongNames - - script: .\build.cmd + - script: .\build.cmd Build /p:BuildPortable=true /p:Desktop=false displayName: Windows Build - task: CodeQL3000Finalize@0 diff --git a/azure-pipelines.yml b/azure-pipelines.yml new file mode 100644 index 000000000..fea01ece8 --- /dev/null +++ b/azure-pipelines.yml @@ -0,0 +1,92 @@ +parameters: + # Test only the Release build by default. +- name: ReleaseBuildTarget + displayName: 'Build which target for Release?' + type: string + values: [ Build, Integration, UnitTest ] + default: UnitTest +- name: OtherBuildTarget + displayName: 'Build which target for Debug/CodeAnalysis?' + type: string + values: [ Build, Integration, UnitTest ] + default: Build + +variables: +- name: DOTNET_CLI_TELEMETRY_OPTOUT + value: 1 + # Run CodeQL3000 tasks in a separate internal pipeline; not needed here. +- name: Codeql.SkipTaskAutoInjection + value: true + +trigger: [main] +pr: ['*'] + +jobs: +- job: build + displayName: Build + pool: + ${{ if eq(variables['System.TeamProject'], 'public') }}: + name: NetCore-Public + demands: ImageOverride -equals windows.vs2017.amd64.open + ${{ else }}: + name: NetCore1ESPool-Internal + demands: ImageOverride -equals windows.vs2017.amd64 + timeoutInMinutes: 30 + + strategy: + matrix: + Release: + _BuildTarget: ${{ parameters.ReleaseBuildTarget }} + _Configuration: Release + _StyleCopEnabled: true + # Do CG work only in internal pipelines. + skipComponentGovernanceDetection: ${{ eq(variables['System.TeamProject'], 'public') }} + Debug: + _BuildTarget: ${{ parameters.OtherBuildTarget }} + _Configuration: Debug + _StyleCopEnabled: false + # Do not redo CG work. Configuration changes in this part of the matrix are not relevant to CG. + skipComponentGovernanceDetection: true + CodeAnalysis: + _BuildTarget: ${{ parameters.OtherBuildTarget }} + _Configuration: CodeAnalysis + _StyleCopEnabled: false + # Do not redo CG work. Configuration changes in this part of the matrix are not relevant to CG. + skipComponentGovernanceDetection: true + + steps: + - checkout: self + clean: true + displayName: Checkout + - task: UseDotNet@2 + displayName: Get .NET SDK + inputs: + useGlobalJson: true + + - script: .\build.cmd EnableSkipStrongNames + displayName: Enable SkipStrongNames + - script: .\build.cmd $(_BuildTarget) /p:Desktop=false /p:BuildPortable=true ^ + /binaryLogger:artifacts/msbuild.binlog /p:Configuration=$(_Configuration) /p:StyleCopEnabled=$(_StyleCopEnabled) ^ + /fileLoggerParameters:LogFile=artifacts/msbuild.log;Summary;Verbosity=minimal + displayName: Build + + - publish: ./bin/$(_Configuration)/Test/TestResults/ + artifact: $(_Configuration) Test Results + condition: and(always(), ne(variables._BuildTarget, 'Build')) + continueOnError: true + displayName: Upload test results + - task: PublishTestResults@2 + condition: and(always(), ne(variables._BuildTarget, 'Build')) + continueOnError: true + displayName: Publish test results + inputs: + mergeTestResults: true + searchFolder: ./bin/$(_Configuration)/Test/TestResults/ + testResultsFiles: '*.xml' + testRunner: xUnit + testRunTitle: $(_Configuration) + + - publish: ./artifacts/ + artifact: $(_Configuration) Logs + condition: always() + displayName: Upload logs diff --git a/build.cmd b/build.cmd index 270103785..a5ca225d4 100644 --- a/build.cmd +++ b/build.cmd @@ -40,7 +40,7 @@ if exist "%InstallDir%\MSBuild\15.0\Bin\MSBuild.exe" ( if "%1" == "" goto BuildDefaults -%MSBuild% Runtime.msbuild /m /nr:false /t:%* /p:Platform="Any CPU" /p:Desktop=true /v:M /fl /flp:LogFile=bin\msbuild.log;Verbosity=Normal +%MSBuild% Runtime.msbuild /m /nr:false /p:Platform="Any CPU" /p:Desktop=true /v:M /fl /flp:LogFile=bin\msbuild.log;Verbosity=Normal /t:%* if %ERRORLEVEL% neq 0 goto BuildFail goto BuildSuccess From 06589fb44292b517a343da997e1bb2fb7f0f4bea Mon Sep 17 00:00:00 2001 From: Doug Bunting <6431421+dougbu@users.noreply.github.com> Date: Wed, 23 Nov 2022 17:07:19 -0800 Subject: [PATCH 25/54] Do not fail tests immediately (#368) - combine `RegexReplace` into `PrintTestRunSummary` task - remove unused `WarnOnNoMatch` parameter; inline other parameters - capture test summary in `msbuild` logs - avoid `System.Console` use in the task - fail task if any tests fail - collect `xunit` task exit codes in case of catastrophic problems (not test failures) - fail build if `PrintTestRunSummary` doesn't but errors occurred also: - do not test assemblies in parallel; reduce port contention issues - avoid `CallTarget` task nits: - clean some trailing whitespace in C# sources - mostly files I expect to update soon - reduce `NuGet.exe restore` verbosity; no longer debugging that - add console summary when using build.cmd - reduce duplication in `RestorePackages` target - only restore NetCore projects when `$(BuildPortable)` is `true` - restore src NetStandard project transitively through NetStandard.Test project - pass more properties w/ `Restore` target invocation --- Runtime.msbuild | 31 ++-- build.cmd | 6 +- src/Common/CollectionExtensions.cs | 8 +- src/Common/CommonWebApiResources.Designer.cs | 24 +-- src/Common/Error.cs | 2 +- .../ByteRangeStreamContent.cs | 28 +-- .../Formatting/BufferedMediaTypeFormatter.cs | 8 +- .../Formatting/DefaultContentNegotiator.cs | 14 +- .../Formatting/FormDataCollection.cs | 18 +- .../Formatting/FormUrlEncodedJson.cs | 18 +- .../FormUrlEncodedMediaTypeFormatter.cs | 6 +- .../Formatting/JsonMediaTypeFormatter.cs | 2 +- .../Formatting/MediaTypeFormatter.cs | 4 +- .../MediaTypeHeaderValueExtensions.cs | 12 +- ...MediaTypeWithQualityHeaderValueComparer.cs | 6 +- .../Formatting/ParsedMediaTypeHeaderValue.cs | 12 +- .../Parsers/FormUrlEncodedParser.cs | 6 +- .../Parsers/HttpRequestLineParser.cs | 4 +- .../Parsers/HttpStatusLineParser.cs | 4 +- .../Parsers/MimeMultipartBodyPartParser.cs | 14 +- .../Formatting/Parsers/MimeMultipartParser.cs | 30 ++-- .../Formatting/RequestHeaderMapping.cs | 10 +- .../StringWithQualityHeaderValueComparer.cs | 6 +- .../Formatting/XmlMediaTypeFormatter.cs | 6 +- .../FormattingUtilities.cs | 4 +- .../Handlers/ProgressStream.cs | 2 +- .../HttpContentFormDataExtensions.cs | 2 +- .../HttpContentMessageExtensions.cs | 8 +- .../HttpContentMultipartExtensions.cs | 8 +- .../HttpMessageContent.cs | 2 +- .../Internal/HttpValueCollection.cs | 2 +- .../MimeBodyPart.cs | 4 +- .../MultipartRelatedStreamProvider.cs | 4 +- .../Properties/Resources.Designer.cs | 162 +++++++++--------- .../ApplicationParts/ApplicationPartTest.cs | 6 +- tools/WebStack.tasks.targets | 107 +++++------- tools/WebStack.xunit.targets | 29 ++-- 37 files changed, 299 insertions(+), 320 deletions(-) diff --git a/Runtime.msbuild b/Runtime.msbuild index 2e785ab2e..4999f6a4f 100644 --- a/Runtime.msbuild +++ b/Runtime.msbuild @@ -11,7 +11,7 @@ true true false - $(BuildInParallel) + false $(MSBuildThisFileDirectory)bin\$(Configuration)\test\TestResults\ $(MSBuildThisFileDirectory)packages\Microsoft.Web.SkipStrongNames.1.0.0\tools\SkipStrongNames.exe $(MSBuildThisFileDirectory)tools\SkipStrongNames.xml @@ -65,25 +65,24 @@ - <_NuGetPackagesAndSolutions Include="src\System.Net.Http.Formatting.NetCore\packages.config; - test\System.Net.Http.Formatting.NetCore.Test\packages.config; - Runtime.sln" /> + <_NuGetPackagesAndSolutions Include="Runtime.sln" /> <_NuGetPackagesAndSolutions Include="src\System.Net.Http.Formatting.NetCore\packages.config; test\System.Net.Http.Formatting.NetCore.Test\packages.config" Condition=" '$(BuildPortable)' == 'true' " /> - <_ProjectsToRestore Include="src\System.Net.Http.Formatting.NetStandard\System.Net.Http.Formatting.NetStandard.csproj; - test\System.Net.Http.Formatting.NetStandard.Test\System.Net.Http.Formatting.NetStandard.Test.csproj" + <_ProjectsToRestore Include="test\System.Net.Http.Formatting.NetStandard.Test\System.Net.Http.Formatting.NetStandard.Test.csproj" Condition=" '$(BuildPortable)' == 'true' " /> - + -Verbosity quiet -ConfigFile "$(MSBuildThisFileDirectory)\.nuget\NuGet.Config"' /> + @@ -110,9 +109,7 @@ Properties="Configuration=$(Configuration);CodeAnalysis=$(CodeAnalysis);StyleCopEnabled=$(StyleCopEnabled);VisualStudioVersion=$(VisualStudioVersion)" /> - - - + @@ -128,7 +125,9 @@ - + + + - + + + + diff --git a/build.cmd b/build.cmd index a5ca225d4..5a6a4f8f9 100644 --- a/build.cmd +++ b/build.cmd @@ -40,12 +40,14 @@ if exist "%InstallDir%\MSBuild\15.0\Bin\MSBuild.exe" ( if "%1" == "" goto BuildDefaults -%MSBuild% Runtime.msbuild /m /nr:false /p:Platform="Any CPU" /p:Desktop=true /v:M /fl /flp:LogFile=bin\msbuild.log;Verbosity=Normal /t:%* +%MSBuild% Runtime.msbuild /m /nr:false /p:Platform="Any CPU" /p:Desktop=true /v:M ^ + /fl /fileLoggerParameters:LogFile=bin\msbuild.log;Verbosity=Normal /consoleLoggerParameters:Summary /t:%* if %ERRORLEVEL% neq 0 goto BuildFail goto BuildSuccess :BuildDefaults -%MSBuild% Runtime.msbuild /m /nr:false /p:Platform="Any CPU" /p:Desktop=true /v:M /fl /flp:LogFile=bin\msbuild.log;Verbosity=Normal +%MSBuild% Runtime.msbuild /m /nr:false /p:Platform="Any CPU" /p:Desktop=true /v:M ^ + /fl /fileLoggerParameters:LogFile=bin\msbuild.log;Verbosity=Normal /consoleLoggerParameters:Summary if %ERRORLEVEL% neq 0 goto BuildFail goto BuildSuccess diff --git a/src/Common/CollectionExtensions.cs b/src/Common/CollectionExtensions.cs index c89d4ad98..bfd1eb61d 100644 --- a/src/Common/CollectionExtensions.cs +++ b/src/Common/CollectionExtensions.cs @@ -27,7 +27,7 @@ public static T[] AppendAndReallocate(this T[] array, T value) } /// - /// Return the enumerable as an Array, copying if required. Optimized for common case where it is an Array. + /// Return the enumerable as an Array, copying if required. Optimized for common case where it is an Array. /// Avoid mutating the return value. /// public static T[] AsArray(this IEnumerable values) @@ -43,7 +43,7 @@ public static T[] AsArray(this IEnumerable values) } /// - /// Return the enumerable as a Collection of T, copying if required. Optimized for the common case where it is + /// Return the enumerable as a Collection of T, copying if required. Optimized for the common case where it is /// a Collection of T and avoiding a copy if it implements IList of T. Avoid mutating the return value. /// public static Collection AsCollection(this IEnumerable enumerable) @@ -78,9 +78,9 @@ public static IList AsIList(this IEnumerable enumerable) } return new List(enumerable); } - + /// - /// Return the enumerable as a List of T, copying if required. Optimized for common case where it is an List of T + /// Return the enumerable as a List of T, copying if required. Optimized for common case where it is an List of T /// or a ListWrapperCollection of T. Avoid mutating the return value. /// public static List AsList(this IEnumerable enumerable) diff --git a/src/Common/CommonWebApiResources.Designer.cs b/src/Common/CommonWebApiResources.Designer.cs index 4ceb3f115..251eed2b4 100644 --- a/src/Common/CommonWebApiResources.Designer.cs +++ b/src/Common/CommonWebApiResources.Designer.cs @@ -24,15 +24,15 @@ namespace System.Web.Http.Properties { [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class CommonWebApiResources { - + private static global::System.Resources.ResourceManager resourceMan; - + private static global::System.Globalization.CultureInfo resourceCulture; - + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal CommonWebApiResources() { } - + /// /// Returns the cached ResourceManager instance used by this class. /// @@ -59,7 +59,7 @@ internal CommonWebApiResources() { return resourceMan; } } - + /// /// Overrides the current thread's CurrentUICulture property for all /// resource lookups using this strongly typed resource class. @@ -73,7 +73,7 @@ internal CommonWebApiResources() { resourceCulture = value; } } - + /// /// Looks up a localized string similar to Relative URI values are not supported: '{0}'. The URI must be absolute.. /// @@ -82,7 +82,7 @@ internal static string ArgumentInvalidAbsoluteUri { return ResourceManager.GetString("ArgumentInvalidAbsoluteUri", resourceCulture); } } - + /// /// Looks up a localized string similar to Unsupported URI scheme: '{0}'. The URI scheme must be either '{1}' or '{2}'.. /// @@ -91,7 +91,7 @@ internal static string ArgumentInvalidHttpUriScheme { return ResourceManager.GetString("ArgumentInvalidHttpUriScheme", resourceCulture); } } - + /// /// Looks up a localized string similar to Value must be greater than or equal to {0}.. /// @@ -100,7 +100,7 @@ internal static string ArgumentMustBeGreaterThanOrEqualTo { return ResourceManager.GetString("ArgumentMustBeGreaterThanOrEqualTo", resourceCulture); } } - + /// /// Looks up a localized string similar to Value must be less than or equal to {0}.. /// @@ -109,7 +109,7 @@ internal static string ArgumentMustBeLessThanOrEqualTo { return ResourceManager.GetString("ArgumentMustBeLessThanOrEqualTo", resourceCulture); } } - + /// /// Looks up a localized string similar to The argument '{0}' is null or empty.. /// @@ -118,7 +118,7 @@ internal static string ArgumentNullOrEmpty { return ResourceManager.GetString("ArgumentNullOrEmpty", resourceCulture); } } - + /// /// Looks up a localized string similar to URI must not contain a query component or a fragment identifier.. /// @@ -127,7 +127,7 @@ internal static string ArgumentUriHasQueryOrFragment { return ResourceManager.GetString("ArgumentUriHasQueryOrFragment", resourceCulture); } } - + /// /// Looks up a localized string similar to The value of argument '{0}' ({1}) is invalid for Enum type '{2}'.. /// diff --git a/src/Common/Error.cs b/src/Common/Error.cs index 0e8c83465..b6013c5dc 100644 --- a/src/Common/Error.cs +++ b/src/Common/Error.cs @@ -74,7 +74,7 @@ internal static ArgumentException ArgumentUriNotAbsolute(string parameterName, U } /// - /// Creates an with a message saying that the argument must be an absolute URI + /// Creates an with a message saying that the argument must be an absolute URI /// without a query or fragment identifier and then logs it with . /// /// The name of the parameter that caused the current exception. diff --git a/src/System.Net.Http.Formatting/ByteRangeStreamContent.cs b/src/System.Net.Http.Formatting/ByteRangeStreamContent.cs index 587a0fd7f..40edaddb8 100644 --- a/src/System.Net.Http.Formatting/ByteRangeStreamContent.cs +++ b/src/System.Net.Http.Formatting/ByteRangeStreamContent.cs @@ -13,8 +13,8 @@ namespace System.Net.Http { /// /// implementation which provides a byte range view over a stream used to generate HTTP - /// 206 (Partial Content) byte range responses. The supports one or more - /// byte ranges regardless of whether the ranges are consecutive or not. If there is only one range then a + /// 206 (Partial Content) byte range responses. The supports one or more + /// byte ranges regardless of whether the ranges are consecutive or not. If there is only one range then a /// single partial response body containing a Content-Range header is generated. If there are more than one /// ranges then a multipart/byteranges response is generated where each body part contains a range indicated /// by the associated Content-Range header field. @@ -33,9 +33,9 @@ public class ByteRangeStreamContent : HttpContent /// /// implementation which provides a byte range view over a stream used to generate HTTP - /// 206 (Partial Content) byte range responses. If none of the requested ranges overlap with the current extend - /// of the selected resource represented by the parameter then an - /// is thrown indicating the valid Content-Range of the content. + /// 206 (Partial Content) byte range responses. If none of the requested ranges overlap with the current extend + /// of the selected resource represented by the parameter then an + /// is thrown indicating the valid Content-Range of the content. /// /// The stream over which to generate a byte range view. /// The range or ranges, typically obtained from the Range HTTP request header field. @@ -47,9 +47,9 @@ public ByteRangeStreamContent(Stream content, RangeHeaderValue range, string med /// /// implementation which provides a byte range view over a stream used to generate HTTP - /// 206 (Partial Content) byte range responses. If none of the requested ranges overlap with the current extend - /// of the selected resource represented by the parameter then an - /// is thrown indicating the valid Content-Range of the content. + /// 206 (Partial Content) byte range responses. If none of the requested ranges overlap with the current extend + /// of the selected resource represented by the parameter then an + /// is thrown indicating the valid Content-Range of the content. /// /// The stream over which to generate a byte range view. /// The range or ranges, typically obtained from the Range HTTP request header field. @@ -62,9 +62,9 @@ public ByteRangeStreamContent(Stream content, RangeHeaderValue range, string med /// /// implementation which provides a byte range view over a stream used to generate HTTP - /// 206 (Partial Content) byte range responses. If none of the requested ranges overlap with the current extend - /// of the selected resource represented by the parameter then an - /// is thrown indicating the valid Content-Range of the content. + /// 206 (Partial Content) byte range responses. If none of the requested ranges overlap with the current extend + /// of the selected resource represented by the parameter then an + /// is thrown indicating the valid Content-Range of the content. /// /// The stream over which to generate a byte range view. /// The range or ranges, typically obtained from the Range HTTP request header field. @@ -76,9 +76,9 @@ public ByteRangeStreamContent(Stream content, RangeHeaderValue range, MediaTypeH /// /// implementation which provides a byte range view over a stream used to generate HTTP - /// 206 (Partial Content) byte range responses. If none of the requested ranges overlap with the current extend - /// of the selected resource represented by the parameter then an - /// is thrown indicating the valid Content-Range of the content. + /// 206 (Partial Content) byte range responses. If none of the requested ranges overlap with the current extend + /// of the selected resource represented by the parameter then an + /// is thrown indicating the valid Content-Range of the content. /// /// The stream over which to generate a byte range view. /// The range or ranges, typically obtained from the Range HTTP request header field. diff --git a/src/System.Net.Http.Formatting/Formatting/BufferedMediaTypeFormatter.cs b/src/System.Net.Http.Formatting/Formatting/BufferedMediaTypeFormatter.cs index 29554fd07..908ba6221 100644 --- a/src/System.Net.Http.Formatting/Formatting/BufferedMediaTypeFormatter.cs +++ b/src/System.Net.Http.Formatting/Formatting/BufferedMediaTypeFormatter.cs @@ -13,7 +13,7 @@ namespace System.Net.Http.Formatting { /// - /// Base class for writing a synchronous formatter on top of the asynchronous formatter infrastructure. + /// Base class for writing a synchronous formatter on top of the asynchronous formatter infrastructure. /// This does not guarantee non-blocking threads. The only way to guarantee that we don't block a thread on IO is /// to use the asynchronous . /// @@ -219,13 +219,13 @@ private static Stream GetBufferStream(Stream innerStream, int bufferSize) { Contract.Assert(innerStream != null); - // We wrap the inner stream in a non-closing delegating stream so that we allow the user + // We wrap the inner stream in a non-closing delegating stream so that we allow the user // to use the using (...) pattern yet not break the contract of formatters not closing // the inner stream. Stream nonClosingStream = new NonClosingDelegatingStream(innerStream); - // This uses a naive buffering. BufferedStream() will block the thread while it drains the buffer. - // We can explore a smarter implementation that async drains the buffer. + // This uses a naive buffering. BufferedStream() will block the thread while it drains the buffer. + // We can explore a smarter implementation that async drains the buffer. return new BufferedStream(nonClosingStream, bufferSize); } } diff --git a/src/System.Net.Http.Formatting/Formatting/DefaultContentNegotiator.cs b/src/System.Net.Http.Formatting/Formatting/DefaultContentNegotiator.cs index 94b0f9b99..0cf5c36d7 100644 --- a/src/System.Net.Http.Formatting/Formatting/DefaultContentNegotiator.cs +++ b/src/System.Net.Http.Formatting/Formatting/DefaultContentNegotiator.cs @@ -95,7 +95,7 @@ public virtual ContentNegotiationResult Negotiate(Type type, HttpRequestMessage /// /// Determine how well each formatter matches by associating a value - /// with the formatter. Then associate the quality of the match based on q-factors and other parameters. The result of this + /// with the formatter. Then associate the quality of the match based on q-factors and other parameters. The result of this /// method is a collection of the matches found categorized and assigned a quality value. /// /// The type to be serialized. @@ -123,7 +123,7 @@ protected virtual Collection ComputeFormatterMatches(Ty // Go through each formatter to find how well it matches. ListWrapperCollection matches = new ListWrapperCollection(); MediaTypeFormatter[] writingFormatters = GetWritingFormatters(formatters); - for (int i = 0; i < writingFormatters.Length; i++) + for (int i = 0; i < writingFormatters.Length; i++) { MediaTypeFormatter formatter = writingFormatters[i]; MediaTypeFormatterMatch match = null; @@ -161,7 +161,7 @@ protected virtual Collection ComputeFormatterMatches(Ty continue; } - // Check whether we should match on type or stop the matching process. + // Check whether we should match on type or stop the matching process. // The latter is used to generate 406 (Not Acceptable) status codes. bool shouldMatchOnType = ShouldMatchOnType(sortedAcceptValues); @@ -459,7 +459,7 @@ protected virtual MediaTypeFormatterMatch MatchRequestMediaType(HttpRequestMessa /// /// Determine whether to match on type or not. This is used to determine whether to /// generate a 406 response or use the default media type formatter in case there - /// is no match against anything in the request. If ExcludeMatchOnTypeOnly is true + /// is no match against anything in the request. If ExcludeMatchOnTypeOnly is true /// then we don't match on type unless there are no accept headers. /// /// The sorted accept header values to match. @@ -504,7 +504,7 @@ protected virtual MediaTypeFormatterMatch MatchType(Type type, MediaTypeFormatte } /// - /// Sort Accept header values and related header field values with similar syntax rules + /// Sort Accept header values and related header field values with similar syntax rules /// (if more than 1) in descending order based on q-factor. /// /// The header values to sort. @@ -529,7 +529,7 @@ protected virtual IEnumerable SortMediaTypeWith } /// - /// Sort Accept-Charset, Accept-Encoding, Accept-Language and related header field values with similar syntax rules + /// Sort Accept-Charset, Accept-Encoding, Accept-Language and related header field values with similar syntax rules /// (if more than 1) in descending order based on q-factor. /// /// The header values to sort. @@ -554,7 +554,7 @@ protected virtual IEnumerable SortStringWithQualit } /// - /// Evaluates whether a match is better than the current match and if so returns the replacement; otherwise returns the + /// Evaluates whether a match is better than the current match and if so returns the replacement; otherwise returns the /// current match. /// protected virtual MediaTypeFormatterMatch UpdateBestMatch(MediaTypeFormatterMatch current, MediaTypeFormatterMatch potentialReplacement) diff --git a/src/System.Net.Http.Formatting/Formatting/FormDataCollection.cs b/src/System.Net.Http.Formatting/Formatting/FormDataCollection.cs index 21504147b..17ce38c8e 100644 --- a/src/System.Net.Http.Formatting/Formatting/FormDataCollection.cs +++ b/src/System.Net.Http.Formatting/Formatting/FormDataCollection.cs @@ -21,9 +21,9 @@ namespace System.Net.Http.Formatting { /// /// Represent the form data. - /// - This has 100% fidelity (including ordering, which is important for deserializing ordered array). - /// - using interfaces allows us to optimize the implementation. E.g., we can avoid eagerly string-splitting a 10gb file. - /// - This also provides a convenient place to put extension methods. + /// - This has 100% fidelity (including ordering, which is important for deserializing ordered array). + /// - using interfaces allows us to optimize the implementation. E.g., we can avoid eagerly string-splitting a 10gb file. + /// - This also provides a convenient place to put extension methods. /// #if NETFX_CORE internal @@ -37,8 +37,8 @@ class FormDataCollection : IEnumerable> private NameValueCollection _nameValueCollection; /// - /// Initialize a form collection around incoming data. - /// The key value enumeration should be immutable. + /// Initialize a form collection around incoming data. + /// The key value enumeration should be immutable. /// /// incoming set of key value pairs. Ordering is preserved. [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is the convention for representing FormData")] @@ -52,8 +52,8 @@ public FormDataCollection(IEnumerable> pairs) } /// - /// Initialize a form collection from a query string. - /// Uri and FormURl body have the same schema. + /// Initialize a form collection from a query string. + /// Uri and FormURl body have the same schema. /// public FormDataCollection(Uri uri) { @@ -136,7 +136,7 @@ public NameValueCollection ReadAsNameValueCollection() } /// - /// Get values associated with a given key. If there are multiple values, they're concatenated. + /// Get values associated with a given key. If there are multiple values, they're concatenated. /// public string Get(string key) { @@ -144,7 +144,7 @@ public string Get(string key) } /// - /// Get a value associated with a given key. + /// Get a value associated with a given key. /// public string[] GetValues(string key) { diff --git a/src/System.Net.Http.Formatting/Formatting/FormUrlEncodedJson.cs b/src/System.Net.Http.Formatting/Formatting/FormUrlEncodedJson.cs index 6a295c72c..cb3d53917 100644 --- a/src/System.Net.Http.Formatting/Formatting/FormUrlEncodedJson.cs +++ b/src/System.Net.Http.Formatting/Formatting/FormUrlEncodedJson.cs @@ -13,9 +13,9 @@ namespace System.Net.Http.Formatting { /// - /// This class provides a low-level API for parsing HTML form URL-encoded data, also known as application/x-www-form-urlencoded - /// data. The output of the parser is a instance. - /// This is a low-level API intended for use by other APIs. It has been optimized for performance and + /// This class provides a low-level API for parsing HTML form URL-encoded data, also known as application/x-www-form-urlencoded + /// data. The output of the parser is a instance. + /// This is a low-level API intended for use by other APIs. It has been optimized for performance and /// is not intended to be called directly from user code. /// internal static class FormUrlEncodedJson @@ -31,7 +31,7 @@ internal static class FormUrlEncodedJson /// /// Parses a collection of query string values as a . /// - /// This is a low-level API intended for use by other APIs. It has been optimized for performance and + /// This is a low-level API intended for use by other APIs. It has been optimized for performance and /// is not intended to be called directly from user code. /// The collection of query string name-value pairs parsed in lexical order. Both names /// and values must be un-escaped so that they don't contain any encoding. @@ -44,7 +44,7 @@ public static JObject Parse(IEnumerable> nameValueP /// /// Parses a collection of query string values as a . /// - /// This is a low-level API intended for use by other APIs. It has been optimized for performance and + /// This is a low-level API intended for use by other APIs. It has been optimized for performance and /// is not intended to be called directly from user code. /// The collection of query string name-value pairs parsed in lexical order. Both names /// and values must be un-escaped so that they don't contain any encoding. @@ -58,7 +58,7 @@ public static JObject Parse(IEnumerable> nameValueP /// /// Parses a collection of query string values as a . /// - /// This is a low-level API intended for use by other APIs. It has been optimized for performance and + /// This is a low-level API intended for use by other APIs. It has been optimized for performance and /// is not intended to be called directly from user code. /// The collection of query string name-value pairs parsed in lexical order. Both names /// and values must be un-escaped so that they don't contain any encoding. @@ -72,7 +72,7 @@ public static bool TryParse(IEnumerable> nameValueP /// /// Parses a collection of query string values as a . /// - /// This is a low-level API intended for use by other APIs. It has been optimized for performance and + /// This is a low-level API intended for use by other APIs. It has been optimized for performance and /// is not intended to be called directly from user code. /// The collection of query string name-value pairs parsed in lexical order. Both names /// and values must be un-escaped so that they don't contain any encoding. @@ -87,7 +87,7 @@ public static bool TryParse(IEnumerable> nameValueP /// /// Parses a collection of query string values as a . /// - /// This is a low-level API intended for use by other APIs. It has been optimized for performance and + /// This is a low-level API intended for use by other APIs. It has been optimized for performance and /// is not intended to be called directly from user code. /// The collection of query string name-value pairs parsed in lexical order. Both names /// and values must be un-escaped so that they don't contain any encoding. @@ -112,7 +112,7 @@ private static JObject ParseInternal(IEnumerable> n string key = nameValuePair.Key; string value = nameValuePair.Value; - // value is preserved, even if it's null, "undefined", "null", String.Empty, etc when converting to JToken. + // value is preserved, even if it's null, "undefined", "null", String.Empty, etc when converting to JToken. if (key == null) { diff --git a/src/System.Net.Http.Formatting/Formatting/FormUrlEncodedMediaTypeFormatter.cs b/src/System.Net.Http.Formatting/Formatting/FormUrlEncodedMediaTypeFormatter.cs index 994ab173b..5c8d883af 100644 --- a/src/System.Net.Http.Formatting/Formatting/FormUrlEncodedMediaTypeFormatter.cs +++ b/src/System.Net.Http.Formatting/Formatting/FormUrlEncodedMediaTypeFormatter.cs @@ -13,7 +13,7 @@ namespace System.Net.Http.Formatting { /// - /// class for handling HTML form URL-ended data, also known as application/x-www-form-urlencoded. + /// class for handling HTML form URL-ended data, also known as application/x-www-form-urlencoded. /// public class FormUrlEncodedMediaTypeFormatter : MediaTypeFormatter { @@ -119,7 +119,7 @@ public override bool CanReadType(Type type) throw Error.ArgumentNull("type"); } - // Can't read arbitrary types. + // Can't read arbitrary types. return type == typeof(FormDataCollection) || FormattingUtilities.IsJTokenType(type); } @@ -193,7 +193,7 @@ private object ReadFromStream(Type type, Stream readStream) } /// - /// Reads all name-value pairs encoded as HTML Form URL encoded data and add them to + /// Reads all name-value pairs encoded as HTML Form URL encoded data and add them to /// a collection as UNescaped URI strings. /// /// Stream to read from. diff --git a/src/System.Net.Http.Formatting/Formatting/JsonMediaTypeFormatter.cs b/src/System.Net.Http.Formatting/Formatting/JsonMediaTypeFormatter.cs index 019c8feb2..23b2908bb 100644 --- a/src/System.Net.Http.Formatting/Formatting/JsonMediaTypeFormatter.cs +++ b/src/System.Net.Http.Formatting/Formatting/JsonMediaTypeFormatter.cs @@ -95,7 +95,7 @@ public static MediaTypeHeaderValue DefaultMediaType #endif /// - /// Gets or sets a value indicating whether to indent elements when writing data. + /// Gets or sets a value indicating whether to indent elements when writing data. /// public bool Indent { get; set; } diff --git a/src/System.Net.Http.Formatting/Formatting/MediaTypeFormatter.cs b/src/System.Net.Http.Formatting/Formatting/MediaTypeFormatter.cs index dd7731e1d..367fba74a 100644 --- a/src/System.Net.Http.Formatting/Formatting/MediaTypeFormatter.cs +++ b/src/System.Net.Http.Formatting/Formatting/MediaTypeFormatter.cs @@ -79,7 +79,7 @@ protected MediaTypeFormatter(MediaTypeFormatter formatter) } /// - /// Gets or sets the maximum number of keys stored in a NameValueCollection. + /// Gets or sets the maximum number of keys stored in a NameValueCollection. /// public static int MaxHttpCollectionKeys { @@ -117,7 +117,7 @@ internal List SupportedMediaTypesInternal /// /// Gets the mutable collection of character encodings supported by /// this instance. The encodings are - /// used when reading or writing data. + /// used when reading or writing data. /// public Collection SupportedEncodings { get; private set; } diff --git a/src/System.Net.Http.Formatting/Formatting/MediaTypeHeaderValueExtensions.cs b/src/System.Net.Http.Formatting/Formatting/MediaTypeHeaderValueExtensions.cs index a0cae45d0..7f58a0d18 100644 --- a/src/System.Net.Http.Formatting/Formatting/MediaTypeHeaderValueExtensions.cs +++ b/src/System.Net.Http.Formatting/Formatting/MediaTypeHeaderValueExtensions.cs @@ -17,8 +17,8 @@ internal static class MediaTypeHeaderValueExtensions /// /// Determines whether two instances match. The instance /// is said to match if and only if - /// is a strict subset of the values and parameters of . - /// That is, if the media type and media type parameters of are all present + /// is a strict subset of the values and parameters of . + /// That is, if the media type and media type parameters of are all present /// and match those of then it is a match even though may have additional /// parameters. /// @@ -34,8 +34,8 @@ public static bool IsSubsetOf(this MediaTypeHeaderValue mediaType1, MediaTypeHea /// /// Determines whether two instances match. The instance /// is said to match if and only if - /// is a strict subset of the values and parameters of . - /// That is, if the media type and media type parameters of are all present + /// is a strict subset of the values and parameters of . + /// That is, if the media type and media type parameters of are all present /// and match those of then it is a match even though may have additional /// parameters. /// @@ -75,12 +75,12 @@ public static bool IsSubsetOf(this MediaTypeHeaderValue mediaType1, MediaTypeHea } } - // So far we either have a full match or a subset match. Now check that all of + // So far we either have a full match or a subset match. Now check that all of // mediaType1's parameters are present and equal in mediatype2 // Optimize for the common case where the parameters inherit from Collection and cache the count which is faster for Collection. Collection parameters1 = mediaType1.Parameters.AsCollection(); int parameterCount1 = parameters1.Count; - Collection parameters2 = mediaType2.Parameters.AsCollection(); + Collection parameters2 = mediaType2.Parameters.AsCollection(); int parameterCount2 = parameters2.Count; for (int i = 0; i < parameterCount1; i++) { diff --git a/src/System.Net.Http.Formatting/Formatting/MediaTypeWithQualityHeaderValueComparer.cs b/src/System.Net.Http.Formatting/Formatting/MediaTypeWithQualityHeaderValueComparer.cs index 549d2272f..277759254 100644 --- a/src/System.Net.Http.Formatting/Formatting/MediaTypeWithQualityHeaderValueComparer.cs +++ b/src/System.Net.Http.Formatting/Formatting/MediaTypeWithQualityHeaderValueComparer.cs @@ -8,7 +8,7 @@ namespace System.Net.Http.Formatting { /// Implementation of that can compare accept media type header fields - /// based on their quality values (a.k.a q-values). See + /// based on their quality values (a.k.a q-values). See /// for a comparer for other content negotiation /// header field q-values. internal class MediaTypeWithQualityHeaderValueComparer : IComparer @@ -26,8 +26,8 @@ public static MediaTypeWithQualityHeaderValueComparer QualityComparer /// /// Compares two based on their quality value (a.k.a their "q-value"). - /// Values with identical q-values are considered equal (i.e the result is 0) with the exception that sub-type wild-cards are - /// considered less than specific media types and full wild-cards are considered less than sub-type wild-cards. This allows to + /// Values with identical q-values are considered equal (i.e the result is 0) with the exception that sub-type wild-cards are + /// considered less than specific media types and full wild-cards are considered less than sub-type wild-cards. This allows to /// sort a sequence of following their q-values in the order of specific media types, /// sub-type wildcards, and last any full wild-cards. /// diff --git a/src/System.Net.Http.Formatting/Formatting/ParsedMediaTypeHeaderValue.cs b/src/System.Net.Http.Formatting/Formatting/ParsedMediaTypeHeaderValue.cs index 057730391..fa1e4c259 100644 --- a/src/System.Net.Http.Formatting/Formatting/ParsedMediaTypeHeaderValue.cs +++ b/src/System.Net.Http.Formatting/Formatting/ParsedMediaTypeHeaderValue.cs @@ -40,14 +40,14 @@ public ParsedMediaTypeHeaderValue(MediaTypeHeaderValue mediaTypeHeaderValue) } } - public bool IsAllMediaRange - { - get { return _isAllMediaRange; } + public bool IsAllMediaRange + { + get { return _isAllMediaRange; } } - public bool IsSubtypeMediaRange - { - get { return _isSubtypeMediaRange; } + public bool IsSubtypeMediaRange + { + get { return _isSubtypeMediaRange; } } public bool TypesEqual(ref ParsedMediaTypeHeaderValue other) diff --git a/src/System.Net.Http.Formatting/Formatting/Parsers/FormUrlEncodedParser.cs b/src/System.Net.Http.Formatting/Formatting/Parsers/FormUrlEncodedParser.cs index d7f248d16..6a4f42024 100644 --- a/src/System.Net.Http.Formatting/Formatting/Parsers/FormUrlEncodedParser.cs +++ b/src/System.Net.Http.Formatting/Formatting/Parsers/FormUrlEncodedParser.cs @@ -11,7 +11,7 @@ namespace System.Net.Http.Formatting.Parsers { /// - /// Buffer-oriented parsing of HTML form URL-ended, also known as application/x-www-form-urlencoded, data. + /// Buffer-oriented parsing of HTML form URL-ended, also known as application/x-www-form-urlencoded, data. /// internal class FormUrlEncodedParser { @@ -54,7 +54,7 @@ private enum NameValueState /// /// Parse a buffer of URL form-encoded name-value pairs and add them to the collection. - /// Bytes are parsed in a consuming manner from the beginning of the buffer meaning that the same bytes can not be + /// Bytes are parsed in a consuming manner from the beginning of the buffer meaning that the same bytes can not be /// present in the buffer. /// /// Buffer from where data is read @@ -243,7 +243,7 @@ private ParserState CopyCurrent(ParserState parseState) } /// - /// Maintains information about the current header field being parsed. + /// Maintains information about the current header field being parsed. /// private class CurrentNameValuePair { diff --git a/src/System.Net.Http.Formatting/Formatting/Parsers/HttpRequestLineParser.cs b/src/System.Net.Http.Formatting/Formatting/Parsers/HttpRequestLineParser.cs index 027270150..b89189f8a 100644 --- a/src/System.Net.Http.Formatting/Formatting/Parsers/HttpRequestLineParser.cs +++ b/src/System.Net.Http.Formatting/Formatting/Parsers/HttpRequestLineParser.cs @@ -56,8 +56,8 @@ private enum HttpRequestLineState } /// - /// Parse an HTTP request line. - /// Bytes are parsed in a consuming manner from the beginning of the request buffer meaning that the same bytes can not be + /// Parse an HTTP request line. + /// Bytes are parsed in a consuming manner from the beginning of the request buffer meaning that the same bytes can not be /// present in the request buffer. /// /// Request buffer from where request is read diff --git a/src/System.Net.Http.Formatting/Formatting/Parsers/HttpStatusLineParser.cs b/src/System.Net.Http.Formatting/Formatting/Parsers/HttpStatusLineParser.cs index e64677e94..86f00f77d 100644 --- a/src/System.Net.Http.Formatting/Formatting/Parsers/HttpStatusLineParser.cs +++ b/src/System.Net.Http.Formatting/Formatting/Parsers/HttpStatusLineParser.cs @@ -58,8 +58,8 @@ private enum HttpStatusLineState } /// - /// Parse an HTTP status line. - /// Bytes are parsed in a consuming manner from the beginning of the response buffer meaning that the same bytes can not be + /// Parse an HTTP status line. + /// Bytes are parsed in a consuming manner from the beginning of the response buffer meaning that the same bytes can not be /// present in the response buffer. /// /// Response buffer from where response is read diff --git a/src/System.Net.Http.Formatting/Formatting/Parsers/MimeMultipartBodyPartParser.cs b/src/System.Net.Http.Formatting/Formatting/Parsers/MimeMultipartBodyPartParser.cs index 24981c209..4f135c6ed 100644 --- a/src/System.Net.Http.Formatting/Formatting/Parsers/MimeMultipartBodyPartParser.cs +++ b/src/System.Net.Http.Formatting/Formatting/Parsers/MimeMultipartBodyPartParser.cs @@ -11,7 +11,7 @@ namespace System.Net.Http.Formatting.Parsers { /// - /// Complete MIME multipart parser that combines for parsing the MIME message into individual body parts + /// Complete MIME multipart parser that combines for parsing the MIME message into individual body parts /// and for parsing each body part into a MIME header and a MIME body. The caller of the parser is returned /// the resulting MIME bodies which can then be written to some output. /// @@ -104,7 +104,7 @@ public void Dispose() } /// - /// Parses the data provided and generates parsed MIME body part bodies in the form of which are ready to + /// Parses the data provided and generates parsed MIME body part bodies in the form of which are ready to /// write to the output stream. /// /// The data to parse @@ -116,11 +116,11 @@ public IEnumerable ParseBuffer(byte[] data, int bytesRead) bool isFinal = false; // There's a special case here - if we've reached the end of the message and there's no optional - // CRLF, then we're out of bytes to read, but we have finished the message. + // CRLF, then we're out of bytes to read, but we have finished the message. // - // If IsWaitingForEndOfMessage is true and we're at the end of the stream, then we're going to - // call into the parser again with an empty array as the buffer to signal the end of the parse. - // Then the final boundary segment will be marked as complete. + // If IsWaitingForEndOfMessage is true and we're at the end of the stream, then we're going to + // call into the parser again with an empty array as the buffer to signal the end of the parse. + // Then the final boundary segment will be marked as complete. if (bytesRead == 0 && !_mimeParser.IsWaitingForEndOfMessage) { CleanupCurrentBodyPart(); @@ -195,7 +195,7 @@ public IEnumerable ParseBuffer(byte[] data, int bytesRead) } else { - // Otherwise return what we have + // Otherwise return what we have yield return _currentBodyPart; } } diff --git a/src/System.Net.Http.Formatting/Formatting/Parsers/MimeMultipartParser.cs b/src/System.Net.Http.Formatting/Formatting/Parsers/MimeMultipartParser.cs index 734124566..40b83e617 100644 --- a/src/System.Net.Http.Formatting/Formatting/Parsers/MimeMultipartParser.cs +++ b/src/System.Net.Http.Formatting/Formatting/Parsers/MimeMultipartParser.cs @@ -122,7 +122,7 @@ public enum State /// DataTooBig, } - + public bool CanParseMore(int bytesRead, int bytesConsumed) { if (bytesConsumed < bytesRead) @@ -147,7 +147,7 @@ public bool CanParseMore(int bytesRead, int bytesConsumed) /// /// Parse a MIME multipart message. Bytes are parsed in a consuming - /// manner from the beginning of the request buffer meaning that the same bytes can not be + /// manner from the beginning of the request buffer meaning that the same bytes can not be /// present in the request buffer. /// /// Request buffer from where request is read @@ -156,7 +156,7 @@ public bool CanParseMore(int bytesRead, int bytesConsumed) /// Any body part that was considered as a potential MIME multipart boundary but which was in fact part of the body. /// The bulk of the body part. /// Indicates whether the final body part has been found. - /// In order to get the complete body part, the caller is responsible for concatenating the contents of the + /// In order to get the complete body part, the caller is responsible for concatenating the contents of the /// and out parameters. /// State of the parser. [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exception is translated to parse state.")] @@ -375,7 +375,7 @@ private static State ParseBodyPart( goto quit; } } - + if (bytesConsumed > segmentStart) { if (!currentBodyPart.AppendBoundary(buffer, segmentStart, bytesConsumed - segmentStart)) @@ -391,7 +391,7 @@ private static State ParseBodyPart( case BodyPartState.AfterBoundary: // This state means that we just saw the end of a boundary. It might by a 'normal' boundary, in which - // case it's followed by optional whitespace and a CRLF. Or it might be the 'final' boundary and will + // case it's followed by optional whitespace and a CRLF. Or it might be the 'final' boundary and will // be followed by '--', optional whitespace and an optional CRLF. if (buffer[bytesConsumed] == MimeMultipartParser.Dash && !currentBodyPart.IsFinal) { @@ -456,13 +456,13 @@ private static State ParseBodyPart( { currentBodyPart.AppendBoundary(MimeMultipartParser.Dash); bytesConsumed++; - + if (currentBodyPart.IsBoundaryComplete()) { Debug.Assert(currentBodyPart.IsFinal); - // If we get in here, it means we've see the trailing '--' of the last boundary - in order to consume all of the - // remaining bytes, we don't mark the parse as complete again - wait until this method is called again with the + // If we get in here, it means we've see the trailing '--' of the last boundary - in order to consume all of the + // remaining bytes, we don't mark the parse as complete again - wait until this method is called again with the // empty buffer to do that. bodyPartState = BodyPartState.AfterBoundary; parseStatus = State.NeedMoreData; @@ -658,9 +658,9 @@ public void AppendBoundary(byte data) /// The number of bytes to append. public bool AppendBoundary(byte[] data, int offset, int count) { - // Check that potential boundary is not bigger than our reference boundary. - // Allow for 2 extra characters to include the final boundary which ends with - // an additional "--" sequence + plus up to 4 LWS characters (which are allowed). + // Check that potential boundary is not bigger than our reference boundary. + // Allow for 2 extra characters to include the final boundary which ends with + // an additional "--" sequence + plus up to 4 LWS characters (which are allowed). if (_boundaryLength + count > _referenceBoundaryLength + 6) { return false; @@ -753,7 +753,7 @@ public bool IsBoundaryComplete() { return false; } - + if (_boundaryLength < _referenceBoundaryLength) { return false; @@ -797,9 +797,9 @@ private string DebuggerToString() var boundary = Encoding.UTF8.GetString(_boundary, 0, _boundaryLength); return String.Format( - CultureInfo.InvariantCulture, - "Expected: {0} *** Current: {1}", - referenceBoundary, + CultureInfo.InvariantCulture, + "Expected: {0} *** Current: {1}", + referenceBoundary, boundary); } } diff --git a/src/System.Net.Http.Formatting/Formatting/RequestHeaderMapping.cs b/src/System.Net.Http.Formatting/Formatting/RequestHeaderMapping.cs index 3deee8ca3..845d8903d 100644 --- a/src/System.Net.Http.Formatting/Formatting/RequestHeaderMapping.cs +++ b/src/System.Net.Http.Formatting/Formatting/RequestHeaderMapping.cs @@ -23,9 +23,9 @@ public class RequestHeaderMapping : MediaTypeMapping /// Name of the header to match. /// The header value to match. /// The value comparison to use when matching . - /// if set to true then is + /// if set to true then is /// considered a match if it matches a substring of the actual header value. - /// The media type to use if and + /// The media type to use if and /// is considered a match. public RequestHeaderMapping(string headerName, string headerValue, StringComparison valueComparison, bool isValueSubstring, string mediaType) : base(mediaType) @@ -39,9 +39,9 @@ public RequestHeaderMapping(string headerName, string headerValue, StringCompari /// Name of the header to match. /// The header value to match. /// The to use when matching . - /// if set to true then is + /// if set to true then is /// considered a match if it matches a substring of the actual header value. - /// The to use if and + /// The to use if and /// is considered a match. public RequestHeaderMapping(string headerName, string headerValue, StringComparison valueComparison, bool isValueSubstring, MediaTypeHeaderValue mediaType) : base(mediaType) @@ -65,7 +65,7 @@ public RequestHeaderMapping(string headerName, string headerValue, StringCompari public StringComparison HeaderValueComparison { get; private set; } /// - /// Gets a value indicating whether is + /// Gets a value indicating whether is /// a matched as a substring of the actual header value. /// this instance is value substring. /// diff --git a/src/System.Net.Http.Formatting/Formatting/StringWithQualityHeaderValueComparer.cs b/src/System.Net.Http.Formatting/Formatting/StringWithQualityHeaderValueComparer.cs index c10caf277..6ded7c717 100644 --- a/src/System.Net.Http.Formatting/Formatting/StringWithQualityHeaderValueComparer.cs +++ b/src/System.Net.Http.Formatting/Formatting/StringWithQualityHeaderValueComparer.cs @@ -9,9 +9,9 @@ namespace System.Net.Http.Formatting { /// /// Implementation of that can compare content negotiation header fields - /// based on their quality values (a.k.a q-values). This applies to values used in accept-charset, - /// accept-encoding, accept-language and related header fields with similar syntax rules. See - /// for a comparer for media type + /// based on their quality values (a.k.a q-values). This applies to values used in accept-charset, + /// accept-encoding, accept-language and related header fields with similar syntax rules. See + /// for a comparer for media type /// q-values. /// internal class StringWithQualityHeaderValueComparer : IComparer diff --git a/src/System.Net.Http.Formatting/Formatting/XmlMediaTypeFormatter.cs b/src/System.Net.Http.Formatting/Formatting/XmlMediaTypeFormatter.cs index bec831de8..2ffd75975 100644 --- a/src/System.Net.Http.Formatting/Formatting/XmlMediaTypeFormatter.cs +++ b/src/System.Net.Http.Formatting/Formatting/XmlMediaTypeFormatter.cs @@ -67,8 +67,8 @@ protected XmlMediaTypeFormatter(XmlMediaTypeFormatter formatter) /// /// /// - /// The default media type does not have any charset parameter as - /// the can be configured on a per + /// The default media type does not have any charset parameter as + /// the can be configured on a per /// instance basis. /// /// Because is mutable, the value @@ -89,7 +89,7 @@ public static MediaTypeHeaderValue DefaultMediaType public bool UseXmlSerializer { get; set; } /// - /// Gets or sets a value indicating whether to indent elements when writing data. + /// Gets or sets a value indicating whether to indent elements when writing data. /// public bool Indent { diff --git a/src/System.Net.Http.Formatting/FormattingUtilities.cs b/src/System.Net.Http.Formatting/FormattingUtilities.cs index 220ce1d89..a1ac95595 100644 --- a/src/System.Net.Http.Formatting/FormattingUtilities.cs +++ b/src/System.Net.Http.Formatting/FormattingUtilities.cs @@ -18,7 +18,7 @@ namespace System.Net.Http internal static class FormattingUtilities { // Supported date formats for input. - private static readonly string[] dateFormats = new string[] + private static readonly string[] dateFormats = new string[] { // "r", // RFC 1123, required output format but too strict for input "ddd, d MMM yyyy H:m:s 'GMT'", // RFC 1123 (r, except it allows both 1 and 01 for date and time) @@ -134,7 +134,7 @@ public static bool IsJTokenType(Type type) } /// - /// Creates an empty instance. The only way is to get it from a dummy + /// Creates an empty instance. The only way is to get it from a dummy /// instance. /// /// The created instance. diff --git a/src/System.Net.Http.Formatting/Handlers/ProgressStream.cs b/src/System.Net.Http.Formatting/Handlers/ProgressStream.cs index fe545f9a2..8c169c94e 100644 --- a/src/System.Net.Http.Formatting/Handlers/ProgressStream.cs +++ b/src/System.Net.Http.Formatting/Handlers/ProgressStream.cs @@ -10,7 +10,7 @@ namespace System.Net.Http.Handlers { /// - /// This implementation of registers how much data has been + /// This implementation of registers how much data has been /// read (received) versus written (sent) for a particular HTTP operation. The implementation /// is client side in that the total bytes to send is taken from the request and the total /// bytes to read is taken from the response. In a server side scenario, it would be the diff --git a/src/System.Net.Http.Formatting/HttpContentFormDataExtensions.cs b/src/System.Net.Http.Formatting/HttpContentFormDataExtensions.cs index 19f5b9bc3..4a830684d 100644 --- a/src/System.Net.Http.Formatting/HttpContentFormDataExtensions.cs +++ b/src/System.Net.Http.Formatting/HttpContentFormDataExtensions.cs @@ -15,7 +15,7 @@ namespace System.Net.Http { /// - /// Extension methods to allow HTML form URL-encoded data, also known as application/x-www-form-urlencoded, + /// Extension methods to allow HTML form URL-encoded data, also known as application/x-www-form-urlencoded, /// to be read from instances. /// [EditorBrowsable(EditorBrowsableState.Never)] diff --git a/src/System.Net.Http.Formatting/HttpContentMessageExtensions.cs b/src/System.Net.Http.Formatting/HttpContentMessageExtensions.cs index a7dcb869d..99ebe4b92 100644 --- a/src/System.Net.Http.Formatting/HttpContentMessageExtensions.cs +++ b/src/System.Net.Http.Formatting/HttpContentMessageExtensions.cs @@ -126,7 +126,7 @@ public static Task ReadAsHttpRequestMessageAsync(this HttpCo /// Read the as an . /// /// The content to read. - /// The URI scheme to use for the request URI (the + /// The URI scheme to use for the request URI (the /// URI scheme is not actually part of the HTTP Request URI and so must be provided externally). /// Size of the buffer. /// A task object representing reading the content as an . @@ -140,7 +140,7 @@ public static Task ReadAsHttpRequestMessageAsync(this HttpCo /// Read the as an . /// /// The content to read. - /// The URI scheme to use for the request URI (the + /// The URI scheme to use for the request URI (the /// URI scheme is not actually part of the HTTP Request URI and so must be provided externally). /// Size of the buffer. /// The token to monitor for cancellation requests. @@ -157,7 +157,7 @@ public static Task ReadAsHttpRequestMessageAsync(this HttpCo /// Read the as an . /// /// The content to read. - /// The URI scheme to use for the request URI (the + /// The URI scheme to use for the request URI (the /// URI scheme is not actually part of the HTTP Request URI and so must be provided externally). /// Size of the buffer. /// The max length of the HTTP header. @@ -174,7 +174,7 @@ public static Task ReadAsHttpRequestMessageAsync(this HttpCo /// Read the as an . /// /// The content to read. - /// The URI scheme to use for the request URI (the + /// The URI scheme to use for the request URI (the /// URI scheme is not actually part of the HTTP Request URI and so must be provided externally). /// Size of the buffer. /// The max length of the HTTP header. diff --git a/src/System.Net.Http.Formatting/HttpContentMultipartExtensions.cs b/src/System.Net.Http.Formatting/HttpContentMultipartExtensions.cs index dce8ce8fa..e9671d5b2 100644 --- a/src/System.Net.Http.Formatting/HttpContentMultipartExtensions.cs +++ b/src/System.Net.Http.Formatting/HttpContentMultipartExtensions.cs @@ -41,9 +41,9 @@ public static bool IsMimeMultipartContent(this HttpContent content) } /// - /// Determines whether the specified content is MIME multipart content with the + /// Determines whether the specified content is MIME multipart content with the /// specified subtype. For example, the subtype mixed would match content - /// with a content type of multipart/mixed. + /// with a content type of multipart/mixed. /// /// The content. /// The MIME multipart subtype to match. @@ -91,7 +91,7 @@ public static Task ReadAsMultipartAsync(this Http /// /// Reads all body parts within a MIME multipart message using the provided instance - /// to determine where the contents of each body part is written. + /// to determine where the contents of each body part is written. /// /// The with which to process the data. /// An existing instance to use for the object's content. @@ -104,7 +104,7 @@ public static Task ReadAsMultipartAsync(this HttpContent content, T stream /// /// Reads all body parts within a MIME multipart message using the provided instance - /// to determine where the contents of each body part is written. + /// to determine where the contents of each body part is written. /// /// The with which to process the data. /// An existing instance to use for the object's content. diff --git a/src/System.Net.Http.Formatting/HttpMessageContent.cs b/src/System.Net.Http.Formatting/HttpMessageContent.cs index 1d90b16d8..d34ca72b9 100644 --- a/src/System.Net.Http.Formatting/HttpMessageContent.cs +++ b/src/System.Net.Http.Formatting/HttpMessageContent.cs @@ -357,7 +357,7 @@ private byte[] SerializeHeader() private void ValidateStreamForReading(Stream stream) { // If the content needs to be written to a target stream a 2nd time, then the stream must support - // seeking (e.g. a FileStream), otherwise the stream can't be copied a second time to a target + // seeking (e.g. a FileStream), otherwise the stream can't be copied a second time to a target // stream (e.g. a NetworkStream). if (_contentConsumed) { diff --git a/src/System.Net.Http.Formatting/Internal/HttpValueCollection.cs b/src/System.Net.Http.Formatting/Internal/HttpValueCollection.cs index 1af77650e..3197a9733 100644 --- a/src/System.Net.Http.Formatting/Internal/HttpValueCollection.cs +++ b/src/System.Net.Http.Formatting/Internal/HttpValueCollection.cs @@ -40,7 +40,7 @@ internal class HttpValueCollection : NameValueCollection internal readonly List> List = new List>(); /// - /// Creates a new instance + /// Creates a new instance /// public HttpValueCollection() { diff --git a/src/System.Net.Http.Formatting/MimeBodyPart.cs b/src/System.Net.Http.Formatting/MimeBodyPart.cs index aa14f5dc6..fcd4a7f94 100644 --- a/src/System.Net.Http.Formatting/MimeBodyPart.cs +++ b/src/System.Net.Http.Formatting/MimeBodyPart.cs @@ -39,8 +39,8 @@ public MimeBodyPart(MultipartStreamProvider streamProvider, int maxBodyPartHeade Segments = new List>(2); _headers = FormattingUtilities.CreateEmptyContentHeaders(); HeaderParser = new InternetMessageFormatHeaderParser( - _headers, - maxBodyPartHeaderSize, + _headers, + maxBodyPartHeaderSize, ignoreHeaderValidation: true); } diff --git a/src/System.Net.Http.Formatting/MultipartRelatedStreamProvider.cs b/src/System.Net.Http.Formatting/MultipartRelatedStreamProvider.cs index 464f891e7..68b5a6034 100644 --- a/src/System.Net.Http.Formatting/MultipartRelatedStreamProvider.cs +++ b/src/System.Net.Http.Formatting/MultipartRelatedStreamProvider.cs @@ -24,7 +24,7 @@ public class MultipartRelatedStreamProvider : MultipartStreamProvider private HttpContent _parent; /// - /// Gets the instance that has been marked as the root content in the + /// Gets the instance that has been marked as the root content in the /// MIME multipart related message using the start parameter. If no start parameter is /// present then pick the first of the children. /// @@ -71,7 +71,7 @@ private static HttpContent FindRootContent(HttpContent parent, IEnumerable /// A strongly-typed resource class, for looking up localized strings, etc. /// @@ -23,15 +23,15 @@ namespace System.Net.Http.Properties { [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { - + private static global::System.Resources.ResourceManager resourceMan; - + private static global::System.Globalization.CultureInfo resourceCulture; - + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal Resources() { } - + /// /// Returns the cached ResourceManager instance used by this class. /// @@ -50,7 +50,7 @@ internal Resources() { return resourceMan; } } - + /// /// Overrides the current thread's CurrentUICulture property for all /// resource lookups using this strongly typed resource class. @@ -64,7 +64,7 @@ internal Resources() { resourceCulture = value; } } - + /// /// Looks up a localized string similar to Async Callback threw an exception.. /// @@ -73,7 +73,7 @@ internal static string AsyncResult_CallbackThrewException { return ResourceManager.GetString("AsyncResult_CallbackThrewException", resourceCulture); } } - + /// /// Looks up a localized string similar to The IAsyncResult implementation '{0}' tried to complete a single operation multiple times. This could be caused by an incorrect application IAsyncResult implementation or other extensibility code, such as an IAsyncResult that returns incorrect CompletedSynchronously values or invokes the AsyncCallback multiple times.. /// @@ -82,7 +82,7 @@ internal static string AsyncResult_MultipleCompletes { return ResourceManager.GetString("AsyncResult_MultipleCompletes", resourceCulture); } } - + /// /// Looks up a localized string similar to End cannot be called twice on an AsyncResult.. /// @@ -91,7 +91,7 @@ internal static string AsyncResult_MultipleEnds { return ResourceManager.GetString("AsyncResult_MultipleEnds", resourceCulture); } } - + /// /// Looks up a localized string similar to An incorrect IAsyncResult was provided to an 'End' method. The IAsyncResult object passed to 'End' must be the one returned from the matching 'Begin' or passed to the callback provided to 'Begin'.. /// @@ -100,7 +100,7 @@ internal static string AsyncResult_ResultMismatch { return ResourceManager.GetString("AsyncResult_ResultMismatch", resourceCulture); } } - + /// /// Looks up a localized string similar to Found zero byte ranges. There must be at least one byte range provided.. /// @@ -109,7 +109,7 @@ internal static string ByteRangeStreamContentNoRanges { return ResourceManager.GetString("ByteRangeStreamContentNoRanges", resourceCulture); } } - + /// /// Looks up a localized string similar to The range unit '{0}' is not valid. The range must have a unit of '{1}'.. /// @@ -118,7 +118,7 @@ internal static string ByteRangeStreamContentNotBytesRange { return ResourceManager.GetString("ByteRangeStreamContentNotBytesRange", resourceCulture); } } - + /// /// Looks up a localized string similar to The stream over which '{0}' provides a range view must have a length greater than or equal to 1.. /// @@ -127,7 +127,7 @@ internal static string ByteRangeStreamEmpty { return ResourceManager.GetString("ByteRangeStreamEmpty", resourceCulture); } } - + /// /// Looks up a localized string similar to The 'From' value of the range must be less than or equal to {0}.. /// @@ -136,7 +136,7 @@ internal static string ByteRangeStreamInvalidFrom { return ResourceManager.GetString("ByteRangeStreamInvalidFrom", resourceCulture); } } - + /// /// Looks up a localized string similar to An attempt was made to move the position before the beginning of the stream.. /// @@ -145,7 +145,7 @@ internal static string ByteRangeStreamInvalidOffset { return ResourceManager.GetString("ByteRangeStreamInvalidOffset", resourceCulture); } } - + /// /// Looks up a localized string similar to None of the requested ranges ({0}) overlap with the current extent of the selected resource.. /// @@ -154,7 +154,7 @@ internal static string ByteRangeStreamNoneOverlap { return ResourceManager.GetString("ByteRangeStreamNoneOverlap", resourceCulture); } } - + /// /// Looks up a localized string similar to The requested range ({0}) does not overlap with the current extent of the selected resource.. /// @@ -163,7 +163,7 @@ internal static string ByteRangeStreamNoOverlap { return ResourceManager.GetString("ByteRangeStreamNoOverlap", resourceCulture); } } - + /// /// Looks up a localized string similar to The stream over which '{0}' provides a range view must be seekable.. /// @@ -172,7 +172,7 @@ internal static string ByteRangeStreamNotSeekable { return ResourceManager.GetString("ByteRangeStreamNotSeekable", resourceCulture); } } - + /// /// Looks up a localized string similar to This is a read-only stream.. /// @@ -181,7 +181,7 @@ internal static string ByteRangeStreamReadOnly { return ResourceManager.GetString("ByteRangeStreamReadOnly", resourceCulture); } } - + /// /// Looks up a localized string similar to A null '{0}' is not valid.. /// @@ -190,7 +190,7 @@ internal static string CannotHaveNullInList { return ResourceManager.GetString("CannotHaveNullInList", resourceCulture); } } - + /// /// Looks up a localized string similar to The '{0}' of '{1}' cannot be used as a supported media type because it is a media range.. /// @@ -199,7 +199,7 @@ internal static string CannotUseMediaRangeForSupportedMediaType { return ResourceManager.GetString("CannotUseMediaRangeForSupportedMediaType", resourceCulture); } } - + /// /// Looks up a localized string similar to The '{0}' type cannot accept a null value for the value type '{1}'.. /// @@ -208,7 +208,7 @@ internal static string CannotUseNullValueType { return ResourceManager.GetString("CannotUseNullValueType", resourceCulture); } } - + /// /// Looks up a localized string similar to The specified value is not a valid cookie name.. /// @@ -217,7 +217,7 @@ internal static string CookieInvalidName { return ResourceManager.GetString("CookieInvalidName", resourceCulture); } } - + /// /// Looks up a localized string similar to Cookie cannot be null.. /// @@ -226,7 +226,7 @@ internal static string CookieNull { return ResourceManager.GetString("CookieNull", resourceCulture); } } - + /// /// Looks up a localized string similar to The '{0}' list is invalid because it contains one or more null items.. /// @@ -235,7 +235,7 @@ internal static string DelegatingHandlerArrayContainsNullItem { return ResourceManager.GetString("DelegatingHandlerArrayContainsNullItem", resourceCulture); } } - + /// /// Looks up a localized string similar to The '{0}' list is invalid because the property '{1}' of '{2}' is not null.. /// @@ -244,7 +244,7 @@ internal static string DelegatingHandlerArrayHasNonNullInnerHandler { return ResourceManager.GetString("DelegatingHandlerArrayHasNonNullInnerHandler", resourceCulture); } } - + /// /// Looks up a localized string similar to Error reading HTML form URL-encoded data stream.. /// @@ -253,7 +253,7 @@ internal static string ErrorReadingFormUrlEncodedStream { return ResourceManager.GetString("ErrorReadingFormUrlEncodedStream", resourceCulture); } } - + /// /// Looks up a localized string similar to Mismatched types at node '{0}'.. /// @@ -262,7 +262,7 @@ internal static string FormUrlEncodedMismatchingTypes { return ResourceManager.GetString("FormUrlEncodedMismatchingTypes", resourceCulture); } } - + /// /// Looks up a localized string similar to Error parsing HTML form URL-encoded data, byte {0}.. /// @@ -271,7 +271,7 @@ internal static string FormUrlEncodedParseError { return ResourceManager.GetString("FormUrlEncodedParseError", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid HTTP status code: '{0}'. The status code must be between {1} and {2}.. /// @@ -280,7 +280,7 @@ internal static string HttpInvalidStatusCode { return ResourceManager.GetString("HttpInvalidStatusCode", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid HTTP version: '{0}'. The version must start with the characters '{1}'.. /// @@ -289,7 +289,7 @@ internal static string HttpInvalidVersion { return ResourceManager.GetString("HttpInvalidVersion", resourceCulture); } } - + /// /// Looks up a localized string similar to The '{0}' of the '{1}' has already been read.. /// @@ -298,7 +298,7 @@ internal static string HttpMessageContentAlreadyRead { return ResourceManager.GetString("HttpMessageContentAlreadyRead", resourceCulture); } } - + /// /// Looks up a localized string similar to The '{0}' must be seekable in order to create an '{1}' instance containing an entity body. . /// @@ -307,7 +307,7 @@ internal static string HttpMessageContentStreamMustBeSeekable { return ResourceManager.GetString("HttpMessageContentStreamMustBeSeekable", resourceCulture); } } - + /// /// Looks up a localized string similar to Error reading HTTP message.. /// @@ -316,7 +316,7 @@ internal static string HttpMessageErrorReading { return ResourceManager.GetString("HttpMessageErrorReading", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid '{0}' instance provided. It does not have a content type header with a value of '{1}'.. /// @@ -325,7 +325,7 @@ internal static string HttpMessageInvalidMediaType { return ResourceManager.GetString("HttpMessageInvalidMediaType", resourceCulture); } } - + /// /// Looks up a localized string similar to HTTP Request URI cannot be an empty string.. /// @@ -334,7 +334,7 @@ internal static string HttpMessageParserEmptyUri { return ResourceManager.GetString("HttpMessageParserEmptyUri", resourceCulture); } } - + /// /// Looks up a localized string similar to Error parsing HTTP message header byte {0} of message {1}.. /// @@ -343,7 +343,7 @@ internal static string HttpMessageParserError { return ResourceManager.GetString("HttpMessageParserError", resourceCulture); } } - + /// /// Looks up a localized string similar to An invalid number of '{0}' header fields were present in the HTTP Request. It must contain exactly one '{0}' header field but found {1}.. /// @@ -352,7 +352,7 @@ internal static string HttpMessageParserInvalidHostCount { return ResourceManager.GetString("HttpMessageParserInvalidHostCount", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid URI scheme: '{0}'. The URI scheme must be a valid '{1}' scheme.. /// @@ -361,7 +361,7 @@ internal static string HttpMessageParserInvalidUriScheme { return ResourceManager.GetString("HttpMessageParserInvalidUriScheme", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid array at node '{0}'.. /// @@ -370,7 +370,7 @@ internal static string InvalidArrayInsert { return ResourceManager.GetString("InvalidArrayInsert", resourceCulture); } } - + /// /// Looks up a localized string similar to Traditional style array without '[]' is not supported with nested object at location {0}.. /// @@ -379,7 +379,7 @@ internal static string JQuery13CompatModeNotSupportNestedJson { return ResourceManager.GetString("JQuery13CompatModeNotSupportNestedJson", resourceCulture); } } - + /// /// Looks up a localized string similar to The '{0}' method returned null. It must return a JSON serializer instance.. /// @@ -388,7 +388,7 @@ internal static string JsonSerializerFactoryReturnedNull { return ResourceManager.GetString("JsonSerializerFactoryReturnedNull", resourceCulture); } } - + /// /// Looks up a localized string similar to The '{0}' method threw an exception when attempting to create a JSON serializer.. /// @@ -397,7 +397,7 @@ internal static string JsonSerializerFactoryThrew { return ResourceManager.GetString("JsonSerializerFactoryThrew", resourceCulture); } } - + /// /// Looks up a localized string similar to The maximum read depth ({0}) has been exceeded because the form url-encoded data being read has more levels of nesting than is allowed.. /// @@ -406,7 +406,7 @@ internal static string MaxDepthExceeded { return ResourceManager.GetString("MaxDepthExceeded", resourceCulture); } } - + /// /// Looks up a localized string similar to The number of keys in a NameValueCollection has exceeded the limit of '{0}'. You can adjust it by modifying the MaxHttpCollectionKeys property on the '{1}' class.. /// @@ -415,7 +415,7 @@ internal static string MaxHttpCollectionKeyLimitReached { return ResourceManager.GetString("MaxHttpCollectionKeyLimitReached", resourceCulture); } } - + /// /// Looks up a localized string similar to Error parsing BSON data; unable to read content as a {0}.. /// @@ -424,7 +424,7 @@ internal static string MediaTypeFormatter_BsonParseError_MissingData { return ResourceManager.GetString("MediaTypeFormatter_BsonParseError_MissingData", resourceCulture); } } - + /// /// Looks up a localized string similar to Error parsing BSON data; unexpected dictionary content: {0} entries, first key '{1}'.. /// @@ -433,7 +433,7 @@ internal static string MediaTypeFormatter_BsonParseError_UnexpectedData { return ResourceManager.GetString("MediaTypeFormatter_BsonParseError_UnexpectedData", resourceCulture); } } - + /// /// Looks up a localized string similar to The '{0}' method returned null. It must return a JSON reader instance.. /// @@ -442,7 +442,7 @@ internal static string MediaTypeFormatter_JsonReaderFactoryReturnedNull { return ResourceManager.GetString("MediaTypeFormatter_JsonReaderFactoryReturnedNull", resourceCulture); } } - + /// /// Looks up a localized string similar to The '{0}' method returned null. It must return a JSON writer instance.. /// @@ -451,7 +451,7 @@ internal static string MediaTypeFormatter_JsonWriterFactoryReturnedNull { return ResourceManager.GetString("MediaTypeFormatter_JsonWriterFactoryReturnedNull", resourceCulture); } } - + /// /// Looks up a localized string similar to The media type formatter of type '{0}' does not support reading because it does not implement the ReadFromStreamAsync method.. /// @@ -460,7 +460,7 @@ internal static string MediaTypeFormatterCannotRead { return ResourceManager.GetString("MediaTypeFormatterCannotRead", resourceCulture); } } - + /// /// Looks up a localized string similar to The media type formatter of type '{0}' does not support reading because it does not implement the ReadFromStream method.. /// @@ -469,7 +469,7 @@ internal static string MediaTypeFormatterCannotReadSync { return ResourceManager.GetString("MediaTypeFormatterCannotReadSync", resourceCulture); } } - + /// /// Looks up a localized string similar to The media type formatter of type '{0}' does not support writing because it does not implement the WriteToStreamAsync method.. /// @@ -478,7 +478,7 @@ internal static string MediaTypeFormatterCannotWrite { return ResourceManager.GetString("MediaTypeFormatterCannotWrite", resourceCulture); } } - + /// /// Looks up a localized string similar to The media type formatter of type '{0}' does not support writing because it does not implement the WriteToStream method.. /// @@ -487,7 +487,7 @@ internal static string MediaTypeFormatterCannotWriteSync { return ResourceManager.GetString("MediaTypeFormatterCannotWriteSync", resourceCulture); } } - + /// /// Looks up a localized string similar to No encoding found for media type formatter '{0}'. There must be at least one supported encoding registered in order for the media type formatter to read or write content.. /// @@ -496,7 +496,7 @@ internal static string MediaTypeFormatterNoEncoding { return ResourceManager.GetString("MediaTypeFormatterNoEncoding", resourceCulture); } } - + /// /// Looks up a localized string similar to MIME multipart boundary cannot end with an empty space.. /// @@ -505,7 +505,7 @@ internal static string MimeMultipartParserBadBoundary { return ResourceManager.GetString("MimeMultipartParserBadBoundary", resourceCulture); } } - + /// /// Looks up a localized string similar to Did not find required '{0}' header field in MIME multipart body part.. /// @@ -514,7 +514,7 @@ internal static string MultipartFormDataStreamProviderNoContentDisposition { return ResourceManager.GetString("MultipartFormDataStreamProviderNoContentDisposition", resourceCulture); } } - + /// /// Looks up a localized string similar to Could not determine a valid local file name for the multipart body part.. /// @@ -523,7 +523,7 @@ internal static string MultipartStreamProviderInvalidLocalFileName { return ResourceManager.GetString("MultipartStreamProviderInvalidLocalFileName", resourceCulture); } } - + /// /// Looks up a localized string similar to Nested bracket is not valid for '{0}' data at position {1}.. /// @@ -532,7 +532,7 @@ internal static string NestedBracketNotValid { return ResourceManager.GetString("NestedBracketNotValid", resourceCulture); } } - + /// /// Looks up a localized string similar to A non-null request URI must be provided to determine if a '{0}' matches a given request or response message.. /// @@ -541,7 +541,7 @@ internal static string NonNullUriRequiredForMediaTypeMapping { return ResourceManager.GetString("NonNullUriRequiredForMediaTypeMapping", resourceCulture); } } - + /// /// Looks up a localized string similar to No MediaTypeFormatter is available to read an object of type '{0}' from content with media type '{1}'.. /// @@ -550,7 +550,7 @@ internal static string NoReadSerializerAvailable { return ResourceManager.GetString("NoReadSerializerAvailable", resourceCulture); } } - + /// /// Looks up a localized string similar to An object of type '{0}' cannot be used with a type parameter of '{1}'.. /// @@ -559,7 +559,7 @@ internal static string ObjectAndTypeDisagree { return ResourceManager.GetString("ObjectAndTypeDisagree", resourceCulture); } } - + /// /// Looks up a localized string similar to The configured formatter '{0}' cannot write an object of type '{1}'.. /// @@ -568,7 +568,7 @@ internal static string ObjectContent_FormatterCannotWriteType { return ResourceManager.GetString("ObjectContent_FormatterCannotWriteType", resourceCulture); } } - + /// /// Looks up a localized string similar to Query string name cannot be null.. /// @@ -577,7 +577,7 @@ internal static string QueryStringNameShouldNotNull { return ResourceManager.GetString("QueryStringNameShouldNotNull", resourceCulture); } } - + /// /// Looks up a localized string similar to Unexpected end of HTTP message stream. HTTP message is not complete.. /// @@ -586,7 +586,7 @@ internal static string ReadAsHttpMessageUnexpectedTermination { return ResourceManager.GetString("ReadAsHttpMessageUnexpectedTermination", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid '{0}' instance provided. It does not have a '{1}' content-type header with a '{2}' parameter.. /// @@ -595,7 +595,7 @@ internal static string ReadAsMimeMultipartArgumentNoBoundary { return ResourceManager.GetString("ReadAsMimeMultipartArgumentNoBoundary", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid '{0}' instance provided. It does not have a content-type header value. '{0}' instances must have a content-type header starting with '{1}'.. /// @@ -604,7 +604,7 @@ internal static string ReadAsMimeMultipartArgumentNoContentType { return ResourceManager.GetString("ReadAsMimeMultipartArgumentNoContentType", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid '{0}' instance provided. It does not have a content type header starting with '{1}'.. /// @@ -613,7 +613,7 @@ internal static string ReadAsMimeMultipartArgumentNoMultipart { return ResourceManager.GetString("ReadAsMimeMultipartArgumentNoMultipart", resourceCulture); } } - + /// /// Looks up a localized string similar to Error reading MIME multipart body part.. /// @@ -622,7 +622,7 @@ internal static string ReadAsMimeMultipartErrorReading { return ResourceManager.GetString("ReadAsMimeMultipartErrorReading", resourceCulture); } } - + /// /// Looks up a localized string similar to Error writing MIME multipart body part to output stream.. /// @@ -631,7 +631,7 @@ internal static string ReadAsMimeMultipartErrorWriting { return ResourceManager.GetString("ReadAsMimeMultipartErrorWriting", resourceCulture); } } - + /// /// Looks up a localized string similar to Error parsing MIME multipart body part header byte {0} of data segment {1}.. /// @@ -640,7 +640,7 @@ internal static string ReadAsMimeMultipartHeaderParseError { return ResourceManager.GetString("ReadAsMimeMultipartHeaderParseError", resourceCulture); } } - + /// /// Looks up a localized string similar to Error parsing MIME multipart message byte {0} of data segment {1}.. /// @@ -649,7 +649,7 @@ internal static string ReadAsMimeMultipartParseError { return ResourceManager.GetString("ReadAsMimeMultipartParseError", resourceCulture); } } - + /// /// Looks up a localized string similar to The stream provider of type '{0}' threw an exception.. /// @@ -658,7 +658,7 @@ internal static string ReadAsMimeMultipartStreamProviderException { return ResourceManager.GetString("ReadAsMimeMultipartStreamProviderException", resourceCulture); } } - + /// /// Looks up a localized string similar to The stream provider of type '{0}' returned null. It must return a writable '{1}' instance.. /// @@ -667,7 +667,7 @@ internal static string ReadAsMimeMultipartStreamProviderNull { return ResourceManager.GetString("ReadAsMimeMultipartStreamProviderNull", resourceCulture); } } - + /// /// Looks up a localized string similar to The stream provider of type '{0}' returned a read-only stream. It must return a writable '{1}' instance.. /// @@ -676,7 +676,7 @@ internal static string ReadAsMimeMultipartStreamProviderReadOnly { return ResourceManager.GetString("ReadAsMimeMultipartStreamProviderReadOnly", resourceCulture); } } - + /// /// Looks up a localized string similar to Unexpected end of MIME multipart stream. MIME multipart message is not complete.. /// @@ -685,7 +685,7 @@ internal static string ReadAsMimeMultipartUnexpectedTermination { return ResourceManager.GetString("ReadAsMimeMultipartUnexpectedTermination", resourceCulture); } } - + /// /// Looks up a localized string similar to The '{0}' method in '{1}' returned null. It must return a RemoteStreamResult instance containing a writable stream and a valid URL.. /// @@ -694,7 +694,7 @@ internal static string RemoteStreamInfoCannotBeNull { return ResourceManager.GetString("RemoteStreamInfoCannotBeNull", resourceCulture); } } - + /// /// Looks up a localized string similar to The '{0}' serializer cannot serialize the type '{1}'.. /// @@ -703,7 +703,7 @@ internal static string SerializerCannotSerializeType { return ResourceManager.GetString("SerializerCannotSerializeType", resourceCulture); } } - + /// /// Looks up a localized string similar to There is an unmatched opened bracket for the '{0}' at position {1}.. /// @@ -712,7 +712,7 @@ internal static string UnMatchedBracketNotValid { return ResourceManager.GetString("UnMatchedBracketNotValid", resourceCulture); } } - + /// /// Looks up a localized string similar to Indentation is not supported by '{0}'.. /// @@ -721,7 +721,7 @@ internal static string UnsupportedIndent { return ResourceManager.GetString("UnsupportedIndent", resourceCulture); } } - + /// /// Looks up a localized string similar to The object of type '{0}' returned by {1} must be an instance of either XmlObjectSerializer or XmlSerializer.. /// @@ -730,7 +730,7 @@ internal static string XmlMediaTypeFormatter_InvalidSerializerType { return ResourceManager.GetString("XmlMediaTypeFormatter_InvalidSerializerType", resourceCulture); } } - + /// /// Looks up a localized string similar to The object returned by {0} must not be a null value.. /// diff --git a/test/System.Web.WebPages.Test/ApplicationParts/ApplicationPartTest.cs b/test/System.Web.WebPages.Test/ApplicationParts/ApplicationPartTest.cs index 742da8aee..8ff5ea3a9 100644 --- a/test/System.Web.WebPages.Test/ApplicationParts/ApplicationPartTest.cs +++ b/test/System.Web.WebPages.Test/ApplicationParts/ApplicationPartTest.cs @@ -70,7 +70,7 @@ public void GetResourceNameFromVirtualPathForTopLevelPath() var moduleName = "my-module"; var path = "foo.baz"; - // Act + // Act var name = ApplicationPart.GetResourceNameFromVirtualPath(moduleName, path); // Assert @@ -84,7 +84,7 @@ public void GetResourceNameFromVirtualPathForItemInSubDir() var moduleName = "my-module"; var path = "/bar/foo"; - // Act + // Act var name = ApplicationPart.GetResourceNameFromVirtualPath(moduleName, path); // Assert @@ -98,7 +98,7 @@ public void GetResourceNameFromVirtualPathForItemWithSpaces() var moduleName = "my-module"; var path = "/program files/data files/my file .foo"; - // Act + // Act var name = ApplicationPart.GetResourceNameFromVirtualPath(moduleName, path); // Assert diff --git a/tools/WebStack.tasks.targets b/tools/WebStack.tasks.targets index fbebe6774..cf88c574c 100644 --- a/tools/WebStack.tasks.targets +++ b/tools/WebStack.tasks.targets @@ -30,6 +30,7 @@ if (!Version.TryParse(MinimumVersion, out minimumRequiredVersion)) { Log.LogError("MinimumVersion '{0}' is not a valid Version.", MinimumVersion); + return false; } try @@ -74,7 +75,7 @@ if (!File.Exists(OutputFileName)) { - Log.LogMessage("Downloading latest version of NuGet.exe..."); + Log.LogMessage(MessageImportance.High, "Downloading latest version of NuGet.exe..."); WebClient webClient = new WebClient(); webClient.DownloadFile("https://dist.nuget.org/win-x86-commandline/latest/nuget.exe", OutputFileName); } @@ -91,58 +92,6 @@ - - - - - - - - - - - - - - - - - - - - @@ -154,13 +103,18 @@ + + + + [0-9A-Fa-f]+);", + RegexOptions.Multiline | RegexOptions.Compiled); int testsPassed = 0; int testsFailed = 0; int testsSkipped = 0; @@ -169,8 +123,20 @@ foreach (string testResultFile in testResultFiles) { + // Replace potentially illegal escaped characters (if they get through validations done during Save). + string fullPath = Path.GetFullPath(testResultFile); + string originalText = File.ReadAllText(fullPath); + bool matched = regex.IsMatch(originalText); + + if (matched) + { + File.SetAttributes(fullPath, File.GetAttributes(fullPath) & ~FileAttributes.ReadOnly); + File.WriteAllText(fullPath, regex.Replace(originalText, "\0x${char}"), Encoding.UTF8); + } + + // Collect test failure information from results file. XElement xml; - using (FileStream fileStream = File.OpenRead(testResultFile)) + using (FileStream fileStream = File.OpenRead(fullPath)) { xml = XElement.Load(fileStream); } @@ -213,23 +179,32 @@ } } + // Log all test failures. if (testFailures.Count > 0) { - Console.WriteLine(); - Console.WriteLine(" Test Failures:"); - ConsoleColor originalColor = Console.ForegroundColor; - Console.ForegroundColor = ConsoleColor.Red; + Log.LogMessage(MessageImportance.High, string.Empty); + Log.LogError("Tests failed..."); foreach (string testFailure in testFailures) { - Console.WriteLine(" " + testFailure); + // Provide the list of failed tests but don't repeat it in the build summary. List + // is usually less helpful than errors from tests themselves (which are repeated) + // because those errors include the exact failure locations. On the other hand, + // this is more compact. + Log.LogMessage(MessageImportance.High, testFailure); } - Console.ForegroundColor = originalColor; } - Console.WriteLine(); - Console.WriteLine(" Tests passed: {0}, Tests failed: {1}, Tests skipped: {2}", testsPassed, testsFailed, testsSkipped); - Console.WriteLine(" Time spent running tests: {0} seconds", timeSpent); - return true; + // Log summary of all results. + Log.LogMessage(MessageImportance.High, string.Empty); + Log.LogMessage(MessageImportance.High, + "Tests passed: {0}, Tests failed: {1}, Tests skipped: {2}", + testsPassed, + testsFailed, + testsSkipped); + Log.LogMessage(MessageImportance.High, + "Time spent running tests: {0} seconds", timeSpent); + + return !Log.HasLoggedErrors; } catch (Exception ex) { @@ -240,4 +215,4 @@ - \ No newline at end of file + diff --git a/tools/WebStack.xunit.targets b/tools/WebStack.xunit.targets index 3392c1dde..d11eaee74 100644 --- a/tools/WebStack.xunit.targets +++ b/tools/WebStack.xunit.targets @@ -1,18 +1,17 @@ - + + - - + + + + - - - - - - - \ No newline at end of file + + <_ExitCodes Include="$(TestAssembly)" Code="$(_ExitCode)" /> + + + From d2c666066d9f13beaf47f42e99b8ac617cda44dd Mon Sep 17 00:00:00 2001 From: Doug Bunting <6431421+dougbu@users.noreply.github.com> Date: Wed, 23 Nov 2022 17:55:12 -0800 Subject: [PATCH 26/54] Bump Newtonsoft.Json to 13.0.1 (#369) * Bump Newtonsoft.Json to 13.0.1 - also bump Newtonsoft.Json.Bson to 1.0.2 in System.Net.Http.Formatting.NetStandard - incorporates changes from 23 Dependabot PRs; they are now obsolete - Dependabot also left `@(Reference)` items alone in project files :frowning: - fixed what Dependabot didn't do i.e. corrected paths and assembly identities in those items
Release notes

Sourced from Newtonsoft.Json's releases.

13.0.1

  • New feature - Add JsonSelectSettings with configuration for a regex timeout
  • Change - Remove portable assemblies from NuGet package
  • Change - JsonReader and JsonSerializer MaxDepth defaults to 64
  • Fix - Fixed throwing missing member error on ignored fields
  • Fix - Fixed various nullable annotations
  • Fix - Fixed annotations not being copied when tokens are cloned
  • Fix - Fixed naming strategy not being used when deserializing dictionary enum keys
  • Fix - Fixed serializing nullable struct dictionaries
  • Fix - Fixed JsonWriter.WriteToken to allow null with string token
  • Fix - Fixed missing error when deserializing JToken with a contract type mismatch
  • Fix - Fixed JTokenWriter when writing comment to an object

12.0.3

  • New feature - Added support for nullable reference types
  • New feature - Added KebabCaseNamingStrategy
  • Change - Package now uses embedded package icon
  • Fix - Fixed bug when merging JToken with itself
  • Fix - Fixed performance of calling ICustomTypeDescriptor.GetProperties
  • Fix - Fixed serializing Enumerable.Empty and empty arrays on .NET Core 3.0
  • Fix - Fixed deserializing some collection types with constructor
  • Fix - Fixed deserializing IImmutableSet to ImmutableHashSet instead of ImmutableSortedSet
  • Fix - Fixed deserializing IImmutableDictionary to ImmutableDictionary instead of ImmutableSortedDictionary
  • Fix - Fixed deserializing into constructors with more than 256 parameters
  • Fix - Fixed hang when deserializing JTokenReader with preceding comment
  • Fix - Fixed JSONPath scanning with nested indexer
  • Fix - Fixed deserializing incomplete JSON object to JObject
  • Fix - Fixed using StringEnumConverter with naming strategy and specified values

12.0.2

  • New feature - Added MissingMemberHandling to JsonObjectAttribute and JsonObjectContract
  • New feature - Added constructor to JTokenReader to specify initial path
  • New feature - Added JsonProperty.IsRequiredSpecified
  • New feature - Added JsonContract.InternalConverter
  • Change - Moved embedded debug symbols in NuGet package to a symbol package on NuGet.org
  • Fix - Fixed deserializing nullable struct collections
  • Fix - Fixed memory link when serializing enums to named values
  • Fix - Fixed error when setting JsonLoadSettings.DuplicatePropertyNameHandling to Replace

12.0.1

  • New feature - Added NuGet package signing
  • New feature - Added Authenticode assembly signing
  • New feature - Added SourceLink support
  • New feature - Added constructors to StringEnumConverter for setting AllowIntegerValue
  • New feature - Added JsonNameTable and JsonTextReader.PropertyNameTable
  • New feature - Added line information to JsonSerializationException
  • New feature - Added JObject.Property overload with a StringComparison
  • New feature - Added JsonMergeSettings.PropertyNameComparison
  • New feature - Added support for multiple Date constructors with JavaScriptDateTimeConverter
  • New feature - Added support for strict equals and strict not equals in JSON Path queries

... (truncated)

Commits
* React to Newtonsoft.Json changes - react to `BsonReader`, `BsonWriter` deprecation - one of our `DateTime` tests now consistently hits `5` errors - `s/True/true/` also consistent now in another test - `decimal` overflow now `throw`s a `JsonReaderException` * Remove Newtonsoft.Json binding redirects - where possible, entirely remove app.config files - w/ consistent Newtonsoft.Json versions, these special cases are mostly not needed - auto-generation of .config file handles the special case just fine in System.Net.Http.Formatting.NetStandard.Test.csproj and System.Web.Http.SignalR.Test.csproj --- .../Microsoft.AspNet.Facebook.csproj | 4 ++-- src/Microsoft.AspNet.Facebook/packages.config | 2 +- .../System.Net.Http.Formatting.NetCore.csproj | 4 ++-- .../packages.config | 2 +- .../System.Net.Http.Formatting.NetStandard.csproj | 4 ++-- .../Formatting/BsonMediaTypeFormatter.cs | 12 ++++++++++++ .../System.Net.Http.Formatting.csproj | 4 ++-- src/System.Net.Http.Formatting/packages.config | 2 +- .../System.Web.Http.SignalR.csproj | 4 ++-- src/System.Web.Http.SignalR/packages.config | 2 +- .../System.Web.Http.Tracing.csproj | 4 ++-- src/System.Web.Http.Tracing/packages.config | 2 +- src/System.Web.Http/System.Web.Http.csproj | 4 ++-- src/System.Web.Http/packages.config | 2 +- src/WebApiHelpPage/VB/WebApiHelpPageVB.vbproj | 4 ++-- src/WebApiHelpPage/VB/packages.config | 2 +- src/WebApiHelpPage/WebApiHelpPage.csproj | 4 ++-- src/WebApiHelpPage/packages.config | 2 +- test/Microsoft.AspNet.Facebook.Test/App.config | 8 -------- .../Microsoft.AspNet.Facebook.Test.csproj | 6 +++--- test/Microsoft.AspNet.Facebook.Test/packages.config | 2 +- .../Microsoft.Web.Mvc.Test.csproj | 5 ++--- test/Microsoft.Web.Mvc.Test/app.config | 11 ----------- test/Microsoft.Web.Mvc.Test/packages.config | 2 +- .../System.Net.Http.Formatting.NetCore.Test.csproj | 4 ++-- .../app.config | 4 ---- .../packages.config | 2 +- ...ystem.Net.Http.Formatting.NetStandard.Test.csproj | 3 --- .../app.config | 11 ----------- .../Formatting/BsonMediaTypeFormatterTests.cs | 4 ++-- .../Formatting/JsonNetValidationTest.cs | 10 +--------- .../System.Net.Http.Formatting.Test.csproj | 5 ++--- test/System.Net.Http.Formatting.Test/app.config | 11 ----------- test/System.Net.Http.Formatting.Test/packages.config | 2 +- .../System.Web.Http.Cors.Test.csproj | 5 ++--- test/System.Web.Http.Cors.Test/app.config | 11 ----------- test/System.Web.Http.Cors.Test/packages.config | 2 +- .../System.Web.Http.Integration.Test.csproj | 5 ++--- test/System.Web.Http.Integration.Test/app.config | 11 ----------- .../System.Web.Http.Integration.Test/packages.config | 2 +- .../System.Web.Http.Owin.Test.csproj | 5 ++--- test/System.Web.Http.Owin.Test/app.config | 11 ----------- test/System.Web.Http.Owin.Test/packages.config | 2 +- .../System.Web.Http.SelfHost.Test.csproj | 5 ++--- test/System.Web.Http.SelfHost.Test/app.config | 11 ----------- test/System.Web.Http.SelfHost.Test/packages.config | 2 +- .../System.Web.Http.SignalR.Test.csproj | 5 ++--- test/System.Web.Http.SignalR.Test/app.config | 11 ----------- test/System.Web.Http.SignalR.Test/packages.config | 2 +- .../System.Web.Http.Test/System.Web.Http.Test.csproj | 5 ++--- .../Tracers/FormatterParameterBindingTracerTest.cs | 2 +- test/System.Web.Http.Test/app.config | 11 ----------- test/System.Web.Http.Test/packages.config | 2 +- .../System.Web.Http.Tracing.Test.csproj | 7 +++---- test/System.Web.Http.Tracing.Test/app.config | 11 ----------- test/System.Web.Http.Tracing.Test/packages.config | 2 +- .../System.Web.Http.WebHost.Test.csproj | 5 ++--- test/System.Web.Http.WebHost.Test/app.config | 11 ----------- test/System.Web.Http.WebHost.Test/packages.config | 2 +- test/System.Web.Mvc.Test/System.Web.Mvc.Test.csproj | 5 ++--- test/System.Web.Mvc.Test/app.config | 11 ----------- test/System.Web.Mvc.Test/packages.config | 2 +- test/WebApiHelpPage.Test/WebApiHelpPage.Test.csproj | 7 +++---- test/WebApiHelpPage.Test/app.config | 11 ----------- test/WebApiHelpPage.Test/packages.config | 2 +- .../WebApiHelpPage.VB.Test.csproj | 9 +++------ 66 files changed, 90 insertions(+), 259 deletions(-) delete mode 100644 test/Microsoft.Web.Mvc.Test/app.config delete mode 100644 test/System.Net.Http.Formatting.NetStandard.Test/app.config delete mode 100644 test/System.Net.Http.Formatting.Test/app.config delete mode 100644 test/System.Web.Http.Cors.Test/app.config delete mode 100644 test/System.Web.Http.Integration.Test/app.config delete mode 100644 test/System.Web.Http.Owin.Test/app.config delete mode 100644 test/System.Web.Http.SelfHost.Test/app.config delete mode 100644 test/System.Web.Http.SignalR.Test/app.config delete mode 100644 test/System.Web.Http.Test/app.config delete mode 100644 test/System.Web.Http.Tracing.Test/app.config delete mode 100644 test/System.Web.Http.WebHost.Test/app.config delete mode 100644 test/System.Web.Mvc.Test/app.config delete mode 100644 test/WebApiHelpPage.Test/app.config diff --git a/src/Microsoft.AspNet.Facebook/Microsoft.AspNet.Facebook.csproj b/src/Microsoft.AspNet.Facebook/Microsoft.AspNet.Facebook.csproj index 7e0f0f6ba..12642c354 100644 --- a/src/Microsoft.AspNet.Facebook/Microsoft.AspNet.Facebook.csproj +++ b/src/Microsoft.AspNet.Facebook/Microsoft.AspNet.Facebook.csproj @@ -26,8 +26,8 @@ False ..\..\packages\Facebook.6.4.2\lib\net45\Facebook.dll - - ..\..\packages\Newtonsoft.Json.6.0.4\lib\net45\Newtonsoft.Json.dll + + ..\..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll False False diff --git a/src/Microsoft.AspNet.Facebook/packages.config b/src/Microsoft.AspNet.Facebook/packages.config index 613e222f9..102ce84aa 100644 --- a/src/Microsoft.AspNet.Facebook/packages.config +++ b/src/Microsoft.AspNet.Facebook/packages.config @@ -2,5 +2,5 @@ - + \ No newline at end of file diff --git a/src/System.Net.Http.Formatting.NetCore/System.Net.Http.Formatting.NetCore.csproj b/src/System.Net.Http.Formatting.NetCore/System.Net.Http.Formatting.NetCore.csproj index 364d375d4..e579c5926 100644 --- a/src/System.Net.Http.Formatting.NetCore/System.Net.Http.Formatting.NetCore.csproj +++ b/src/System.Net.Http.Formatting.NetCore/System.Net.Http.Formatting.NetCore.csproj @@ -254,7 +254,7 @@ - ..\..\packages\Newtonsoft.Json.6.0.4\lib\portable-net45+wp80+win8+wpa81\Newtonsoft.Json.dll + ..\..\packages\Newtonsoft.Json.13.0.1\lib\netstandard1.0\Newtonsoft.Json.dll ..\..\packages\Microsoft.Net.Http.2.2.13\lib\portable-net40+sl4+win8+wp71\System.Net.Http.dll @@ -266,7 +266,7 @@ ..\..\packages\Microsoft.Net.Http.2.2.13\lib\portable-net40+sl4+win8+wp71\System.Net.Http.Primitives.dll - - 15.0 + 16.0 + + true diff --git a/Runtime.msbuild b/Runtime.msbuild index dbe4db084..5862d38b4 100644 --- a/Runtime.msbuild +++ b/Runtime.msbuild @@ -11,6 +11,7 @@ true true false + false false $(MSBuildThisFileDirectory)bin\$(Configuration)\test\TestResults\ $(MSBuildThisFileDirectory)packages\Microsoft.Web.SkipStrongNames.1.0.0\tools\SkipStrongNames.exe @@ -64,24 +65,12 @@ - - <_NuGetPackagesAndSolutions Include="Runtime.sln" /> - - - <_NuGetPackagesAndSolutions Include="src\System.Net.Http.Formatting.NetCore\packages.config; - test\System.Net.Http.Formatting.NetCore.Test\packages.config" - Condition=" '$(BuildPortable)' == 'true' " /> - <_ProjectsToRestore Include="test\System.Net.Http.Formatting.NetStandard.Test\System.Net.Http.Formatting.NetStandard.Test.csproj" - Condition=" '$(BuildPortable)' == 'true' " /> - - - - - + + + @@ -96,7 +85,7 @@ Properties="Configuration=Release;OutputPath=$(CustomFxCopRulesPath)" /> - + diff --git a/azure-pipelines.yml b/azure-pipelines.yml index a4050925e..f63cbb9fb 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -27,10 +27,10 @@ jobs: pool: ${{ if eq(variables['System.TeamProject'], 'public') }}: name: NetCore-Public - demands: ImageOverride -equals windows.vs2017.amd64.open + demands: ImageOverride -equals windows.vs2019.amd64.open ${{ else }}: name: NetCore1ESPool-Internal - demands: ImageOverride -equals windows.vs2017.amd64 + demands: ImageOverride -equals windows.vs2019.amd64 timeoutInMinutes: 30 strategy: diff --git a/build.cmd b/build.cmd index a37e007d6..1cc1cd4ea 100644 --- a/build.cmd +++ b/build.cmd @@ -7,12 +7,11 @@ mkdir bin :Build -REM Find the most recent 32bit MSBuild.exe on the system. Require v15.0 (installed with VS2017) or later since .NET -REM Core projects are coming soon. -REM Use `vswhere` for the search since %ProgramFiles(x86)%\msbuild\15.0\Bin\MSBuild.exe almost never exists. +REM Find the most recent 32bit MSBuild.exe on the system. Require v16.0 (installed with VS2019) or later. +REM Use `vswhere` for the search because it can find all VS installations. set vswhere="%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" if not exist %vswhere% ( - set VsWhere="%ProgramFiles%\Microsoft Visual Studio\Installer\vswhere.exe" + set vswhere="%ProgramFiles%\Microsoft Visual Studio\Installer\vswhere.exe" ) if not exist %vswhere% ( REM vswhere.exe not in normal locations; check the Path. @@ -25,19 +24,29 @@ if not exist %vswhere% ( goto BuildFail ) +REM We're fine w/ any .NET SDK newer than 2.1.500 but also need a 2.1.x runtime. Microsoft.Net.Core.Component.SDK.2.1 +REM actually checks for only the runtime these days. set InstallDir= -for /f "usebackq tokens=*" %%i in (`%vswhere% -version ^[15^,16^) -latest -prerelease -products * ^ - -requires Microsoft.Component.MSBuild -requires Microsoft.Net.Core.Component.SDK.2.1 ^ +for /f "usebackq tokens=*" %%i in (`%vswhere% -version 16 -latest -prerelease -products * ^ + -requires Microsoft.Component.MSBuild ^ + -requires Microsoft.NetCore.Component.SDK ^ + -requires Microsoft.Net.Core.Component.SDK.2.1 ^ -property installationPath`) do ( - set InstallDir=%%i + set InstallDir="%%i" ) -if exist "%InstallDir%\MSBuild\15.0\Bin\MSBuild.exe" ( - set MSBuild="%InstallDir%\MSBuild\15.0\Bin\MSBuild.exe" + +if exist %InstallDir%\MSBuild\Current\Bin\MSBuild.exe ( + set MSBuild=%InstallDir%\MSBuild\Current\Bin\MSBuild.exe ) else ( - echo Could not find MSBuild.exe. Please install the VS2017 BuildTools component or a workload that includes it. + echo Could not find MSBuild.exe. Please install the VS2019 BuildTools component or a workload that includes it. goto BuildFail ) +REM Configure NuGet operations to work w/in this repo i.e. do not pollute system packages folder. +REM Note this causes two copies of packages restored using packages.config to land in this folder e.g. +REM StyleCpy.5.0.0/ and stylecop/5.0.0/. +set "NUGET_PACKAGES=%CD%\packages" + REM Are we running in a local dev environment (not on CI)? if DEFINED CI (set Desktop=false) else if DEFINED TEAMCITY_VERSION (set Desktop=false) else (set Desktop=true) diff --git a/global.json b/global.json index 9ddc9bf9c..7b2cb540d 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { "version": "2.1.500", - "rollForward": "latestPatch" + "rollForward": "major" } } diff --git a/src/Strict.ruleset b/src/Strict.ruleset index 5a2a69ba9..a0c61fcb5 100644 --- a/src/Strict.ruleset +++ b/src/Strict.ruleset @@ -6,5 +6,7 @@ + + \ No newline at end of file diff --git a/src/System.Net.Http.Formatting.NetCore/System.Net.Http.Formatting.NetCore.csproj b/src/System.Net.Http.Formatting.NetCore/System.Net.Http.Formatting.NetCore.csproj index e579c5926..6964b5560 100644 --- a/src/System.Net.Http.Formatting.NetCore/System.Net.Http.Formatting.NetCore.csproj +++ b/src/System.Net.Http.Formatting.NetCore/System.Net.Http.Formatting.NetCore.csproj @@ -266,13 +266,14 @@ ..\..\packages\Microsoft.Net.Http.2.2.13\lib\portable-net40+sl4+win8+wp71\System.Net.Http.Primitives.dll - - + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + \ No newline at end of file diff --git a/test/Directory.Build.targets b/test/Directory.Build.targets index 72087f737..54ff85834 100644 --- a/test/Directory.Build.targets +++ b/test/Directory.Build.targets @@ -1,6 +1,6 @@ - + diff --git a/test/System.Net.Http.Formatting.NetCore.Test/System.Net.Http.Formatting.NetCore.Test.csproj b/test/System.Net.Http.Formatting.NetCore.Test/System.Net.Http.Formatting.NetCore.Test.csproj index 8d7515803..7aecee20d 100644 --- a/test/System.Net.Http.Formatting.NetCore.Test/System.Net.Http.Formatting.NetCore.Test.csproj +++ b/test/System.Net.Http.Formatting.NetCore.Test/System.Net.Http.Formatting.NetCore.Test.csproj @@ -317,14 +317,21 @@ - + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - + + + + - \ No newline at end of file diff --git a/tools/WebStack.StyleCop.targets b/tools/WebStack.StyleCop.targets index 0b73b551f..5ff6c528a 100644 --- a/tools/WebStack.StyleCop.targets +++ b/tools/WebStack.StyleCop.targets @@ -1,7 +1,7 @@  - - + + diff --git a/tools/src/Microsoft.Web.FxCop/Microsoft.Web.FxCop.csproj b/tools/src/Microsoft.Web.FxCop/Microsoft.Web.FxCop.csproj index d4a4451c7..2fc7c9bb4 100644 --- a/tools/src/Microsoft.Web.FxCop/Microsoft.Web.FxCop.csproj +++ b/tools/src/Microsoft.Web.FxCop/Microsoft.Web.FxCop.csproj @@ -10,7 +10,8 @@ Properties Microsoft.Web.FxCop Microsoft.Web.FxCop - v4.0 + + v4.7.2 bin\$(Configuration) From 1e2a82c42c49ea1ef41c1797da80223f1b3f9662 Mon Sep 17 00:00:00 2001 From: Doug Bunting <6431421+dougbu@users.noreply.github.com> Date: Mon, 12 Dec 2022 16:13:35 -0800 Subject: [PATCH 31/54] Use .NET SDK in two test projects (#371) - Use .NET SDK in NetCore.Test project - for now, unable to target `netcoreapp2.1` in NetCore.Test project - Microsoft.Net.Http is not compatible - System.Net.Http types have different identities, causing compilation failures - switch to use `dotnet vstest` for any .NET Core assemblies (just one currently) - can use `Xunit` target for all .NET Framework assemblies - make XunitXml.TestLogger available for .NET Core App testing - use above test logger in repo-level testing - integrate w/ tests that use the `Xunit` target - don't import from xunit.msbuild.runner when targeting .NET Core; not needed - add `$(CopyLocalLockFileAssemblies)` to these (now both .NET SDK) test projects - xUnit assemblies were not copied (when they should have been) w/o this - Use .NET SDK in Microsoft.TestCommon - allows reference in .NET SDK test projects - Create general `TestAssembly` target - rename WebStack.xunit.targets -> WebStack.testing.targets - rename `Xunit` target -> `TestAssembly` - move `dotnet vstest` use into new target - handle exit codes more consistently --- Runtime.msbuild | 27 +- RuntimePortable.sln | 4 +- packages/repositories.config | 2 - test/Directory.Build.props | 5 +- test/Directory.Build.targets | 3 +- .../ExceptionAssertions.cs | 2 + .../Microsoft.TestCommon.csproj | 139 +------ test/Microsoft.TestCommon/packages.config | 8 - ...em.Net.Http.Formatting.NetCore.Test.csproj | 378 ++++-------------- .../app.config | 11 - .../packages.config | 17 - ...et.Http.Formatting.NetStandard.Test.csproj | 12 +- .../Internal/HttpValueCollectionTest.cs | 2 + ...xunit.targets => WebStack.testing.targets} | 13 +- 14 files changed, 137 insertions(+), 486 deletions(-) delete mode 100644 test/Microsoft.TestCommon/packages.config delete mode 100644 test/System.Net.Http.Formatting.NetCore.Test/app.config delete mode 100644 test/System.Net.Http.Formatting.NetCore.Test/packages.config rename tools/{WebStack.xunit.targets => WebStack.testing.targets} (51%) diff --git a/Runtime.msbuild b/Runtime.msbuild index 5862d38b4..d53e2e46d 100644 --- a/Runtime.msbuild +++ b/Runtime.msbuild @@ -102,10 +102,20 @@ <_TestDLLsXunit Include="bin\$(Configuration)\test\*.Test.dll" /> - <_TestDLLsXunit Include="bin\$(Configuration)\test\*.Test.*.dll" /> - <_TestDLLsXunit Include="bin\$(Configuration)\Test\NetCore\*.Test.dll" Condition="'$(BuildPortable)' == 'true'" /> - <_XunitProject Include="tools\WebStack.xunit.targets"> - TestAssembly=%(_TestDLLsXunit.FullPath);XmlPath=$(TestResultsDirectory)%(_TestDLLsXunit.FileName)-XunitResults.xml + <_TestDLLsXunit Include="bin\$(Configuration)\test\*\net4*\*.Test.dll" + Condition=" '$(BuildPortable)' == 'true' " /> + <_XunitProject Include="tools\WebStack.testing.targets"> + TestAssembly=%(_TestDLLsXunit.FullPath); + XmlPath=$(TestResultsDirectory)%(_TestDLLsXunit.FileName)-XunitResults.xml + + + <_VSTestDLLs Include="bin\$(Configuration)\test\*\netcoreapp*\*.Test.dll" + Condition=" '$(BuildPortable)' == 'true' "/> + <_XunitProject Include="tools\WebStack.testing.targets" + Condition=" '$(BuildPortable)' == 'true' "> + TestAssembly=%(_VSTestDLLs.FullPath); + XmlPath=$(TestResultsDirectory)%(_VSTestDLLs.FileName)-NetCoreApp-XunitResults.xml; + UseVSTest=true @@ -113,16 +123,9 @@ - + - - - diff --git a/RuntimePortable.sln b/RuntimePortable.sln index f20623fd4..bbe26d3cf 100644 --- a/RuntimePortable.sln +++ b/RuntimePortable.sln @@ -7,11 +7,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{A9836F9E-6DB EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{C40883CD-366D-4534-8B58-3EA0D13136DF}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.TestCommon", "test\Microsoft.TestCommon\Microsoft.TestCommon.csproj", "{FCCC4CB7-BAF7-4A57-9F89-E5766FE536C0}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.TestCommon", "test\Microsoft.TestCommon\Microsoft.TestCommon.csproj", "{FCCC4CB7-BAF7-4A57-9F89-E5766FE536C0}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Net.Http.Formatting.NetCore", "src\System.Net.Http.Formatting.NetCore\System.Net.Http.Formatting.NetCore.csproj", "{C7060639-719B-4BD2-8A37-2F146B5A0668}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Net.Http.Formatting.NetCore.Test", "test\System.Net.Http.Formatting.NetCore.Test\System.Net.Http.Formatting.NetCore.Test.csproj", "{8DA61DAC-FF7E-4CA1-93A0-6148DB66FD08}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Net.Http.Formatting.NetCore.Test", "test\System.Net.Http.Formatting.NetCore.Test\System.Net.Http.Formatting.NetCore.Test.csproj", "{8DA61DAC-FF7E-4CA1-93A0-6148DB66FD08}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Net.Http.Formatting.NetStandard", "src\System.Net.Http.Formatting.NetStandard\System.Net.Http.Formatting.NetStandard.csproj", "{636CA76A-C85C-42E2-B4AA-88046279B3CA}" EndProject diff --git a/packages/repositories.config b/packages/repositories.config index 8bede8eeb..22e5c94b2 100644 --- a/packages/repositories.config +++ b/packages/repositories.config @@ -17,11 +17,9 @@ - - diff --git a/test/Directory.Build.props b/test/Directory.Build.props index 8dc298fd2..64681b2ef 100644 --- a/test/Directory.Build.props +++ b/test/Directory.Build.props @@ -4,6 +4,9 @@ false true - v4.5.2 + v4.5.2 diff --git a/test/Directory.Build.targets b/test/Directory.Build.targets index 54ff85834..b1167ac05 100644 --- a/test/Directory.Build.targets +++ b/test/Directory.Build.targets @@ -1,6 +1,7 @@ - + diff --git a/test/Microsoft.TestCommon/ExceptionAssertions.cs b/test/Microsoft.TestCommon/ExceptionAssertions.cs index 1d21f04f0..11b36e9e6 100644 --- a/test/Microsoft.TestCommon/ExceptionAssertions.cs +++ b/test/Microsoft.TestCommon/ExceptionAssertions.cs @@ -466,6 +466,7 @@ public static ArgumentOutOfRangeException ThrowsArgumentLessThanOrEqualTo(Action String.Format(CultureReplacer.DefaultCulture, "Value must be less than or equal to {0}.", maxValue), false, actualValue); } +#if !NETCOREAPP /// /// Verifies that the code throws an HttpException (or optionally any exception which derives from it). /// @@ -481,6 +482,7 @@ public static HttpException ThrowsHttpException(Action testCode, string exceptio Equal(httpCode, ex.GetHttpCode()); return ex; } +#endif /// /// Verifies that the code throws an InvalidEnumArgumentException (or optionally any exception which derives from it). diff --git a/test/Microsoft.TestCommon/Microsoft.TestCommon.csproj b/test/Microsoft.TestCommon/Microsoft.TestCommon.csproj index 73887c60e..dae43e747 100644 --- a/test/Microsoft.TestCommon/Microsoft.TestCommon.csproj +++ b/test/Microsoft.TestCommon/Microsoft.TestCommon.csproj @@ -1,128 +1,23 @@ - - + - {FCCC4CB7-BAF7-4A57-9F89-E5766FE536C0} - Library - Properties - Microsoft.TestCommon - Microsoft.TestCommon - false + netcoreapp2.1;net452 ..\..\bin\$(Configuration)\Test\ - false - false - true - false + $(Configurations);CodeAnalysis + false - - - - - - - - - - - ..\..\packages\xunit.abstractions.2.0.1\lib\net35\xunit.abstractions.dll - True - - - ..\..\packages\xunit.assert.2.3.0\lib\netstandard1.1\xunit.assert.dll - True - - - ..\..\packages\xunit.extensibility.core.2.3.0\lib\netstandard1.1\xunit.core.dll - True - - - ..\..\packages\xunit.extensibility.execution.2.3.0\lib\net452\xunit.execution.desktop.dll - True - + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - Code - - - - - - - - Code - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PreserveNewest - - - - - - - - - - - - \ No newline at end of file + diff --git a/test/Microsoft.TestCommon/packages.config b/test/Microsoft.TestCommon/packages.config deleted file mode 100644 index d6bfcf037..000000000 --- a/test/Microsoft.TestCommon/packages.config +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/test/System.Net.Http.Formatting.NetCore.Test/System.Net.Http.Formatting.NetCore.Test.csproj b/test/System.Net.Http.Formatting.NetCore.Test/System.Net.Http.Formatting.NetCore.Test.csproj index 7aecee20d..d60e9a90c 100644 --- a/test/System.Net.Http.Formatting.NetCore.Test/System.Net.Http.Formatting.NetCore.Test.csproj +++ b/test/System.Net.Http.Formatting.NetCore.Test/System.Net.Http.Formatting.NetCore.Test.csproj @@ -1,314 +1,87 @@ - - - - + - {8DA61DAC-FF7E-4CA1-93A0-6148DB66FD08} - Library - Properties + net462 System.Net.Http System.Net.Http.Formatting.NetCore.Test ..\..\bin\$(Configuration)\Test\NetCore\ + $(Configurations);CodeAnalysis + false $(DefineConstants);NETFX_CORE + true - - ..\..\packages\Castle.Core.4.2.1\lib\net45\Castle.Core.dll - True - - - ..\..\packages\Moq.4.7.142\lib\net45\Moq.dll - True - - - ..\..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll - True - - - - - - - ..\..\packages\Microsoft.Net.Http.2.2.13\lib\net45\System.Net.Http.Extensions.dll - - - ..\..\packages\Microsoft.Net.Http.2.2.13\lib\net45\System.Net.Http.Primitives.dll - - - - - - - ..\..\packages\xunit.abstractions.2.0.1\lib\net35\xunit.abstractions.dll - True - - - ..\..\packages\xunit.assert.2.3.0\lib\netstandard1.1\xunit.assert.dll - True - - - ..\..\packages\xunit.extensibility.core.2.3.0\lib\netstandard1.1\xunit.core.dll - True - - - ..\..\packages\xunit.extensibility.execution.2.3.0\lib\net452\xunit.execution.desktop.dll - True - + + + + + all + runtime; build; native; contentfiles; analyzers + + + + + + - - False - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - DataSets\Types\DerivedFormUrlEncodedMediaTypeFormatter.cs - - - Formatting\BsonMediaTypeFormatterTests.cs - - - Internal\FormDataCollectionTests.cs - - - Formatting\FormUrlEncodedFromContentTests.cs - - - Formatting\FormUrlEncodedFromUriQueryTests.cs - - - Internal\FormUrlEncodedJsonTests.cs - - - Formatting\FormUrlEncodedMediaTypeFormatterTests.cs - - - Formatting\JsonNetSerializationTest.cs - - - Formatting\JsonNetValidationTest.cs - - - Internal\FormUrlEncodedParserTests.cs - - - HttpContentFormDataExtensionsTest.cs - - - HttpValueCollectionTest.cs - - - Internal\ReadOnlyStreamWithEncodingPreambleTest.cs - - - MimeBodyPartTest.cs - - - HttpHeaderExtensionsTest.cs - - - HttpUnsortedResponseTest.cs - - - HttpUnsortedRequestTest.cs - - - SFormatting\tringComparisonHelperTest.cs - - - Mocks\MockAsyncCallback.cs - - - Mocks\MockCompletedAsyncResult.cs - - - HttpClientFactoryTest.cs - - - Handlers\ProgressContentTest.cs - - - Handlers\ProgressStreamTest.cs - - - Handlers\HttpProgressEventArgsTest.cs - - - MultipartRelatedStreamProviderTests.cs - - - MultipartStreamProviderTestBase.cs - - - MultipartFileDataTest.cs - - - DataSets\Types\DataContractEnum.cs - - - DataSets\Types\DataContractType.cs - - - DataSets\Types\DerivedDataContractType.cs - - - DataSets\Types\DerivedJsonMediaTypeFormatter.cs - - - DataSets\Types\DerivedWcfPocoType.cs - - - DataSets\Types\DerivedXmlMediaTypeFormatter.cs - - - DataSets\Types\DerivedXmlSerializableType.cs - - - DataSets\HttpTestData.cs - - - DataSets\Types\INotJsonSerializable.cs - - - DataSets\Types\WcfPocoType.cs - - - DataSets\Types\XmlSerializableType.cs - - - Formatting\SerializerConsistencyTests.cs - - - Formatting\XmlSerializerMediaTypeFormatterTests.cs - - - Formatting\MediaTypeFormatterTestBase.cs - - - HttpClientExtensionsTest.cs - - - Internal\AsyncResultTest.cs - - - Internal\DelegatingStreamTest.cs - - - Mocks\MockDelegatingHandler.cs - - - Mocks\MockDelegatingStream.cs - - - Mocks\MockProgressEventHandler.cs - - - Mocks\TestableHttpMessageHandler.cs - - - UriExtensionsTests.cs - - - UriQueryDataSet.cs - - - FormattingUtilitiesTests.cs - - - Formatting\JsonMediaTypeFormatterTests.cs - - - Formatting\MediaTypeConstantsTests.cs - - - Formatting\MediaTypeFormatterCollectionTests.cs - - - Formatting\MediaTypeFormatterTests.cs - - - Formatting\MediaTypeHeaderValueExtensionsTests.cs - - - Formatting\ParsedMediaTypeHeaderValueTests.cs - - - Formatting\XmlMediaTypeFormatterTests.cs - - - HttpContentMessageExtensionsTests.cs - - - HttpContentMultipartExtensionsTests.cs - - - HttpMessageContentTests.cs - - - Formatting\Parsers\HttpRequestHeaderParserTests.cs - - - Formatting\Parsers\HttpRequestLineParserTests.cs - - - Formatting\Parsers\HttpResponseHeaderParserTests.cs - - - Formatting\Parsers\HttpStatusLineParserTests.cs - - - Formatting\Parsers\InternetMessageFormatHeaderParserTests.cs - - - Formatting\Parsers\MimeMultipartParserTests.cs - - - MultipartMemoryStreamProviderTests.cs - - - ObjectContentOfTTests.cs - - - ObjectContentTests.cs - - - ParserData.cs - - - Mocks\MockHttpContent.cs - - - Mocks\MockMediaTypeFormatter.cs - - - HttpContentExtensionsTest.cs - - - PushStreamContentTest.cs - - - ProgressMessageHandlerTest.cs - - - ConcurrentDictionaryTests.cs - - - - - {C7060639-719B-4BD2-8A37-2F146B5A0668} - System.Net.Http.Formatting - - - {FCCC4CB7-BAF7-4A57-9F89-E5766FE536C0} - Microsoft.TestCommon - - - - - - Designer - + + @@ -316,17 +89,12 @@ - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - \ No newline at end of file + diff --git a/test/System.Net.Http.Formatting.NetCore.Test/app.config b/test/System.Net.Http.Formatting.NetCore.Test/app.config deleted file mode 100644 index d0071f86e..000000000 --- a/test/System.Net.Http.Formatting.NetCore.Test/app.config +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/test/System.Net.Http.Formatting.NetCore.Test/packages.config b/test/System.Net.Http.Formatting.NetCore.Test/packages.config deleted file mode 100644 index 88bf30ad7..000000000 --- a/test/System.Net.Http.Formatting.NetCore.Test/packages.config +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/System.Net.Http.Formatting.NetStandard.Test/System.Net.Http.Formatting.NetStandard.Test.csproj b/test/System.Net.Http.Formatting.NetStandard.Test/System.Net.Http.Formatting.NetStandard.Test.csproj index 0b89690d5..64d06cf7e 100644 --- a/test/System.Net.Http.Formatting.NetStandard.Test/System.Net.Http.Formatting.NetStandard.Test.csproj +++ b/test/System.Net.Http.Formatting.NetStandard.Test/System.Net.Http.Formatting.NetStandard.Test.csproj @@ -1,17 +1,23 @@  - netcoreapp2.1;net461 + netcoreapp2.1;net462 System.Net.Http System.Net.Http.Formatting.NetStandard.Test - ..\..\bin\$(Configuration)\Test\ + ..\..\bin\$(Configuration)\Test\NetStandard\ $(Configurations);CodeAnalysis false + true + - + + all + runtime; build; native; contentfiles; analyzers + + diff --git a/test/System.Net.Http.Formatting.Test/Internal/HttpValueCollectionTest.cs b/test/System.Net.Http.Formatting.Test/Internal/HttpValueCollectionTest.cs index 626c655aa..03b5aadf0 100644 --- a/test/System.Net.Http.Formatting.Test/Internal/HttpValueCollectionTest.cs +++ b/test/System.Net.Http.Formatting.Test/Internal/HttpValueCollectionTest.cs @@ -27,10 +27,12 @@ private static HttpValueCollection CreateInstance() #endif } +#if !NETCOREAPP private static void RunInIsolation(Action action) { AppDomainUtils.RunInSeparateAppDomain(action); } +#endif public static TheoryDataSet>> KeyValuePairs { diff --git a/tools/WebStack.xunit.targets b/tools/WebStack.testing.targets similarity index 51% rename from tools/WebStack.xunit.targets rename to tools/WebStack.testing.targets index d11eaee74..b802862a0 100644 --- a/tools/WebStack.xunit.targets +++ b/tools/WebStack.testing.targets @@ -5,10 +5,19 @@ --> - - + + + + + <_ExitCodes Include="$(TestAssembly)" Code="$(_ExitCode)" /> From 8515e0beddcc890f6e270180d2c5c9b503ed6634 Mon Sep 17 00:00:00 2001 From: Doug Bunting <6431421+dougbu@users.noreply.github.com> Date: Fri, 20 Jan 2023 10:45:23 -0800 Subject: [PATCH 32/54] Address a few more nits (#378) - avoid repeated NuGet.exe downloads - remove extra bits in modern file versions before parsing - suppress warnings about targeting `netcoreapp2.1` --- Directory.Build.props | 3 +++ tools/WebStack.tasks.targets | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/Directory.Build.props b/Directory.Build.props index 41d0defa2..fef50e3d3 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -9,5 +9,8 @@ analyzers, which run during build. Refer to https://aka.ms/fxcopanalyzers to migrate to FxCop analyzers." --> true + + false + diff --git a/tools/WebStack.tasks.targets b/tools/WebStack.tasks.targets index cf88c574c..efbf42d40 100644 --- a/tools/WebStack.tasks.targets +++ b/tools/WebStack.tasks.targets @@ -48,6 +48,11 @@ if (versionInfo != null && versionInfo.ProductVersion != null) { toParse = versionInfo.ProductVersion; + int index = toParse.IndexOfAny(new[] {'-', '+'}); + if (index > 0) + { + toParse = toParse.Substring(0, index); + } } else { From fc1cf70d827b66aac21ec9b0a6764a47afc7b7d6 Mon Sep 17 00:00:00 2001 From: Doug Bunting <6431421+dougbu@users.noreply.github.com> Date: Tue, 24 Jan 2023 15:42:49 -0800 Subject: [PATCH 33/54] Use latest 2.1.x .NET SDK (#381) - noticed CI builds were using old 2.1.500 - `UseDotNet@2` seems to ignore `rollForward` when using global.json :frown: - nits: - quiet `dotnet` in CI (where `dotnet` is always new) - complain about all potentially missing components when VS isn't found - add a missing blank line --- azure-pipelines.yml | 2 ++ build.cmd | 4 ++++ global.json | 2 +- src/System.Net.Http.Formatting/Handlers/ProgressStream.cs | 1 + 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index f63cbb9fb..820089f1c 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -14,6 +14,8 @@ parameters: variables: - name: DOTNET_CLI_TELEMETRY_OPTOUT value: 1 +- name: DOTNET_NOLOGO + value: 1 # Run CodeQL3000 tasks in a separate internal pipeline; not needed here. - name: Codeql.SkipTaskAutoInjection value: true diff --git a/build.cmd b/build.cmd index 1cc1cd4ea..798507f17 100644 --- a/build.cmd +++ b/build.cmd @@ -35,6 +35,10 @@ for /f "usebackq tokens=*" %%i in (`%vswhere% -version 16 -latest -prerelease -p set InstallDir="%%i" ) +if not DEFINED InstallDir ( + echo "Could not find a VS2019 installation with the necessary components (MSBuild, .NET Core 2.1 Runtime, .NET SDK). Please install VS2019 or the missing components." +) + if exist %InstallDir%\MSBuild\Current\Bin\MSBuild.exe ( set MSBuild=%InstallDir%\MSBuild\Current\Bin\MSBuild.exe ) else ( diff --git a/global.json b/global.json index 7b2cb540d..053fd617a 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "2.1.500", + "version": "2.1.818", "rollForward": "major" } } diff --git a/src/System.Net.Http.Formatting/Handlers/ProgressStream.cs b/src/System.Net.Http.Formatting/Handlers/ProgressStream.cs index 8c169c94e..4ee57acf3 100644 --- a/src/System.Net.Http.Formatting/Handlers/ProgressStream.cs +++ b/src/System.Net.Http.Formatting/Handlers/ProgressStream.cs @@ -67,6 +67,7 @@ public override async Task ReadAsync(byte[] buffer, int offset, int count, ReportBytesReceived(readCount, userState: null); return readCount; } + #if !NETFX_CORE // BeginX and EndX are not supported on streams in portable libraries public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { From 2ed73bc49d2535b345da53ee2ce6e55a3fac0197 Mon Sep 17 00:00:00 2001 From: Doug Bunting <6431421+dougbu@users.noreply.github.com> Date: Sat, 28 Jan 2023 13:39:45 -0800 Subject: [PATCH 34/54] Move NetCore project to use .NET SDK (#380) Move NetCore project to use .NET SDK - Formatting.NetCore now targets `netstandard1.3` - was `Profile259` aka `portable-net45+wp80+win8+wpa81`, approximately `netstandard1.0` - but Newtonsoft.Json.Bson supports `netstandard1.3` and up - use Newtonsoft.Json.Bson in NetCore projects - can now multi-target NetCore.Test as well - nits: - align src/ Formatting projects as much as possible - align test/ Formatting projects as much as possible - clean up the Microsoft.TestCommon project slightly - note: NetCore project names make no sense but I'm leaving them alone for this PR React to using Newtonsoft.Json.Bson everywhere - remove deprecated `BsonWriter` mentions entirely - remove legacy BSON writer test workaround Remove unnecessary `ConcurrentDictionary` class - was not available in `Profile259` - leave tests to confirm correct operation w/ "real" class Remove `UriQueryUtility` because `WebUtility` is available everywhere - leave test to confirm `WebUtility` continues to behave about the same - handle `WebUtility` being a `public` class - change other tests to handle `WebUtility.UrlEncode(...)` encoding to uppercase - unlike `UriQueryUtility.UrlEncode(...)` Add simple classes to NetCore project - use `ICloneable` copy to get more classes compiling - helps NetCore in similar way to existing `MediaTypeHeaderValueExtensions` - use `InvalidEnumArgumentException` copy to simplify code and testing - both not available in `netstandard1.3` (or available packages) but easily duplicated Remove unnecessary NetCore-specific GlobalSuppressions.cs file Use `NameValueCollection` everywhere - available (but not serializable) in `netstandard1.3` Add `MaxDepth` support in NetCore assembly - remove an unnecessary suppression about `MaxDepth` in `BaseJsonMediaTypeFormatter` Add `UseDataContractJsonSerializer` support in NetCore assembly - `XsdDataContractExporter` remains unavailable - update XML DCS tests to handle this (previously not in NetCore assembly) - try various workarounds - `ReadOnlyStreamWithEncodingPreamble` causes tests to hit dotnet/runtime#80160 - restriction to UTF8 when writing is a significant issue Copy `TranscodingStream` and related files from dotnet/runtime - my runtime clone was at 88868b7a781f4e5b9037b8721f30440207a7aa42 Adjust `TranscodingStream` and related code to compile and run here - add conditions to avoid references to version-specific API - remove references to internal dotnet/runtime code - rewrite some code more generically if performance impact likely minor - use Microsoft.TestCommon instead of directly relying on Xunit in tests - use C# 9.0 Use `TranscodingStream` in JSON and XML formatters - remove `ReadOnlyStreamWithEncodingPreamble` and its tests - was insufficient in general and doesn't work correctly in `netstandard1.3` - see dotnet/runtime#80160 - now support a much broader set of encodings in JSON and XML formatters - not just UTF8, UTF16BE, and UTF16LE - JSON formatter already supported every encoding when `UseDataContractJsonSerializer` was `false` - no longer have this downside when property is `true` - however, quotas remain unsupported in `netstandard1.3` version of this formatter when property is `true` - XML formatter requirement for an XML declaration in non-UTF8 content was general and is no longer an issue Add `MediaTypeMappings` support in NetCore assembly Add `IRequiredMemberSelector` support in NetCore assembly Remove unnecessary NETFX_CORE workarounds - use `DefaultContractResolver`, `GuidAttribute`, `TypeDescriptor`, `XmlElement`, `XmlNode` classes - use `IRequiredMemberSelector` interface - use `RequestMessage.CreateResponse()` extension method - all available in `netstandard1.3` - `JsonContractResolver` use is something of a late Newtonsoft.Json version reaction - was held back by missing `IRequiredMemberSelector` Work around missing features in `netstandard1.3` - get classes now included in NetCore assembly compiling - `SerializationAttribute` is not available - therefore `Exception` is not serializable - therefore `DefaultContractResolver.IgnoreSerializableAttribute` is not available - `Stream.(Begin|End)(Read|Write)` and `Stream.Close()` are not available - nit: clean up `MultipartFormDataStreamProvider` whitespace --- RuntimePortable.sln | 2 +- packages/repositories.config | 1 - src/Common/Error.cs | 23 +- src/Common/UriQueryUtility.cs | 278 ---- src/Directory.Build.props | 2 +- .../GlobalSuppressions.cs | 10 - .../ICloneable.cs | 9 + .../Internal/ConcurrentDictionary.cs | 192 --- .../System.Net.Http.Formatting.NetCore.csproj | 305 +---- .../packages.config | 7 - ...tem.Net.Http.Formatting.NetStandard.csproj | 65 +- .../Formatting/BaseJsonMediaTypeFormatter.cs | 18 - .../Formatting/BsonMediaTypeFormatter.cs | 30 +- .../Formatting/FormDataCollection.cs | 13 +- .../Formatting/JsonContractResolver.cs | 3 + .../Formatting/JsonMediaTypeFormatter.cs | 77 +- .../Formatting/MediaTypeFormatter.cs | 26 +- .../MediaTypeFormatterCollection.cs | 2 - .../Parsers/FormUrlEncodedParser.cs | 6 +- .../Formatting/XmlMediaTypeFormatter.cs | 38 +- .../FormattingUtilities.cs | 4 - .../HttpContentFormDataExtensions.cs | 3 - .../Internal/ByteRangeStream.cs | 4 + .../Internal/HttpValueCollection.cs | 155 +-- .../Internal/NonClosingDelegatingStream.cs | 10 +- .../Internal/NullableAttributes.cs | 198 +++ .../ReadOnlyStreamWithEncodingPreamble.cs | 175 --- .../Internal/TranscodingStream.cs | 828 ++++++++++++ .../InvalidByteRangeException.cs | 4 +- .../MultipartFormDataStreamProvider.cs | 10 +- .../Properties/AssemblyInfo.cs | 6 +- .../Properties/Resources.Designer.cs | 210 +-- .../Properties/Resources.resx | 69 +- .../Settings.StyleCop | 10 - .../System.Net.Http.Formatting.csproj | 195 +-- .../UriExtensions.cs | 9 - .../packages.config | 4 + src/System.Web.Http/Settings.StyleCop | 11 - src/System.Web.Http/System.Web.Http.csproj | 3 - test/Common/UriQueryUtilityTest.cs | 9 +- .../ExceptionAssertions.cs | 10 +- .../Microsoft.TestCommon.csproj | 21 +- ...em.Net.Http.Formatting.NetCore.Test.csproj | 95 +- ...et.Http.Formatting.NetStandard.Test.csproj | 19 +- .../DataSets/HttpTestData.cs | 2 - .../Formatting/BsonMediaTypeFormatterTests.cs | 16 +- ...DataContractJsonMediaTypeFormatterTests.cs | 16 +- .../FormUrlEncodedFromContentTests.cs | 4 +- .../FormUrlEncodedFromUriQueryTests.cs | 4 +- .../Formatting/JsonMediaTypeFormatterTests.cs | 16 - .../Formatting/JsonNetValidationTest.cs | 4 - .../MediaTypeFormatterCollectionTests.cs | 2 - .../Formatting/MediaTypeFormatterTests.cs | 6 - .../Formatting/StringComparisonHelperTest.cs | 10 +- .../Formatting/XmlMediaTypeFormatterTests.cs | 25 - .../XmlSerializerMediaTypeFormatterTests.cs | 21 - .../Handlers/ProgressMessageHandlerTest.cs | 5 +- .../Headers/CookieStateTest.cs | 22 +- .../HttpContentFormDataExtensionsTest.cs | 3 - .../HttpRequestHeadersExtensionsTest.cs | 2 +- .../Internal/ByteRangeStreamTest.cs | 2 + .../Internal/ConcurrentDictionaryTests.cs | 224 +--- .../Internal/HttpValueCollectionTest.cs | 24 - .../ReadOnlyStreamWithEncodingPreambleTest.cs | 75 -- .../Internal/TranscodingStreamTests.cs | 1145 +++++++++++++++++ .../Mocks/MockDelegatingHandler.cs | 4 - .../System.Net.Http.Formatting.Test.csproj | 188 +-- .../packages.config | 6 + tools/WebStack.settings.targets | 4 +- 69 files changed, 2770 insertions(+), 2229 deletions(-) delete mode 100644 src/Common/UriQueryUtility.cs delete mode 100644 src/System.Net.Http.Formatting.NetCore/GlobalSuppressions.cs create mode 100644 src/System.Net.Http.Formatting.NetCore/ICloneable.cs delete mode 100644 src/System.Net.Http.Formatting.NetCore/Internal/ConcurrentDictionary.cs delete mode 100644 src/System.Net.Http.Formatting.NetCore/packages.config create mode 100644 src/System.Net.Http.Formatting/Internal/NullableAttributes.cs delete mode 100644 src/System.Net.Http.Formatting/Internal/ReadOnlyStreamWithEncodingPreamble.cs create mode 100644 src/System.Net.Http.Formatting/Internal/TranscodingStream.cs delete mode 100644 src/System.Net.Http.Formatting/Settings.StyleCop delete mode 100644 src/System.Web.Http/Settings.StyleCop delete mode 100644 test/System.Net.Http.Formatting.Test/Internal/ReadOnlyStreamWithEncodingPreambleTest.cs create mode 100644 test/System.Net.Http.Formatting.Test/Internal/TranscodingStreamTests.cs diff --git a/RuntimePortable.sln b/RuntimePortable.sln index bbe26d3cf..6838937f7 100644 --- a/RuntimePortable.sln +++ b/RuntimePortable.sln @@ -9,7 +9,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{C40883CD-3 EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.TestCommon", "test\Microsoft.TestCommon\Microsoft.TestCommon.csproj", "{FCCC4CB7-BAF7-4A57-9F89-E5766FE536C0}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Net.Http.Formatting.NetCore", "src\System.Net.Http.Formatting.NetCore\System.Net.Http.Formatting.NetCore.csproj", "{C7060639-719B-4BD2-8A37-2F146B5A0668}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Net.Http.Formatting.NetCore", "src\System.Net.Http.Formatting.NetCore\System.Net.Http.Formatting.NetCore.csproj", "{C7060639-719B-4BD2-8A37-2F146B5A0668}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Net.Http.Formatting.NetCore.Test", "test\System.Net.Http.Formatting.NetCore.Test\System.Net.Http.Formatting.NetCore.Test.csproj", "{8DA61DAC-FF7E-4CA1-93A0-6148DB66FD08}" EndProject diff --git a/packages/repositories.config b/packages/repositories.config index 22e5c94b2..18d08a3de 100644 --- a/packages/repositories.config +++ b/packages/repositories.config @@ -3,7 +3,6 @@ - diff --git a/src/Common/Error.cs b/src/Common/Error.cs index b6013c5dc..f25b3d9b2 100644 --- a/src/Common/Error.cs +++ b/src/Common/Error.cs @@ -225,11 +225,7 @@ internal static OperationCanceledException OperationCanceled(string messageForma /// The logged . internal static ArgumentException InvalidEnumArgument(string parameterName, int invalidValue, Type enumClass) { -#if NETFX_CORE - return new ArgumentException(Error.Format(CommonWebApiResources.InvalidEnumArgument, parameterName, invalidValue, enumClass.Name), parameterName); -#else return new InvalidEnumArgumentException(parameterName, invalidValue, enumClass); -#endif } /// @@ -265,5 +261,24 @@ internal static NotSupportedException NotSupported(string messageFormat, params { return new NotSupportedException(Error.Format(messageFormat, messageArgs)); } + +#if NETFX_CORE // InvalidEnumArgumentException not available in netstandard1.3. + internal class InvalidEnumArgumentException : ArgumentException + { + public InvalidEnumArgumentException() : this(null) + { } + + public InvalidEnumArgumentException(string message) : base(message) + { } + + public InvalidEnumArgumentException(string message, Exception innerException) : base(message, innerException) + { } + + public InvalidEnumArgumentException(string argumentName, int invalidValue, Type enumClass) : base( + Error.Format(CommonWebApiResources.InvalidEnumArgument, argumentName, invalidValue, enumClass.Name), + argumentName) + { } + } +#endif } } diff --git a/src/Common/UriQueryUtility.cs b/src/Common/UriQueryUtility.cs deleted file mode 100644 index 53675e11a..000000000 --- a/src/Common/UriQueryUtility.cs +++ /dev/null @@ -1,278 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Diagnostics.Contracts; -using System.Net; -using System.Text; - -namespace System.Web.Http -{ - /// - /// Helpers for encoding, decoding, and parsing URI query components. In .Net 4.5 - /// please use the WebUtility class. - /// - internal static class UriQueryUtility - { - public static string UrlEncode(string str) - { - if (str == null) - { - return null; - } - -#if NETFX_CORE - return WebUtility.UrlEncode(str); -#else - byte[] bytes = Encoding.UTF8.GetBytes(str); - return Encoding.ASCII.GetString(UrlEncode(bytes, 0, bytes.Length, alwaysCreateNewReturnValue: false)); -#endif - } - - public static string UrlDecode(string str) - { - if (str == null) - { - return null; - } - -#if NETFX_CORE - return WebUtility.UrlDecode(str); -#else - return UrlDecodeInternal(str, Encoding.UTF8); -#endif - } - -#if !NETFX_CORE - private static byte[] UrlEncode(byte[] bytes, int offset, int count, bool alwaysCreateNewReturnValue) - { - byte[] encoded = UrlEncode(bytes, offset, count); - - return (alwaysCreateNewReturnValue && (encoded != null) && (encoded == bytes)) - ? (byte[])encoded.Clone() - : encoded; - } - - private static byte[] UrlEncode(byte[] bytes, int offset, int count) - { - if (!ValidateUrlEncodingParameters(bytes, offset, count)) - { - return null; - } - - int cSpaces = 0; - int cUnsafe = 0; - - // count them first - for (int i = 0; i < count; i++) - { - char ch = (char)bytes[offset + i]; - - if (ch == ' ') - cSpaces++; - else if (!IsUrlSafeChar(ch)) - cUnsafe++; - } - - // nothing to expand? - if (cSpaces == 0 && cUnsafe == 0) - return bytes; - - // expand not 'safe' characters into %XX, spaces to +s - byte[] expandedBytes = new byte[count + cUnsafe * 2]; - int pos = 0; - - for (int i = 0; i < count; i++) - { - byte b = bytes[offset + i]; - char ch = (char)b; - - if (IsUrlSafeChar(ch)) - { - expandedBytes[pos++] = b; - } - else if (ch == ' ') - { - expandedBytes[pos++] = (byte)'+'; - } - else - { - expandedBytes[pos++] = (byte)'%'; - expandedBytes[pos++] = (byte)IntToHex((b >> 4) & 0xf); - expandedBytes[pos++] = (byte)IntToHex(b & 0x0f); - } - } - - return expandedBytes; - } - - private static string UrlDecodeInternal(string value, Encoding encoding) - { - if (value == null) - { - return null; - } - - int count = value.Length; - UrlDecoder helper = new UrlDecoder(count, encoding); - - // go through the string's chars collapsing %XX and %uXXXX and - // appending each char as char, with exception of %XX constructs - // that are appended as bytes - - for (int pos = 0; pos < count; pos++) - { - char ch = value[pos]; - - if (ch == '+') - { - ch = ' '; - } - else if (ch == '%' && pos < count - 2) - { - int h1 = HexToInt(value[pos + 1]); - int h2 = HexToInt(value[pos + 2]); - - if (h1 >= 0 && h2 >= 0) - { - // valid 2 hex chars - byte b = (byte)((h1 << 4) | h2); - pos += 2; - - // don't add as char - helper.AddByte(b); - continue; - } - } - - if ((ch & 0xFF80) == 0) - helper.AddByte((byte)ch); // 7 bit have to go as bytes because of Unicode - else - helper.AddChar(ch); - } - - return helper.GetString(); - } - - private static int HexToInt(char h) - { - return (h >= '0' && h <= '9') ? h - '0' : - (h >= 'a' && h <= 'f') ? h - 'a' + 10 : - (h >= 'A' && h <= 'F') ? h - 'A' + 10 : - -1; - } - - private static char IntToHex(int n) - { - Contract.Assert(n < 0x10); - - if (n <= 9) - return (char)(n + (int)'0'); - else - return (char)(n - 10 + (int)'a'); - } - - // Set of safe chars, from RFC 1738.4 minus '+' - private static bool IsUrlSafeChar(char ch) - { - if (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' || ch >= '0' && ch <= '9') - return true; - - switch (ch) - { - case '-': - case '_': - case '.': - case '!': - case '*': - case '(': - case ')': - return true; - } - - return false; - } - - private static bool ValidateUrlEncodingParameters(byte[] bytes, int offset, int count) - { - if (bytes == null && count == 0) - return false; - if (bytes == null) - { - throw Error.ArgumentNull("bytes"); - } - if (offset < 0 || offset > bytes.Length) - { - throw new ArgumentOutOfRangeException("offset"); - } - if (count < 0 || offset + count > bytes.Length) - { - throw new ArgumentOutOfRangeException("count"); - } - - return true; - } - - // Internal class to facilitate URL decoding -- keeps char buffer and byte buffer, allows appending of either chars or bytes - private class UrlDecoder - { - private int _bufferSize; - - // Accumulate characters in a special array - private int _numChars; - private char[] _charBuffer; - - // Accumulate bytes for decoding into characters in a special array - private int _numBytes; - private byte[] _byteBuffer; - - // Encoding to convert chars to bytes - private Encoding _encoding; - - private void FlushBytes() - { - if (_numBytes > 0) - { - _numChars += _encoding.GetChars(_byteBuffer, 0, _numBytes, _charBuffer, _numChars); - _numBytes = 0; - } - } - - internal UrlDecoder(int bufferSize, Encoding encoding) - { - _bufferSize = bufferSize; - _encoding = encoding; - - _charBuffer = new char[bufferSize]; - // byte buffer created on demand - } - - internal void AddChar(char ch) - { - if (_numBytes > 0) - FlushBytes(); - - _charBuffer[_numChars++] = ch; - } - - internal void AddByte(byte b) - { - if (_byteBuffer == null) - _byteBuffer = new byte[_bufferSize]; - - _byteBuffer[_numBytes++] = b; - } - - internal String GetString() - { - if (_numBytes > 0) - FlushBytes(); - - if (_numChars > 0) - return new String(_charBuffer, 0, _numChars); - else - return String.Empty; - } - } -#endif - } -} \ No newline at end of file diff --git a/src/Directory.Build.props b/src/Directory.Build.props index c81c39ff4..c5c258a90 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -4,6 +4,6 @@ true false - v4.5 + v4.5 diff --git a/src/System.Net.Http.Formatting.NetCore/GlobalSuppressions.cs b/src/System.Net.Http.Formatting.NetCore/GlobalSuppressions.cs deleted file mode 100644 index 778d614cd..000000000 --- a/src/System.Net.Http.Formatting.NetCore/GlobalSuppressions.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.Diagnostics.CodeAnalysis; - -[assembly: SuppressMessage("Microsoft.Design", "CA2210:AssembliesShouldHaveValidStrongNames")] -[assembly: SuppressMessage("Microsoft.Design", "CA1020:AvoidNamespacesWithFewTypes", Scope = "namespace", Target = "System.Net.Http.Headers", Justification = "We follow the layout of System.Net.Http.")] -[assembly: SuppressMessage("Microsoft.Design", "CA1020:AvoidNamespacesWithFewTypes", Scope = "namespace", Target = "System.Net.Http.Handlers", Justification = "Handlers provide an extensibility hook which we want to keep in a separate namespace.")] -[assembly: SuppressMessage("Microsoft.Design", "CA1014:MarkAssembliesWithClsCompliant", Scope = "module", Target = "system.net.http.formatting.dll", Justification = "CLSCompliant is not applicable to the portable version of the assembly.")] -[assembly: SuppressMessage("Microsoft.Web.FxCop", "MW1000:UnusedResourceUsageRule", Scope = "module", Target = "system.net.http.formatting.dll", Justification = "The resources are only used in the non-portable version of the assembly.")] diff --git a/src/System.Net.Http.Formatting.NetCore/ICloneable.cs b/src/System.Net.Http.Formatting.NetCore/ICloneable.cs new file mode 100644 index 000000000..1fc5b88c5 --- /dev/null +++ b/src/System.Net.Http.Formatting.NetCore/ICloneable.cs @@ -0,0 +1,9 @@ +// No ICloneable interface in .NET Standard 1.3. + +namespace System +{ + internal interface ICloneable + { + object Clone(); + } +} diff --git a/src/System.Net.Http.Formatting.NetCore/Internal/ConcurrentDictionary.cs b/src/System.Net.Http.Formatting.NetCore/Internal/ConcurrentDictionary.cs deleted file mode 100644 index 3df580802..000000000 --- a/src/System.Net.Http.Formatting.NetCore/Internal/ConcurrentDictionary.cs +++ /dev/null @@ -1,192 +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. - -#if NETFX_CORE // This file should only be included by the NetCore version of the formatting project, but adding a guard here just in case. -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace System.Net.Http.Internal -{ - // TODO: Remove this class after BCL makes their portable library version. - internal sealed class ConcurrentDictionary : IDictionary - { - private Dictionary _dictionary = new Dictionary(); - private object _lock = new object(); - - public ICollection Keys - { - get - { - throw new NotImplementedException(); - } - } - - public ICollection Values - { - get - { - throw new NotImplementedException(); - } - } - - public int Count - { - get - { - throw new NotImplementedException(); - } - } - - public bool IsReadOnly - { - get - { - return ((IDictionary)_dictionary).IsReadOnly; - } - } - - public TValue this[TKey key] - { - get - { - throw new NotImplementedException(); - } - set - { - throw new NotImplementedException(); - } - } - - public void Add(TKey key, TValue value) - { - throw new NotImplementedException(); - } - - public bool ContainsKey(TKey key) - { - lock (_lock) - { - return _dictionary.ContainsKey(key); - } - } - - public bool Remove(TKey key) - { - throw new NotImplementedException(); - } - - public bool TryGetValue(TKey key, out TValue value) - { - lock (_lock) - { - return _dictionary.TryGetValue(key, out value); - } - } - - public void Add(KeyValuePair item) - { - throw new NotImplementedException(); - } - - public void Clear() - { - throw new NotImplementedException(); - } - - public bool Contains(KeyValuePair item) - { - throw new NotImplementedException(); - } - - public void CopyTo(KeyValuePair[] array, int arrayIndex) - { - throw new NotImplementedException(); - } - - public bool Remove(KeyValuePair item) - { - throw new NotImplementedException(); - } - - public IEnumerator> GetEnumerator() - { - throw new NotImplementedException(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - throw new NotImplementedException(); - } - - // ConcurrentDictionary members - public bool TryRemove(TKey key, out TValue removedValue) - { - lock (_lock) - { - if (_dictionary.TryGetValue(key, out removedValue)) - { - return _dictionary.Remove(key); - } - - return false; - } - } - - public TValue GetOrAdd(TKey key, Func addValueFactory) - { - lock (_lock) - { - TValue value; - - if (!_dictionary.TryGetValue(key, out value)) - { - value = addValueFactory.Invoke(key); - _dictionary.Add(key, value); - } - - return value; - } - } - - public bool TryAdd(TKey key, TValue value) - { - lock (_lock) - { - if (_dictionary.ContainsKey(key)) - { - return false; - } - - _dictionary.Add(key, value); - return true; - } - } - - public TValue AddOrUpdate(TKey key, TValue addValue, Func updateValueFactory) - { - lock (_lock) - { - TValue value; - - // update - if (_dictionary.TryGetValue(key, out value)) - { - value = updateValueFactory.Invoke(key, value); - _dictionary[key] = value; - return value; - } - - // add - _dictionary.Add(key, addValue); - return addValue; - } - } - } -} -#endif \ No newline at end of file diff --git a/src/System.Net.Http.Formatting.NetCore/System.Net.Http.Formatting.NetCore.csproj b/src/System.Net.Http.Formatting.NetCore/System.Net.Http.Formatting.NetCore.csproj index 6964b5560..615fd2326 100644 --- a/src/System.Net.Http.Formatting.NetCore/System.Net.Http.Formatting.NetCore.csproj +++ b/src/System.Net.Http.Formatting.NetCore/System.Net.Http.Formatting.NetCore.csproj @@ -1,279 +1,72 @@ - - + - {C7060639-719B-4BD2-8A37-2F146B5A0668} - Library - Properties + netstandard1.3 System.Net.Http System.Net.Http.Formatting $(OutputPath)NetCore\ $(OutputPath)$(AssemblyName).xml - $(CodeAnalysis) - ..\Strict.ruleset - /assemblycomparemode:StrongNameIgnoringVersion - false - $(DefineConstants);NETFX_CORE;ASPNETMVC;NOT_CLS_COMPLIANT - Profile259 - {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + false + $(DefineConstants);ASPNETMVC;NETFX_CORE 1591 + false + $(Configurations);CodeAnalysis + false + - - Properties\CommonAssemblyInfo.cs - - - Common\Error.cs - - - Common\TaskHelpers.cs - - - Common\TaskHelpersExtensions.cs - - - Common\UriQueryUtility.cs - - - Common\CollectionExtensions.cs - - - Common\ListWrapperCollection.cs - - - FormattingUtilities.cs - - - Formatting\BaseJsonMediaTypeFormatter.cs - - - Formatting\BsonMediaTypeFormatter.cs - - - Formatting\DelegatingEnumerable.cs - - - Formatting\FormDataCollection.cs - - - Formatting\FormUrlEncodedJson.cs - - - Formatting\FormUrlEncodedMediaTypeFormatter.cs - - - Formatting\IFormatterLogger.cs - - - Formatting\JsonMediaTypeFormatter.cs - - - Formatting\MediaTypeConstants.cs - - - Formatting\MediaTypeFormatter.cs - - - Formatting\MediaTypeFormatterCollection.cs - - - Formatting\MediaTypeHeaderValueExtensions.cs - - - Formatting\MediaTypeHeaderValueRange.cs - - - Formatting\ParsedMediaTypeHeaderValue.cs - - - Formatting\Parsers\FormUrlEncodedParser.cs - - - Formatting\Parsers\HttpRequestHeaderParser.cs - - - Formatting\Parsers\HttpRequestLineParser.cs - - - Formatting\Parsers\HttpResponseHeaderParser.cs - - - Formatting\Parsers\HttpStatusLineParser.cs - - - Formatting\Parsers\InternetMessageFormatHeaderParser.cs - - - Formatting\Parsers\MimeMultipartBodyPartParser.cs - - - Formatting\Parsers\MimeMultipartParser.cs - - - Formatting\Parsers\ParserState.cs - - - Formatting\StringComparisonHelper.cs - - - Formatting\XmlMediaTypeFormatter.cs - - - HttpContentFormDataExtensions.cs - - - HttpValueCollection.cs - - - UriExtensions.cs - - - - Handlers\HttpProgressEventArgs.cs - - - Handlers\ProgressContent.cs - - - Handlers\ProgressMessageHandler.cs - - - Handlers\ProgressStream.cs - - - HttpClientExtensions.cs - - - HttpClientFactory.cs - - - HttpContentExtensions.cs - - - HttpContentMessageExtensions.cs - - - HttpContentMultipartExtensions.cs - - - HttpHeaderExtensions.cs - - - HttpMessageContent.cs - - - HttpUnsortedHeaders.cs - - - HttpUnsortedRequest.cs - - - HttpUnsortedResponse.cs - - - Internal\AsyncResult.cs - - - Internal\DelegatingStream.cs - - - Internal\ReadOnlyStreamWithEncodingPreamble.cs - - - Internal\TypeExtensions.cs - - - MimeBodyPart.cs - - - MultipartFileData.cs - - - MultipartMemoryStreamProvider.cs - - - MultipartRelatedStreamProvider.cs - - - MultipartStreamProvider.cs - - - ObjectContent.cs - - - ObjectContentOfT.cs - - - PushStreamContent.cs - - - Properties\AssemblyInfo.cs - - - Properties\TransparentCommonAssemblyInfo.cs - True - True - Resources.resx - - - UnsupportedMediaTypeException.cs - - - - - + + + + + + + + + + + + + + + + + + + + + %(RecursiveDir)\%(Filename).cs + + - Properties\CommonWebApiResources.Designer.cs True - True CommonWebApiResources.resx + True + Properties\CommonWebApiResources.Designer.cs - - - Properties\CommonWebApiResources.resx ResXFileCodeGenerator CommonWebApiResources.Designer.cs + Properties\CommonWebApiResources.resx - - + + + True + Resources.resx + True + Properties\Resources.Designer.cs + - Properties\Resources.resx ResXFileCodeGenerator Resources.Designer.cs + Properties\Resources.resx Designer + + - - - CodeAnalysisDictionary.xml - - - - - - - - ..\..\packages\Newtonsoft.Json.13.0.1\lib\netstandard1.0\Newtonsoft.Json.dll - - - ..\..\packages\Microsoft.Net.Http.2.2.13\lib\portable-net40+sl4+win8+wp71\System.Net.Http.dll - - - ..\..\packages\Microsoft.Net.Http.2.2.13\lib\portable-net40+sl4+win8+wp71\System.Net.Http.Extensions.dll - - - ..\..\packages\Microsoft.Net.Http.2.2.13\lib\portable-net40+sl4+win8+wp71\System.Net.Http.Primitives.dll - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - \ No newline at end of file + diff --git a/src/System.Net.Http.Formatting.NetCore/packages.config b/src/System.Net.Http.Formatting.NetCore/packages.config deleted file mode 100644 index ba452cd0f..000000000 --- a/src/System.Net.Http.Formatting.NetCore/packages.config +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/src/System.Net.Http.Formatting.NetStandard/System.Net.Http.Formatting.NetStandard.csproj b/src/System.Net.Http.Formatting.NetStandard/System.Net.Http.Formatting.NetStandard.csproj index 2021cff78..ba3a97a38 100644 --- a/src/System.Net.Http.Formatting.NetStandard/System.Net.Http.Formatting.NetStandard.csproj +++ b/src/System.Net.Http.Formatting.NetStandard/System.Net.Http.Formatting.NetStandard.csproj @@ -1,4 +1,4 @@ - + netstandard2.0 @@ -13,67 +13,52 @@ $(Configurations);CodeAnalysis false + + + + - - - - Properties\CommonAssemblyInfo.cs - - - Common\CollectionExtensions.cs - - - Common\Error.cs - - - Common\ListWrapperCollection.cs - - - Common\TaskHelpers.cs - - - Common\TaskHelpersExtensions.cs - - - Common\UriQueryUtility.cs - + + + + + + - + %(RecursiveDir)\%(Filename).cs - - + - Properties\CommonWebApiResources.Designer.cs True - True CommonWebApiResources.resx + True + Properties\CommonWebApiResources.Designer.cs - Properties\CommonWebApiResources.resx ResXFileCodeGenerator CommonWebApiResources.Designer.cs + Properties\CommonWebApiResources.resx - - - + + True - True Resources.resx + True + Properties\Resources.Designer.cs - Properties\Resources.resx ResXFileCodeGenerator Resources.Designer.cs + Properties\Resources.resx Designer - - - - CodeAnalysisDictionary.xml - + + diff --git a/src/System.Net.Http.Formatting/Formatting/BaseJsonMediaTypeFormatter.cs b/src/System.Net.Http.Formatting/Formatting/BaseJsonMediaTypeFormatter.cs index b30a22edf..300716228 100644 --- a/src/System.Net.Http.Formatting/Formatting/BaseJsonMediaTypeFormatter.cs +++ b/src/System.Net.Http.Formatting/Formatting/BaseJsonMediaTypeFormatter.cs @@ -10,9 +10,7 @@ using System.Threading.Tasks; using System.Web.Http; using Newtonsoft.Json; -#if !NETFX_CORE using Newtonsoft.Json.Serialization; -#endif namespace System.Net.Http.Formatting { @@ -24,9 +22,7 @@ public abstract class BaseJsonMediaTypeFormatter : MediaTypeFormatter // Though MaxDepth is not supported in portable library, we still override JsonReader's MaxDepth private int _maxDepth = FormattingUtilities.DefaultMaxDepth; -#if !NETFX_CORE // DataContractResolver is not supported in portable library private readonly IContractResolver _defaultContractResolver; -#endif private JsonSerializerSettings _jsonSerializerSettings; @@ -36,9 +32,7 @@ public abstract class BaseJsonMediaTypeFormatter : MediaTypeFormatter protected BaseJsonMediaTypeFormatter() { // Initialize serializer settings -#if !NETFX_CORE // DataContractResolver is not supported in portable library _defaultContractResolver = new JsonContractResolver(this); -#endif _jsonSerializerSettings = CreateDefaultSerializerSettings(); // Set default supported character encodings @@ -50,19 +44,15 @@ protected BaseJsonMediaTypeFormatter() /// Initializes a new instance of the class. /// /// The instance to copy settings from. -#if !NETFX_CORE [SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors", Justification = "MaxDepth is sealed in existing subclasses and its documentation carries warnings.")] -#endif protected BaseJsonMediaTypeFormatter(BaseJsonMediaTypeFormatter formatter) : base(formatter) { Contract.Assert(formatter != null); SerializerSettings = formatter.SerializerSettings; -#if !NETFX_CORE // MaxDepth is not supported in portable library and so _maxDepth never changes there MaxDepth = formatter._maxDepth; -#endif } /// @@ -82,7 +72,6 @@ public JsonSerializerSettings SerializerSettings } } -#if !NETFX_CORE // MaxDepth is not supported in portable library /// /// Gets or sets the maximum depth allowed by this formatter. /// @@ -106,22 +95,15 @@ public virtual int MaxDepth _maxDepth = value; } } -#endif /// /// Creates a instance with the default settings used by the . /// -#if NETFX_CORE - [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "This could only be static half the time.")] -#endif public JsonSerializerSettings CreateDefaultSerializerSettings() { return new JsonSerializerSettings() { -#if !NETFX_CORE // DataContractResolver is not supported in portable library ContractResolver = _defaultContractResolver, -#endif - MissingMemberHandling = MissingMemberHandling.Ignore, // Do not change this setting diff --git a/src/System.Net.Http.Formatting/Formatting/BsonMediaTypeFormatter.cs b/src/System.Net.Http.Formatting/Formatting/BsonMediaTypeFormatter.cs index 99b8cca5b..b6d0a8351 100644 --- a/src/System.Net.Http.Formatting/Formatting/BsonMediaTypeFormatter.cs +++ b/src/System.Net.Http.Formatting/Formatting/BsonMediaTypeFormatter.cs @@ -11,12 +11,7 @@ using System.Threading.Tasks; using System.Web.Http; using Newtonsoft.Json; -#if NETFX_CORE using Newtonsoft.Json.Bson; -#else -using BsonReader = Newtonsoft.Json.Bson.BsonDataReader; -using BsonWriter = Newtonsoft.Json.Bson.BsonDataWriter; -#endif namespace System.Net.Http.Formatting { @@ -65,7 +60,6 @@ public static MediaTypeHeaderValue DefaultMediaType } } -#if !NETFX_CORE // MaxDepth and DBNull not supported in portable library; no need to override there /// public sealed override int MaxDepth { @@ -79,6 +73,7 @@ public sealed override int MaxDepth } } +#if !NETFX_CORE // DBNull not supported in portable library; no need to override there /// public override Task ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger) { @@ -200,13 +195,7 @@ public override JsonReader CreateJsonReader(Type type, Stream readStream, Encodi throw Error.ArgumentNull("effectiveEncoding"); } -#if NETFX_CORE -#pragma warning disable CS0618 // Type or member is obsolete -#endif - BsonReader reader = new BsonReader(new BinaryReader(readStream, effectiveEncoding)); -#if NETFX_CORE -#pragma warning restore CS0618 // Type or member is obsolete -#endif + BsonDataReader reader = new BsonDataReader(new BinaryReader(readStream, effectiveEncoding)); try { @@ -303,13 +292,7 @@ public override JsonWriter CreateJsonWriter(Type type, Stream writeStream, Encod throw Error.ArgumentNull("effectiveEncoding"); } -#if NETFX_CORE -#pragma warning disable CS0618 // Type or member is obsolete -#endif - return new BsonWriter(new BinaryWriter(writeStream, effectiveEncoding)); -#if NETFX_CORE -#pragma warning restore CS0618 // Type or member is obsolete -#endif + return new BsonDataWriter(new BinaryWriter(writeStream, effectiveEncoding)); } // Return true if Json.Net will likely convert value of given type to a Json primitive, not JsonArray nor @@ -319,15 +302,10 @@ private static bool IsSimpleType(Type type) { Contract.Assert(type != null); - bool isSimpleType; -#if NETFX_CORE // TypeDescriptor is not supported in portable library - isSimpleType = type.IsValueType() || type == typeof(string); -#else // CanConvertFrom() check is similar to MVC / Web API ModelMetadata.IsComplexType getters. This is // sufficient for many cases but Json.Net uses JsonConverterAttribute and built-in converters, not type // descriptors. - isSimpleType = TypeDescriptor.GetConverter(type).CanConvertFrom(typeof(string)); -#endif + bool isSimpleType = TypeDescriptor.GetConverter(type).CanConvertFrom(typeof(string)); return isSimpleType; } diff --git a/src/System.Net.Http.Formatting/Formatting/FormDataCollection.cs b/src/System.Net.Http.Formatting/Formatting/FormDataCollection.cs index 17ce38c8e..74a5ea549 100644 --- a/src/System.Net.Http.Formatting/Formatting/FormDataCollection.cs +++ b/src/System.Net.Http.Formatting/Formatting/FormDataCollection.cs @@ -5,18 +5,12 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.Diagnostics.CodeAnalysis; -#if !NETFX_CORE using System.Net.Http.Formatting.Internal; -#endif using System.Net.Http.Formatting.Parsers; using System.Text; using System.Threading; using System.Web.Http; -#if NETFX_CORE -using NameValueCollection = System.Net.Http.Formatting.HttpValueCollection; -#endif - namespace System.Net.Http.Formatting { /// @@ -25,12 +19,7 @@ namespace System.Net.Http.Formatting /// - using interfaces allows us to optimize the implementation. E.g., we can avoid eagerly string-splitting a 10gb file. /// - This also provides a convenient place to put extension methods. /// -#if NETFX_CORE - internal -#else - public -#endif - class FormDataCollection : IEnumerable> + public class FormDataCollection : IEnumerable> { private readonly IEnumerable> _pairs; diff --git a/src/System.Net.Http.Formatting/Formatting/JsonContractResolver.cs b/src/System.Net.Http.Formatting/Formatting/JsonContractResolver.cs index 95543f96b..dad07b236 100644 --- a/src/System.Net.Http.Formatting/Formatting/JsonContractResolver.cs +++ b/src/System.Net.Http.Formatting/Formatting/JsonContractResolver.cs @@ -29,8 +29,11 @@ public JsonContractResolver(MediaTypeFormatter formatter) } _formatter = formatter; + +#if !NETFX_CORE // Need this setting to have [Serializable] types serialized correctly IgnoreSerializableAttribute = false; +#endif } // Determines whether a member is required or not and sets the appropriate JsonProperty settings diff --git a/src/System.Net.Http.Formatting/Formatting/JsonMediaTypeFormatter.cs b/src/System.Net.Http.Formatting/Formatting/JsonMediaTypeFormatter.cs index 23b2908bb..41344e9c8 100644 --- a/src/System.Net.Http.Formatting/Formatting/JsonMediaTypeFormatter.cs +++ b/src/System.Net.Http.Formatting/Formatting/JsonMediaTypeFormatter.cs @@ -1,26 +1,18 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -#if !NETFX_CORE using System.Collections.Concurrent; using System.Diagnostics.CodeAnalysis; -#endif using System.Diagnostics.Contracts; using System.IO; using System.Net.Http.Headers; -#if !NETFX_CORE using System.Net.Http.Internal; using System.Runtime.Serialization.Json; -#endif using System.Text; using System.Threading; -#if !NETFX_CORE using System.Threading.Tasks; -#endif using System.Web.Http; -#if !NETFX_CORE using System.Xml; -#endif using Newtonsoft.Json; namespace System.Net.Http.Formatting @@ -30,11 +22,9 @@ namespace System.Net.Http.Formatting /// public class JsonMediaTypeFormatter : BaseJsonMediaTypeFormatter { -#if !NETFX_CORE // DataContractJsonSerializer and MediaTypeMappings are not supported in portable library - private ConcurrentDictionary _dataContractSerializerCache = new ConcurrentDictionary(); - private XmlDictionaryReaderQuotas _readerQuotas = FormattingUtilities.CreateDefaultReaderQuotas(); - private RequestHeaderMapping _requestHeaderMapping; -#endif + private readonly ConcurrentDictionary _dataContractSerializerCache = new ConcurrentDictionary(); + private readonly XmlDictionaryReaderQuotas _readerQuotas = FormattingUtilities.CreateDefaultReaderQuotas(); + private readonly RequestHeaderMapping _requestHeaderMapping; /// /// Initializes a new instance of the class. @@ -45,10 +35,8 @@ public JsonMediaTypeFormatter() SupportedMediaTypes.Add(MediaTypeConstants.ApplicationJsonMediaType); SupportedMediaTypes.Add(MediaTypeConstants.TextJsonMediaType); -#if !NETFX_CORE // MediaTypeMappings are not supported in portable library _requestHeaderMapping = new XmlHttpRequestHeaderMapping(); MediaTypeMappings.Add(_requestHeaderMapping); -#endif } /// @@ -60,10 +48,7 @@ protected JsonMediaTypeFormatter(JsonMediaTypeFormatter formatter) { Contract.Assert(formatter != null); -#if !NETFX_CORE // UseDataContractJsonSerializer is not supported in portable library UseDataContractJsonSerializer = formatter.UseDataContractJsonSerializer; -#endif - Indent = formatter.Indent; } @@ -84,7 +69,6 @@ public static MediaTypeHeaderValue DefaultMediaType get { return MediaTypeConstants.ApplicationJsonMediaType; } } -#if !NETFX_CORE // DataContractJsonSerializer is not supported in portable library /// /// Gets or sets a value indicating whether to use by default. /// @@ -92,14 +76,12 @@ public static MediaTypeHeaderValue DefaultMediaType /// true if use by default; otherwise, false. The default is false. /// public bool UseDataContractJsonSerializer { get; set; } -#endif /// /// Gets or sets a value indicating whether to indent elements when writing data. /// public bool Indent { get; set; } -#if !NETFX_CORE // MaxDepth not supported in portable library; no need to override there /// public sealed override int MaxDepth { @@ -113,7 +95,6 @@ public sealed override int MaxDepth _readerQuotas.MaxDepth = value; } } -#endif /// public override JsonReader CreateJsonReader(Type type, Stream readStream, Encoding effectiveEncoding) @@ -163,7 +144,6 @@ public override JsonWriter CreateJsonWriter(Type type, Stream writeStream, Encod return jsonWriter; } -#if !NETFX_CORE // DataContractJsonSerializer not supported in portable library; no need to override there /// public override bool CanReadType(Type type) { @@ -233,10 +213,26 @@ public override object ReadFromStream(Type type, Stream readStream, Encoding eff if (UseDataContractJsonSerializer) { DataContractJsonSerializer dataContractSerializer = GetDataContractSerializer(type); - using (XmlReader reader = JsonReaderWriterFactory.CreateJsonReader(new NonClosingDelegatingStream(readStream), effectiveEncoding, _readerQuotas, null)) + + // JsonReaderWriterFactory is internal, CreateTextReader only supports auto-detecting the encoding + // and auto-detection fails in some cases for the NETFX_CORE project. In addition, DCS encodings are + // limited to UTF8, UTF16BE, and UTF16LE. Convert to UTF8 as we read. + Stream innerStream = string.Equals(effectiveEncoding.WebName, Utf8Encoding.WebName, StringComparison.OrdinalIgnoreCase) ? + new NonClosingDelegatingStream(readStream) : + new TranscodingStream(readStream, effectiveEncoding, Utf8Encoding, leaveOpen: true); + +#if NETFX_CORE + using (innerStream) { - return dataContractSerializer.ReadObject(reader); + // Unfortunately, we're ignoring _readerQuotas. + return dataContractSerializer.ReadObject(innerStream); } +#else + // XmlDictionaryReader will always dispose of innerStream when we dispose of the reader. + using XmlDictionaryReader reader = + JsonReaderWriterFactory.CreateJsonReader(innerStream, Utf8Encoding, _readerQuotas, onClose: null); + return dataContractSerializer.ReadObject(reader); +#endif } else { @@ -294,10 +290,18 @@ public override void WriteToStream(Type type, object value, Stream writeStream, } } - DataContractJsonSerializer dataContractSerializer = GetDataContractSerializer(type); - using (XmlWriter writer = JsonReaderWriterFactory.CreateJsonWriter(writeStream, effectiveEncoding, ownsStream: false)) + WritePreamble(writeStream, effectiveEncoding); + if (string.Equals(effectiveEncoding.WebName, Utf8Encoding.WebName, StringComparison.OrdinalIgnoreCase)) + { + WriteObject(writeStream, type, value); + } + else { - dataContractSerializer.WriteObject(writer, value); + // JsonReaderWriterFactory is internal and DataContractJsonSerializer only writes UTF8 for the + // NETFX_CORE project. In addition, DCS encodings are limited to UTF8, UTF16BE, and UTF16LE. + // Convert to UTF8 as we write. + using var innerStream = new TranscodingStream(writeStream, effectiveEncoding, Utf8Encoding, leaveOpen: true); + WriteObject(innerStream, type, value); } } else @@ -306,6 +310,19 @@ public override void WriteToStream(Type type, object value, Stream writeStream, } } + private void WriteObject(Stream stream, Type type, object value) + { + DataContractJsonSerializer dataContractSerializer = GetDataContractSerializer(type); + + // Do not dispose of the stream. WriteToStream handles that where it's needed. +#if NETFX_CORE + dataContractSerializer.WriteObject(stream, value); +#else + using XmlWriter writer = JsonReaderWriterFactory.CreateJsonWriter(stream, Utf8Encoding, ownsStream: false); + dataContractSerializer.WriteObject(writer, value); +#endif + } + [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Catch all is around an extensibile method")] private DataContractJsonSerializer CreateDataContractSerializer(Type type, bool throwOnError) { @@ -316,8 +333,11 @@ private DataContractJsonSerializer CreateDataContractSerializer(Type type, bool try { +#if !NETFX_CORE // XsdDataContractExporter is not supported in portable libraries // Verify that type is a valid data contract by forcing the serializer to try to create a data contract FormattingUtilities.XsdDataContractExporter.GetRootElementName(type); +#endif + serializer = CreateDataContractSerializer(type); } catch (Exception caught) @@ -378,6 +398,5 @@ private DataContractJsonSerializer GetDataContractSerializer(Type type) return serializer; } -#endif } } diff --git a/src/System.Net.Http.Formatting/Formatting/MediaTypeFormatter.cs b/src/System.Net.Http.Formatting/Formatting/MediaTypeFormatter.cs index 367fba74a..20eace069 100644 --- a/src/System.Net.Http.Formatting/Formatting/MediaTypeFormatter.cs +++ b/src/System.Net.Http.Formatting/Formatting/MediaTypeFormatter.cs @@ -1,17 +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. -#if !NETFX_CORE // In portable library we have our own implementation of Concurrent Dictionary which is in the internal namespace using System.Collections.Concurrent; -#endif using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; using System.Linq; using System.Net.Http.Headers; -#if NETFX_CORE // In portable library we have our own implementation of Concurrent Dictionary which is in the internal namespace -using System.Net.Http.Internal; -#endif using System.Reflection; using System.Text; using System.Threading; @@ -25,6 +20,8 @@ namespace System.Net.Http.Formatting /// public abstract class MediaTypeFormatter { + private protected static readonly Encoding Utf8Encoding = + new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true); private const int DefaultMinHttpCollectionKeys = 1; private const int DefaultMaxHttpCollectionKeys = 1000; // same default as ASPNET private const string IWellKnownComparerTypeName = "System.IWellKnownStringEqualityComparer, mscorlib, Version=4.0.0.0, PublicKeyToken=b77a5c561934e089"; @@ -36,10 +33,8 @@ public abstract class MediaTypeFormatter private readonly List _supportedMediaTypes; private readonly List _supportedEncodings; -#if !NETFX_CORE // No MediaTypeMappings in portable library or IRequiredMemberSelector (no model state on client) private readonly List _mediaTypeMappings; private IRequiredMemberSelector _requiredMemberSelector; -#endif /// /// Initializes a new instance of the class. @@ -50,10 +45,8 @@ protected MediaTypeFormatter() SupportedMediaTypes = new MediaTypeHeaderValueCollection(_supportedMediaTypes); _supportedEncodings = new List(); SupportedEncodings = new Collection(_supportedEncodings); -#if !NETFX_CORE // No MediaTypeMappings in portable library _mediaTypeMappings = new List(); MediaTypeMappings = new Collection(_mediaTypeMappings); -#endif } /// @@ -71,11 +64,9 @@ protected MediaTypeFormatter(MediaTypeFormatter formatter) SupportedMediaTypes = formatter.SupportedMediaTypes; _supportedEncodings = formatter._supportedEncodings; SupportedEncodings = formatter.SupportedEncodings; -#if !NETFX_CORE // No MediaTypeMappings in portable library or IRequiredMemberSelector (no model state on client) _mediaTypeMappings = formatter._mediaTypeMappings; MediaTypeMappings = formatter.MediaTypeMappings; _requiredMemberSelector = formatter._requiredMemberSelector; -#endif } /// @@ -126,7 +117,6 @@ internal List SupportedEncodingsInternal get { return _supportedEncodings; } } -#if !NETFX_CORE // No MediaTypeMappings in portable library /// /// Gets the mutable collection of elements used /// by this instance to determine the @@ -138,9 +128,7 @@ internal List MediaTypeMappingsInternal { get { return _mediaTypeMappings; } } -#endif -#if !NETFX_CORE // IRequiredMemberSelector is not in portable libraries because there is no model state on the client. /// /// Gets or sets the used to determine required members. /// @@ -155,7 +143,6 @@ public virtual IRequiredMemberSelector RequiredMemberSelector _requiredMemberSelector = value; } } -#endif internal virtual bool CanWriteAnyTypes { @@ -504,6 +491,15 @@ public static object GetDefaultValueForType(Type type) return null; } + private protected static void WritePreamble(Stream stream, Encoding encoding) + { + byte[] bytes = encoding.GetPreamble(); + if (bytes.Length > 0) + { + stream.Write(bytes, 0, bytes.Length); + } + } + /// /// Collection class that validates it contains only instances /// that are not null and not media ranges. diff --git a/src/System.Net.Http.Formatting/Formatting/MediaTypeFormatterCollection.cs b/src/System.Net.Http.Formatting/Formatting/MediaTypeFormatterCollection.cs index 17a4959ba..4320d1ff6 100644 --- a/src/System.Net.Http.Formatting/Formatting/MediaTypeFormatterCollection.cs +++ b/src/System.Net.Http.Formatting/Formatting/MediaTypeFormatterCollection.cs @@ -198,9 +198,7 @@ public MediaTypeFormatter FindWriter(Type type, MediaTypeHeaderValue mediaType) public static bool IsTypeExcludedFromValidation(Type type) { return -#if !NETFX_CORE typeof(XmlNode).IsAssignableFrom(type) || -#endif typeof(FormDataCollection).IsAssignableFrom(type) || FormattingUtilities.IsJTokenType(type) || typeof(XObject).IsAssignableFrom(type) || diff --git a/src/System.Net.Http.Formatting/Formatting/Parsers/FormUrlEncodedParser.cs b/src/System.Net.Http.Formatting/Formatting/Parsers/FormUrlEncodedParser.cs index 6a4f42024..90754c123 100644 --- a/src/System.Net.Http.Formatting/Formatting/Parsers/FormUrlEncodedParser.cs +++ b/src/System.Net.Http.Formatting/Formatting/Parsers/FormUrlEncodedParser.cs @@ -275,9 +275,9 @@ public StringBuilder Value /// The collection to copy into. public void CopyTo(ICollection> nameValuePairs) { - string unescapedName = UriQueryUtility.UrlDecode(_name.ToString()); + string unescapedName = WebUtility.UrlDecode(_name.ToString()); string escapedValue = _value.ToString(); - string value = UriQueryUtility.UrlDecode(escapedValue); + string value = WebUtility.UrlDecode(escapedValue); nameValuePairs.Add(new KeyValuePair(unescapedName, value)); @@ -290,7 +290,7 @@ public void CopyTo(ICollection> nameValuePairs) /// The collection to copy into. public void CopyNameOnlyTo(ICollection> nameValuePairs) { - string unescapedName = UriQueryUtility.UrlDecode(_name.ToString()); + string unescapedName = WebUtility.UrlDecode(_name.ToString()); string value = String.Empty; nameValuePairs.Add(new KeyValuePair(unescapedName, value)); Clear(); diff --git a/src/System.Net.Http.Formatting/Formatting/XmlMediaTypeFormatter.cs b/src/System.Net.Http.Formatting/Formatting/XmlMediaTypeFormatter.cs index 2ffd75975..9e858e5cb 100644 --- a/src/System.Net.Http.Formatting/Formatting/XmlMediaTypeFormatter.cs +++ b/src/System.Net.Http.Formatting/Formatting/XmlMediaTypeFormatter.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. -#if !NETFX_CORE // In portable library we have our own implementation of Concurrent Dictionary which is in the internal namespace using System.Collections.Concurrent; -#endif using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; @@ -57,9 +55,7 @@ protected XmlMediaTypeFormatter(XmlMediaTypeFormatter formatter) { UseXmlSerializer = formatter.UseXmlSerializer; WriterSettings = formatter.WriterSettings; -#if !NETFX_CORE // MaxDepth is not supported in portable libraries MaxDepth = formatter.MaxDepth; -#endif } /// @@ -108,7 +104,6 @@ public bool Indent /// public XmlWriterSettings WriterSettings { get; private set; } -#if !NETFX_CORE // MaxDepth is not supported in portable libraries /// /// Gets or sets the maximum depth allowed by this formatter. /// @@ -128,7 +123,6 @@ public int MaxDepth _readerQuotas.MaxDepth = value; } } -#endif /// /// Registers the to use to read or write @@ -343,12 +337,14 @@ protected internal virtual XmlReader CreateXmlReader(Stream readStream, HttpCont { // Get the character encoding for the content Encoding effectiveEncoding = SelectCharacterEncoding(content == null ? null : content.Headers); -#if NETFX_CORE - // Force a preamble into the stream, since CreateTextReader in WinRT only supports auto-detecting encoding. - return XmlDictionaryReader.CreateTextReader(new ReadOnlyStreamWithEncodingPreamble(readStream, effectiveEncoding), _readerQuotas); -#else - return XmlDictionaryReader.CreateTextReader(new NonClosingDelegatingStream(readStream), effectiveEncoding, _readerQuotas, null); -#endif + + // DCS encodings are limited to UTF8, UTF16BE, and UTF16LE. Convert to UTF8 as we read. + Stream innerStream = string.Equals(effectiveEncoding.WebName, Utf8Encoding.WebName, StringComparison.OrdinalIgnoreCase) ? + new NonClosingDelegatingStream(readStream) : + new TranscodingStream(readStream, effectiveEncoding, Utf8Encoding, leaveOpen: true); + + // XmlDictionaryReader will always dispose of innerStream when caller disposes of the reader. + return XmlDictionaryReader.CreateTextReader(innerStream, Utf8Encoding, _readerQuotas, onClose: null); } /// @@ -439,9 +435,20 @@ protected internal virtual object GetSerializer(Type type, object value, HttpCon protected internal virtual XmlWriter CreateXmlWriter(Stream writeStream, HttpContent content) { Encoding effectiveEncoding = SelectCharacterEncoding(content != null ? content.Headers : null); + WritePreamble(writeStream, effectiveEncoding); + + // DCS encodings are limited to UTF8, UTF16BE, and UTF16LE. Convert to UTF8 as we read. + Stream innerStream = string.Equals(effectiveEncoding.WebName, Utf8Encoding.WebName, StringComparison.OrdinalIgnoreCase) ? + writeStream : + new TranscodingStream(writeStream, effectiveEncoding, Utf8Encoding, leaveOpen: true); + XmlWriterSettings writerSettings = WriterSettings.Clone(); - writerSettings.Encoding = effectiveEncoding; - return XmlWriter.Create(writeStream, writerSettings); + writerSettings.Encoding = Utf8Encoding; + + // Have XmlWriter dispose of innerStream when caller disposes of the writer if using a TranscodingStream. + writerSettings.CloseOutput = writeStream != innerStream; + + return XmlWriter.Create(innerStream, writerSettings); } /// @@ -515,11 +522,12 @@ private object CreateDefaultSerializer(Type type, bool throwOnError) } else { -#if !NETFX_CORE +#if !NETFX_CORE // XsdDataContractExporter is not supported in portable libraries // REVIEW: Is there something comparable in WinRT? // Verify that type is a valid data contract by forcing the serializer to try to create a data contract FormattingUtilities.XsdDataContractExporter.GetRootElementName(type); #endif + serializer = CreateDataContractSerializer(type); } } diff --git a/src/System.Net.Http.Formatting/FormattingUtilities.cs b/src/System.Net.Http.Formatting/FormattingUtilities.cs index a1ac95595..897bcd21f 100644 --- a/src/System.Net.Http.Formatting/FormattingUtilities.cs +++ b/src/System.Net.Http.Formatting/FormattingUtilities.cs @@ -166,9 +166,6 @@ public static HttpContentHeaders CreateEmptyContentHeaders() /// public static XmlDictionaryReaderQuotas CreateDefaultReaderQuotas() { -#if NETFX_CORE // MaxDepth is a DOS mitigation. We don't support MaxDepth in portable libraries because it is strictly client side. - return XmlDictionaryReaderQuotas.Max; -#else return new XmlDictionaryReaderQuotas() { MaxArrayLength = Int32.MaxValue, @@ -177,7 +174,6 @@ public static XmlDictionaryReaderQuotas CreateDefaultReaderQuotas() MaxNameTableCharCount = Int32.MaxValue, MaxStringContentLength = Int32.MaxValue }; -#endif } /// diff --git a/src/System.Net.Http.Formatting/HttpContentFormDataExtensions.cs b/src/System.Net.Http.Formatting/HttpContentFormDataExtensions.cs index 4a830684d..72ebb40c7 100644 --- a/src/System.Net.Http.Formatting/HttpContentFormDataExtensions.cs +++ b/src/System.Net.Http.Formatting/HttpContentFormDataExtensions.cs @@ -8,9 +8,6 @@ using System.Threading; using System.Threading.Tasks; using System.Web.Http; -#if NETFX_CORE -using NameValueCollection = System.Net.Http.Formatting.HttpValueCollection; -#endif namespace System.Net.Http { diff --git a/src/System.Net.Http.Formatting/Internal/ByteRangeStream.cs b/src/System.Net.Http.Formatting/Internal/ByteRangeStream.cs index 33325d4f4..bf3d4371f 100644 --- a/src/System.Net.Http.Formatting/Internal/ByteRangeStream.cs +++ b/src/System.Net.Http.Formatting/Internal/ByteRangeStream.cs @@ -111,10 +111,12 @@ public override long Position } } +#if !NETFX_CORE // BeginX and EndX are not supported on streams in portable libraries public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { return base.BeginRead(buffer, offset, PrepareStreamForRangeRead(count), callback, state); } +#endif public override int Read(byte[] buffer, int offset, int count) { @@ -172,6 +174,7 @@ public override void Write(byte[] buffer, int offset, int count) throw Error.NotSupported(Properties.Resources.ByteRangeStreamReadOnly); } +#if !NETFX_CORE // BeginX and EndX are not supported on streams in portable libraries public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { throw Error.NotSupported(Properties.Resources.ByteRangeStreamReadOnly); @@ -181,6 +184,7 @@ public override void EndWrite(IAsyncResult asyncResult) { throw Error.NotSupported(Properties.Resources.ByteRangeStreamReadOnly); } +#endif public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { diff --git a/src/System.Net.Http.Formatting/Internal/HttpValueCollection.cs b/src/System.Net.Http.Formatting/Internal/HttpValueCollection.cs index 3197a9733..72f28d4cd 100644 --- a/src/System.Net.Http.Formatting/Internal/HttpValueCollection.cs +++ b/src/System.Net.Http.Formatting/Internal/HttpValueCollection.cs @@ -1,14 +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. -#if NETFX_CORE -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics.Contracts; -using System.Linq; -using System.Text; -using System.Web.Http; -#else using System.Collections.Generic; using System.Collections.Specialized; using System.Diagnostics.Contracts; @@ -17,45 +9,29 @@ using System.Runtime.Serialization; using System.Text; using System.Web.Http; -#endif -#if NETFX_CORE -namespace System.Net.Http.Formatting -#else namespace System.Net.Http.Formatting.Internal -#endif { /// /// NameValueCollection to represent form data and to generate form data output. /// -#if NETFX_CORE - public class HttpValueCollection : IEnumerable> -#else +#if !NETFX_CORE // NameValueCollection is not serializable in netstandard1.3. [Serializable] - internal class HttpValueCollection : NameValueCollection #endif + internal class HttpValueCollection : NameValueCollection { -#if NETFX_CORE - internal readonly HashSet Names = new HashSet(StringComparer.OrdinalIgnoreCase); - internal readonly List> List = new List>(); - - /// - /// Creates a new instance - /// - public HttpValueCollection() - { - } -#else +#if !NETFX_CORE // NameValueCollection is not serializable in netstandard1.3. protected HttpValueCollection(SerializationInfo info, StreamingContext context) : base(info, context) { } +#endif private HttpValueCollection() : base(StringComparer.OrdinalIgnoreCase) // case-insensitive keys { } -#endif + // Use a builder function instead of a ctor to avoid virtual calls from the ctor. // The above condition is only important in the Full .NET fx implementation. internal static HttpValueCollection Create() @@ -75,9 +51,8 @@ internal static HttpValueCollection Create(IEnumerable /// The name to be added as a case insensitive string. /// The value to be added. - public -#if !NETFX_CORE - override -#endif - void Add(string name, string value) + public override void Add(string name, string value) { ThrowIfMaxHttpCollectionKeysExceeded(Count); name = name ?? String.Empty; value = value ?? String.Empty; -#if NETFX_CORE - Names.Add(name); - List.Add(new KeyValuePair(name, value)); -#else base.Add(name, value); -#endif } /// @@ -131,11 +97,7 @@ private string ToString(bool urlEncode) StringBuilder builder = new StringBuilder(); bool first = true; -#if NETFX_CORE - foreach (string name in Names) -#else foreach (string name in this) -#endif { string[] values = GetValues(name); if (values == null || values.Length == 0) @@ -157,10 +119,10 @@ private string ToString(bool urlEncode) private static bool AppendNameValuePair(StringBuilder builder, bool first, bool urlEncode, string name, string value) { string effectiveName = name ?? String.Empty; - string encodedName = urlEncode ? UriQueryUtility.UrlEncode(effectiveName) : effectiveName; + string encodedName = urlEncode ? WebUtility.UrlEncode(effectiveName) : effectiveName; string effectiveValue = value ?? String.Empty; - string encodedValue = urlEncode ? UriQueryUtility.UrlEncode(effectiveValue) : effectiveValue; + string encodedValue = urlEncode ? WebUtility.UrlEncode(effectiveValue) : effectiveValue; if (first) { @@ -179,104 +141,5 @@ private static bool AppendNameValuePair(StringBuilder builder, bool first, bool } return first; } - -#if NETFX_CORE - /// - /// Gets the values associated with the specified name - /// combined into one comma-separated list. - /// - /// The name of the entry that contains the values to get. The name can be null. - /// A that contains a comma-separated list of url encoded values associated - /// with the specified name if found; otherwise, null. The values are Url encoded. - public string this[string name] - { - get - { - return Get(name); - } - } - - /// - /// Gets the number of names in the collection. - /// - public int Count - { - get - { - return Names.Count; - } - } - - /// - /// Gets the values associated with the specified name - /// combined into one comma-separated list. - /// - /// The name of the entry that contains the values to get. The name can be null. - /// - /// A that contains a comma-separated list of url encoded values associated - /// with the specified name if found; otherwise, null. The values are Url encoded. - /// - public string Get(string name) - { - name = name ?? String.Empty; - - if (!Names.Contains(name)) - { - return null; - } - - List values = GetValuesInternal(name); - Contract.Assert(values != null && values.Count > 0); - - return String.Join(",", values); - } - - /// - /// Gets the values associated with the specified name. - /// - /// The - /// A that contains url encoded values associated with the name, or null if the name does not exist. - public string[] GetValues(string name) - { - name = name ?? String.Empty; - - if (!Names.Contains(name)) - { - return null; - } - - return GetValuesInternal(name).ToArray(); - } - - // call this when only when there are values available. - private List GetValuesInternal(string name) - { - List values = new List(); - - for (int i = 0; i < List.Count; i++) - { - KeyValuePair kvp = List[i]; - - if (String.Equals(kvp.Key, name, StringComparison.OrdinalIgnoreCase)) - { - values.Add(kvp.Value); - } - } - - return values; - } - - /// - public IEnumerator> GetEnumerator() - { - return List.GetEnumerator(); - } - - /// - IEnumerator IEnumerable.GetEnumerator() - { - return List.GetEnumerator(); - } -#endif } } diff --git a/src/System.Net.Http.Formatting/Internal/NonClosingDelegatingStream.cs b/src/System.Net.Http.Formatting/Internal/NonClosingDelegatingStream.cs index 5af2385b0..625bc8536 100644 --- a/src/System.Net.Http.Formatting/Internal/NonClosingDelegatingStream.cs +++ b/src/System.Net.Http.Formatting/Internal/NonClosingDelegatingStream.cs @@ -8,8 +8,8 @@ namespace System.Net.Http.Internal /// /// Stream that doesn't close the inner stream when closed. This is to work around a limitation /// in the insisting of closing the inner stream. - /// The regular does allow for not closing the inner stream but that - /// doesn't have the quota that we need for security reasons. Implementations of + /// The regular does allow for not closing the inner stream but that + /// doesn't have the quota that we need for security reasons. Implementations of /// /// should not close the input stream when reading or writing so hence this workaround. /// @@ -20,8 +20,14 @@ public NonClosingDelegatingStream(Stream innerStream) { } +#if NETFX_CORE + protected override void Dispose(bool disposing) + { + } +#else public override void Close() { } +#endif } } diff --git a/src/System.Net.Http.Formatting/Internal/NullableAttributes.cs b/src/System.Net.Http.Formatting/Internal/NullableAttributes.cs new file mode 100644 index 000000000..2344a2994 --- /dev/null +++ b/src/System.Net.Http.Formatting/Internal/NullableAttributes.cs @@ -0,0 +1,198 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// From https://github.com/dotnet/runtime/blob/88868b7a781f4e5b9037b8721f30440207a7aa42/src/tools/illink/src/ILLink.RoslynAnalyzer/NullableAttributes.cs + +namespace System.Diagnostics.CodeAnalysis +{ +#if !NETSTANDARD2_1 + /// Specifies that null is allowed as an input even if the corresponding type disallows it. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class AllowNullAttribute : Attribute { } + + /// Specifies that null is disallowed as an input even if the corresponding type allows it. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class DisallowNullAttribute : Attribute { } + + /// Specifies that an output may be null even if the corresponding type disallows it. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class MaybeNullAttribute : Attribute { } + + /// Specifies that an output will not be null even if the corresponding type allows it. Specifies that an input argument was not null when the call returns. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class NotNullAttribute : Attribute { } + + /// Specifies that when a method returns , the parameter may be null even if the corresponding type disallows it. + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class MaybeNullWhenAttribute : Attribute + { + /// Initializes the attribute with the specified return value condition. + /// + /// The return value condition. If the method returns this value, the associated parameter may be null. + /// + public MaybeNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; + + /// Gets the return value condition. + public bool ReturnValue { get; } + } + + /// Specifies that when a method returns , the parameter will not be null even if the corresponding type allows it. + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class NotNullWhenAttribute : Attribute + { + /// Initializes the attribute with the specified return value condition. + /// + /// The return value condition. If the method returns this value, the associated parameter will not be null. + /// + public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; + + /// Gets the return value condition. + public bool ReturnValue { get; } + } + + /// Specifies that the output will be non-null if the named parameter is non-null. + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class NotNullIfNotNullAttribute : Attribute + { + /// Initializes the attribute with the associated parameter name. + /// + /// The associated parameter name. The output will be non-null if the argument to the parameter specified is non-null. + /// + public NotNullIfNotNullAttribute(string parameterName) => ParameterName = parameterName; + + /// Gets the associated parameter name. + public string ParameterName { get; } + } + + /// Applied to a method that will never return under any circumstance. + [AttributeUsage(AttributeTargets.Method, Inherited = false)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class DoesNotReturnAttribute : Attribute { } + + /// Specifies that the method will not return if the associated Boolean parameter is passed the specified value. + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class DoesNotReturnIfAttribute : Attribute + { + /// Initializes the attribute with the specified parameter value. + /// + /// The condition parameter value. Code after the method will be considered unreachable by diagnostics if the argument to + /// the associated parameter matches this value. + /// + public DoesNotReturnIfAttribute(bool parameterValue) => ParameterValue = parameterValue; + + /// Gets the condition parameter value. + public bool ParameterValue { get; } + } +#endif + + /// Specifies that the method or property will ensure that the listed field and property members have not-null values. + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class MemberNotNullAttribute : Attribute + { + /// Initializes the attribute with a field or property member. + /// + /// The field or property member that is promised to be not-null. + /// + public MemberNotNullAttribute(string member) => Members = new[] { member }; + + /// Initializes the attribute with the list of field and property members. + /// + /// The list of field and property members that are promised to be not-null. + /// + public MemberNotNullAttribute(params string[] members) => Members = members; + + /// Gets field or property member names. + public string[] Members { get; } + } + + /// Specifies that the method or property will ensure that the listed field and property members have not-null values when returning with the specified return value condition. + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class MemberNotNullWhenAttribute : Attribute + { + /// Initializes the attribute with the specified return value condition and a field or property member. + /// + /// The return value condition. If the method returns this value, the associated parameter will not be null. + /// + /// + /// The field or property member that is promised to be not-null. + /// + public MemberNotNullWhenAttribute(bool returnValue, string member) + { + ReturnValue = returnValue; + Members = new[] { member }; + } + + /// Initializes the attribute with the specified return value condition and list of field and property members. + /// + /// The return value condition. If the method returns this value, the associated parameter will not be null. + /// + /// + /// The list of field and property members that are promised to be not-null. + /// + public MemberNotNullWhenAttribute(bool returnValue, params string[] members) + { + ReturnValue = returnValue; + Members = members; + } + + /// Gets the return value condition. + public bool ReturnValue { get; } + + /// Gets field or property member names. + public string[] Members { get; } + } +} diff --git a/src/System.Net.Http.Formatting/Internal/ReadOnlyStreamWithEncodingPreamble.cs b/src/System.Net.Http.Formatting/Internal/ReadOnlyStreamWithEncodingPreamble.cs deleted file mode 100644 index 923e4bd37..000000000 --- a/src/System.Net.Http.Formatting/Internal/ReadOnlyStreamWithEncodingPreamble.cs +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Diagnostics.Contracts; -using System.IO; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace System.Net.Http.Internal -{ - /// - /// This implements a read-only, forward-only stream around another readable stream, to ensure - /// that there is an appropriate encoding preamble in the stream. - /// - internal class ReadOnlyStreamWithEncodingPreamble : Stream - { - private static Task _cancelledTask = GetCancelledTask(); - private Stream _innerStream; - private ArraySegment _remainingBytes; - - public ReadOnlyStreamWithEncodingPreamble(Stream innerStream, Encoding encoding) - { - Contract.Assert(innerStream != null); - Contract.Assert(innerStream.CanRead); - Contract.Assert(encoding != null); - - _innerStream = innerStream; - - // Determine whether we even have a preamble to be concerned about - byte[] preamble = encoding.GetPreamble(); - int preambleLength = preamble.Length; - if (preambleLength <= 0) - { - return; - } - - // Create a double sized buffer, and read enough bytes from the stream to know - // whether we have a preamble present already or not. - int finalBufferLength = preambleLength * 2; - byte[] finalBuffer = new byte[finalBufferLength]; - int finalCount = preambleLength; - preamble.CopyTo(finalBuffer, 0); - - // Read the first bytes of the stream and see if they already contain a preamble - for (; finalCount < finalBufferLength; finalCount++) - { - int b = innerStream.ReadByte(); - if (b == -1) - { - break; - } - finalBuffer[finalCount] = (byte)b; - } - - // Did we read enough bytes to do the comparison? - if (finalCount == finalBufferLength) - { - bool foundPreamble = true; - for (int idx = 0; idx < preambleLength; idx++) - { - if (finalBuffer[idx] != finalBuffer[idx + preambleLength]) - { - foundPreamble = false; - break; - } - } - - // If we found the preamble, then just exclude it from the data that we return - if (foundPreamble) - { - finalCount = preambleLength; - } - } - - _remainingBytes = new ArraySegment(finalBuffer, 0, finalCount); - } - - public override bool CanRead - { - get { return true; } - } - - public override bool CanSeek - { - get { return false; } - } - - public override bool CanWrite - { - get { return false; } - } - - public override long Length - { - get { throw new NotImplementedException(); } - } - - public override long Position - { - get { throw new NotImplementedException(); } - set { throw new NotImplementedException(); } - } - - public override void Flush() - { - throw new NotImplementedException(); - } - - private static Task GetCancelledTask() - { - var tcs = new TaskCompletionSource(); - tcs.SetCanceled(); - return tcs.Task; - } - - public override int Read(byte[] buffer, int offset, int count) - { - byte[] remainingArray = _remainingBytes.Array; - if (remainingArray == null) - { - return _innerStream.Read(buffer, offset, count); - } - - int remainingCount = _remainingBytes.Count; - int remainingOffset = _remainingBytes.Offset; - int result = Math.Min(count, remainingCount); - - for (int idx = 0; idx < result; ++idx) - { - buffer[offset + idx] = remainingArray[remainingOffset + idx]; - } - - if (result == remainingCount) - { - _remainingBytes = default(ArraySegment); - } - else - { - _remainingBytes = new ArraySegment(remainingArray, remainingOffset + result, remainingCount - result); - } - - return result; - } - - public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - if (_remainingBytes.Array == null) - { - return _innerStream.ReadAsync(buffer, offset, count, cancellationToken); - } - if (cancellationToken.IsCancellationRequested) - { - return _cancelledTask; - } - - return Task.FromResult(Read(buffer, offset, count)); - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotImplementedException(); - } - - public override void SetLength(long value) - { - throw new NotImplementedException(); - } - - public override void Write(byte[] buffer, int offset, int count) - { - throw new NotImplementedException(); - } - } -} diff --git a/src/System.Net.Http.Formatting/Internal/TranscodingStream.cs b/src/System.Net.Http.Formatting/Internal/TranscodingStream.cs new file mode 100644 index 000000000..9f89eeee8 --- /dev/null +++ b/src/System.Net.Http.Formatting/Internal/TranscodingStream.cs @@ -0,0 +1,828 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// From https://github.com/dotnet/runtime/blob/88868b7a781f4e5b9037b8721f30440207a7aa42/src/libraries/System.Private.CoreLib/src/System/Text/TranscodingStream.cs + +using System.Buffers; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; +using System.Web.Http; +using Properties = System.Net.Http.Properties; + +#nullable enable + +namespace System.Text +{ + internal sealed class TranscodingStream : Stream + { + private const int DefaultReadByteBufferSize = 4 * 1024; // lifted from StreamReader.cs (FileStream) + + // We optimistically assume 1 byte ~ 1 char during transcoding. This is a good rule of thumb + // but isn't always appropriate: transcoding between single-byte and multi-byte encodings + // will violate this, as will any invalid data fixups performed by the transcoder itself. + // To account for these unknowns we have a minimum scratch buffer size we use during the + // transcoding process. This should be generous enough to account for even the largest + // fallback mechanism we're likely to see in the real world. + + private const int MinWriteRentedArraySize = 4 * 1024; + private const int MaxWriteRentedArraySize = 1024 * 1024; + + internal static readonly byte[] EmptyByteBuffer = new byte[0]; + internal static readonly char[] EmptyCharBuffer = new char[0]; + + private readonly Encoding _innerEncoding; + private readonly Encoding _thisEncoding; + private Stream _innerStream; // null if the wrapper has been disposed + private readonly bool _leaveOpen; + private readonly byte[] _singleByteBuffer = new byte[1]; + + /* + * Fields used for writing bytes [this] -> chars -> bytes [inner] + * Lazily initialized the first time we need to write + */ + + private Encoder? _innerEncoder; + private Decoder? _thisDecoder; + + /* + * Fields used for reading bytes [inner] -> chars -> bytes [this] + * Lazily initialized the first time we need to read + */ + + private Encoder? _thisEncoder; + private Decoder? _innerDecoder; + private int _readCharBufferMaxSize; // the maximum number of characters _innerDecoder.ReadChars can return + private byte[]? _readBuffer; // contains the data that Read() should return + private int _readBufferOffset; + private int _readBufferCount; + + internal TranscodingStream(Stream innerStream, Encoding innerEncoding, Encoding thisEncoding, bool leaveOpen = false) + { + _innerStream = innerStream ?? throw Error.ArgumentNull(nameof(innerStream)); + _leaveOpen = leaveOpen; + + _innerEncoding = innerEncoding ?? throw Error.ArgumentNull(nameof(innerEncoding)); + _thisEncoding = thisEncoding ?? throw Error.ArgumentNull(nameof(thisEncoding)); + } + + /* + * Most CanXyz methods delegate to the inner stream, returning false + * if this instance has been disposed. CanSeek is always false. + */ + + public override bool CanRead => _innerStream?.CanRead ?? false; + + public override bool CanSeek => false; + + public override bool CanWrite => _innerStream?.CanWrite ?? false; + + public override long Length => throw Error.NotSupported(Properties.Resources.NotSupported_UnseekableStream); + + public override long Position + { + get => throw Error.NotSupported(Properties.Resources.NotSupported_UnseekableStream); + set => throw Error.NotSupported(Properties.Resources.NotSupported_UnseekableStream); + } + + protected override void Dispose(bool disposing) + { + Debug.Assert(disposing, "This type isn't finalizable."); + base.Dispose(disposing); + + if (_innerStream is null) + { + return; // dispose called multiple times, ignore + } + + // First, flush any pending data to the inner stream. + + ArraySegment pendingData = FinalFlushWriteBuffers(); + if (pendingData.Count != 0) + { + _innerStream.Write(pendingData.Array, pendingData.Offset, pendingData.Count); + } + + // Mark our object as disposed + + Stream innerStream = _innerStream; + _innerStream = null!; + + // And dispose the inner stream if needed + + if (!_leaveOpen) + { + innerStream.Dispose(); + } + } + +#if NETCOREAPP3_1 || NET5_0_OR_GREATER || NETSTANDARD2_1 + public override ValueTask DisposeAsync() + { + if (_innerStream is null) + { + return default; // dispose called multiple times, ignore + } + + // First, get any pending data destined for the inner stream. + + ArraySegment pendingData = FinalFlushWriteBuffers(); + + if (pendingData.Count == 0) + { + // Fast path: just dispose of the object graph. + // No need to write anything to the stream first. + + Stream innerStream = _innerStream; + _innerStream = null!; + + return (_leaveOpen) + ? default /* no work to do */ + : innerStream.DisposeAsync(); + } + + // Slower path; need to perform an async write followed by an async dispose. + + return DisposeAsyncCore(pendingData); + async ValueTask DisposeAsyncCore(ArraySegment pendingData) + { + Debug.Assert(pendingData.Count != 0); + + Stream innerStream = _innerStream; + _innerStream = null!; + + await innerStream.WriteAsync(pendingData.AsMemory()).ConfigureAwait(false); + + if (!_leaveOpen) + { + await innerStream.DisposeAsync().ConfigureAwait(false); + } + } + } +#endif + +#pragma warning disable CS3016 // Arrays as attribute arguments is not CLS-compliant +#pragma warning disable CS8774 // Member must have a non-null value when exiting. + + // Sets up the data structures that are necessary before any read operation takes place, + // throwing if the object is in a state where reads are not possible. + [MemberNotNull(nameof(_innerDecoder), nameof(_thisEncoder), nameof(_readBuffer))] + private void EnsurePreReadConditions() + { + ThrowIfDisposed(); + if (_innerDecoder is null) + { + InitializeReadDataStructures(); + } + + void InitializeReadDataStructures() + { + if (!CanRead) + { + throw Error.NotSupported(Properties.Resources.NotSupported_UnreadableStream); + } + + _innerDecoder = _innerEncoding.GetDecoder(); + _thisEncoder = _thisEncoding.GetEncoder(); + _readCharBufferMaxSize = _innerEncoding.GetMaxCharCount(DefaultReadByteBufferSize); + + // Can't use ArrayPool for the below array since it's an instance field of this object. + // But since we never expose the raw array contents to our callers we can get away + // with skipping the array zero-init during allocation. The segment points to the + // data which we haven't yet read; however, we own the entire backing array and can + // re-create the segment as needed once the array is repopulated. + +#if NET5_0_OR_GREATER + _readBuffer = GC.AllocateUninitializedArray(_thisEncoding.GetMaxByteCount(_readCharBufferMaxSize)); +#else + _readBuffer = new byte[_thisEncoding.GetMaxByteCount(_readCharBufferMaxSize)]; +#endif + } + } + + // Sets up the data structures that are necessary before any write operation takes place, + // throwing if the object is in a state where writes are not possible. + [MemberNotNull(nameof(_thisDecoder), nameof(_innerEncoder))] + private void EnsurePreWriteConditions() + { + ThrowIfDisposed(); + if (_innerEncoder is null) + { + InitializeReadDataStructures(); + } + + void InitializeReadDataStructures() + { + if (!CanWrite) + { + throw Error.NotSupported(Properties.Resources.NotSupported_UnwritableStream); + } + + _innerEncoder = _innerEncoding.GetEncoder(); + _thisDecoder = _thisEncoding.GetDecoder(); + } + } + +#pragma warning restore CS8774 // Member must have a non-null value when exiting. +#pragma warning restore CS3016 // Arrays as attribute arguments is not CLS-compliant + + // returns any pending data that needs to be flushed to the inner stream before disposal + private ArraySegment FinalFlushWriteBuffers() + { + // If this stream was never used for writing, no-op. + + if (_thisDecoder is null || _innerEncoder is null) + { + return default; + } + + // convert bytes [this] -> chars + // Having leftover data in our buffers should be very rare since it should only + // occur if the end of the stream contains an incomplete multi-byte sequence. + // Let's not bother complicating this logic with array pool rentals or allocation- + // avoiding loops. + + char[] chars = EmptyCharBuffer; + int charCount = _thisDecoder.GetCharCount(EmptyByteBuffer, 0, 0, flush: true); + if (charCount > 0) + { + chars = new char[charCount]; + charCount = _thisDecoder.GetChars(EmptyByteBuffer, 0, 0, chars, 0, flush: true); + } + + // convert chars -> bytes [inner] + // It's possible that _innerEncoder might need to perform some end-of-text fixup + // (due to flush: true), even if _thisDecoder didn't need to do so. + + byte[] bytes = EmptyByteBuffer; + int byteCount = _innerEncoder.GetByteCount(chars, 0, charCount, flush: true); + if (byteCount > 0) + { + bytes = new byte[byteCount]; + byteCount = _innerEncoder.GetBytes(chars, 0, charCount, bytes, 0, flush: true); + } + + return new ArraySegment(bytes, 0, byteCount); + } + + public override void Flush() + { + // Don't pass flush: true to our inner decoder + encoder here, since it could cause data + // corruption if a flush occurs mid-stream. Wait until the stream is being closed. + + ThrowIfDisposed(); + _innerStream.Flush(); + } + + public override Task FlushAsync(CancellationToken cancellationToken) + { + // Don't pass flush: true to our inner decoder + encoder here, since it could cause data + // corruption if a flush occurs mid-stream. Wait until the stream is being closed. + + ThrowIfDisposed(); + return _innerStream.FlushAsync(cancellationToken); + } + + public override int Read(byte[] buffer, int offset, int count) + { + ValidateBufferArguments(buffer, offset, count); + + return Read(new Span(buffer, offset, count)); + } + +#if NETCOREAPP || NETSTANDARD2_1 + public override +#else + private +#endif + int Read(Span buffer) + { + EnsurePreReadConditions(); + + // If there's no data in our pending read buffer, we'll need to populate it from + // the inner stream. We read the inner stream's bytes, decode that to chars using + // the 'inner' encoding, then re-encode those chars under the 'this' encoding. + // We've already calculated the worst-case expansions for the intermediate buffers, + // so we use GetChars / GetBytes instead of Convert to simplify the below code + // and to ensure an exception is thrown if the Encoding reported an incorrect + // worst-case expansion. + + if (_readBufferCount == 0) + { + byte[] rentedBytes = ArrayPool.Shared.Rent(DefaultReadByteBufferSize); + char[] rentedChars = ArrayPool.Shared.Rent(_readCharBufferMaxSize); + + try + { + int pendingReadDataPopulatedJustNow; + bool isEofReached; + + do + { + // Beware: Use our constant value instead of 'rentedBytes.Length' for the count + // parameter below. The reason for this is that the array pool could've returned + // a larger-than-expected array, but our worst-case expansion calculations + // performed earlier didn't take that into account. + + int innerBytesReadJustNow = _innerStream.Read(rentedBytes, 0, DefaultReadByteBufferSize); + isEofReached = (innerBytesReadJustNow == 0); + + // Convert bytes [inner] -> chars, then convert chars -> bytes [this]. + // We can't return 0 to our caller until inner stream EOF has been reached. But if the + // inner stream returns a non-empty but incomplete buffer, GetBytes may return 0 anyway + // since it can't yet make forward progress on the input data. If this happens, we'll + // loop so that we don't return 0 to our caller until we truly see inner stream EOF. + + int charsDecodedJustNow = _innerDecoder.GetChars(rentedBytes, 0, innerBytesReadJustNow, rentedChars, 0, flush: isEofReached); + pendingReadDataPopulatedJustNow = _thisEncoder.GetBytes(rentedChars, 0, charsDecodedJustNow, _readBuffer, 0, flush: isEofReached); + } while (!isEofReached && pendingReadDataPopulatedJustNow == 0); + + _readBufferOffset = 0; + _readBufferCount = pendingReadDataPopulatedJustNow; + } + finally + { + ArrayPool.Shared.Return(rentedBytes); + ArrayPool.Shared.Return(rentedChars); + } + } + + // At this point: (a) we've populated our pending read buffer and there's + // useful data to return to our caller; or (b) the pending read buffer is + // empty because the inner stream has reached EOF and all pending read data + // has already been flushed, and we should return 0. + + int bytesToReturn = Math.Min(_readBufferCount, buffer.Length); + _readBuffer.AsSpan(_readBufferOffset, bytesToReturn).CopyTo(buffer); + _readBufferOffset += bytesToReturn; + _readBufferCount -= bytesToReturn; + return bytesToReturn; + } + + public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + ValidateBufferArguments(buffer, offset, count); + + return ReadAsync(new Memory(buffer, offset, count), cancellationToken).AsTask(); + } + +#if NETCOREAPP || NETSTANDARD2_1 + public override +#else + private +#endif + ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken = default) + { + EnsurePreReadConditions(); + + if (cancellationToken.IsCancellationRequested) + { +#if NETCOREAPP || NETSTANDARD + return new ValueTask(Task.FromCanceled(cancellationToken)); +#else + // Lose track of the CancellationToken in this case. + return new ValueTask(TaskHelpers.Canceled()); +#endif + } + + return ReadAsyncCore(buffer, cancellationToken); + async ValueTask ReadAsyncCore(Memory buffer, CancellationToken cancellationToken) + { + // If there's no data in our pending read buffer, we'll need to populate it from + // the inner stream. We read the inner stream's bytes, decode that to chars using + // the 'inner' encoding, then re-encode those chars under the 'this' encoding. + // We've already calculated the worst-case expansions for the intermediate buffers, + // so we use GetChars / GetBytes instead of Convert to simplify the below code + // and to ensure an exception is thrown if the Encoding reported an incorrect + // worst-case expansion. + + if (_readBufferCount == 0) + { + byte[] rentedBytes = ArrayPool.Shared.Rent(DefaultReadByteBufferSize); + char[] rentedChars = ArrayPool.Shared.Rent(_readCharBufferMaxSize); + + try + { + int pendingReadDataPopulatedJustNow; + bool isEofReached; + + do + { + // Beware: Use our constant value instead of 'rentedBytes.Length' when creating + // the Mem struct. The reason for this is that the array pool could've returned + // a larger-than-expected array, but our worst-case expansion calculations + // performed earlier didn't take that into account. + + int innerBytesReadJustNow = await _innerStream.ReadAsync(rentedBytes, 0, DefaultReadByteBufferSize, cancellationToken).ConfigureAwait(false); + isEofReached = (innerBytesReadJustNow == 0); + + // Convert bytes [inner] -> chars, then convert chars -> bytes [this]. + // We can't return 0 to our caller until inner stream EOF has been reached. But if the + // inner stream returns a non-empty but incomplete buffer, GetBytes may return 0 anyway + // since it can't yet make forward progress on the input data. If this happens, we'll + // loop so that we don't return 0 to our caller until we truly see inner stream EOF. + + int charsDecodedJustNow = _innerDecoder.GetChars(rentedBytes, 0, innerBytesReadJustNow, rentedChars, 0, flush: isEofReached); + pendingReadDataPopulatedJustNow = _thisEncoder.GetBytes(rentedChars, 0, charsDecodedJustNow, _readBuffer, 0, flush: isEofReached); + } while (!isEofReached && pendingReadDataPopulatedJustNow == 0); + + _readBufferOffset = 0; + _readBufferCount = pendingReadDataPopulatedJustNow; + } + finally + { + ArrayPool.Shared.Return(rentedBytes); + ArrayPool.Shared.Return(rentedChars); + } + } + + // At this point: (a) we've populated our pending read buffer and there's + // useful data to return to our caller; or (b) the pending read buffer is + // empty because the inner stream has reached EOF and all pending read data + // has already been flushed, and we should return 0. + + int bytesToReturn = Math.Min(_readBufferCount, buffer.Length); + _readBuffer.AsSpan(_readBufferOffset, bytesToReturn).CopyTo(buffer.Span); + _readBufferOffset += bytesToReturn; + _readBufferCount -= bytesToReturn; + return bytesToReturn; + } + } + + public override int ReadByte() + { + return Read(_singleByteBuffer, offset: 0, count: 1) != 0 ? _singleByteBuffer[0] : -1; + } + + public override long Seek(long offset, SeekOrigin origin) + => throw Error.NotSupported(Properties.Resources.NotSupported_UnseekableStream); + + public override void SetLength(long value) + => throw Error.NotSupported(Properties.Resources.NotSupported_UnseekableStream); + +#if NET6_0_OR_GREATER + [StackTraceHidden] +#endif + private void ThrowIfDisposed() + { + if (_innerStream is null) + { + ThrowObjectDisposedException(); + } + } + + [DoesNotReturn] +#if NET6_0_OR_GREATER + [StackTraceHidden] +#endif + private void ThrowObjectDisposedException() + { + throw new ObjectDisposedException(GetType().Name, Properties.Resources.ObjectDisposed_StreamClosed); + } + + public override void Write(byte[] buffer, int offset, int count) + { + ValidateBufferArguments(buffer, offset, count); + +#if NETCOREAPP || NETSTANDARD2_1 + Write(new ReadOnlySpan(buffer, offset, count)); +#else + WriteCore(buffer, offset, count); +#endif + } + +#if NETCOREAPP || NETSTANDARD2_1 + public override void Write(ReadOnlySpan buffer) + { + EnsurePreWriteConditions(); + + if (buffer.IsEmpty) + { + return; + } + + int rentalLength = buffer.Length < MinWriteRentedArraySize ? MinWriteRentedArraySize : + buffer.Length > MaxWriteRentedArraySize ? MaxWriteRentedArraySize : + buffer.Length; + + char[] scratchChars = ArrayPool.Shared.Rent(rentalLength); + byte[] scratchBytes = ArrayPool.Shared.Rent(rentalLength); + + try + { + bool decoderFinished, encoderFinished; + do + { + // convert bytes [this] -> chars + + _thisDecoder.Convert( + bytes: buffer, + chars: scratchChars, + flush: false, + out int bytesConsumed, + out int charsWritten, + out decoderFinished); + + buffer = buffer.Slice(bytesConsumed); + + // convert chars -> bytes [inner] + + Span decodedChars = scratchChars.AsSpan(0, charsWritten); + + do + { + _innerEncoder.Convert( + chars: decodedChars, + bytes: scratchBytes, + flush: false, + out int charsConsumed, + out int bytesWritten, + out encoderFinished); + + decodedChars = decodedChars.Slice(charsConsumed); + + // It's more likely that the inner stream provides an optimized implementation of + // Write(byte[], ...) over Write(ROS), so we'll prefer the byte[]-based overloads. + + _innerStream.Write(scratchBytes, 0, bytesWritten); + } while (!encoderFinished); + } while (!decoderFinished); + } + finally + { + ArrayPool.Shared.Return(scratchChars); + ArrayPool.Shared.Return(scratchBytes); + } + } +#else + private void WriteCore(byte[] buffer, int offset, int count) + { + EnsurePreWriteConditions(); + + if (count == 0) + { + return; + } + + int rentalLength = buffer.Length < MinWriteRentedArraySize ? MinWriteRentedArraySize : + buffer.Length > MaxWriteRentedArraySize ? MaxWriteRentedArraySize : + buffer.Length; + + char[] scratchChars = ArrayPool.Shared.Rent(rentalLength); + byte[] scratchBytes = ArrayPool.Shared.Rent(rentalLength); + + try + { + bool decoderFinished, encoderFinished; + do + { + // convert bytes [this] -> chars + + _thisDecoder.Convert( + bytes: buffer, + byteIndex: offset, + byteCount: count, + chars: scratchChars, + charIndex: 0, + charCount: rentalLength, + flush: false, + out int bytesConsumed, + out int charsWritten, + out decoderFinished); + + offset += bytesConsumed; + count -= bytesConsumed; + + // convert chars -> bytes [inner] + + int scratchOffset = 0; + do + { + _innerEncoder.Convert( + chars: scratchChars, + charIndex: scratchOffset, + charCount: charsWritten, + bytes: scratchBytes, + byteIndex: 0, + byteCount: rentalLength, + flush: false, + out int charsConsumed, + out int bytesWritten, + out encoderFinished); + + scratchOffset += charsConsumed; + charsWritten -= charsConsumed; + + // It's more likely that the inner stream provides an optimized implementation of + // Write(byte[], ...) over Write(ROS), so we'll prefer the byte[]-based overloads. + + _innerStream.Write(scratchBytes, 0, bytesWritten); + } while (!encoderFinished); + } while (!decoderFinished); + } + finally + { + ArrayPool.Shared.Return(scratchChars); + ArrayPool.Shared.Return(scratchBytes); + } + } +#endif + + public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + ValidateBufferArguments(buffer, offset, count); + +#if NETCOREAPP || NETSTANDARD2_1 + return WriteAsync(new ReadOnlyMemory(buffer, offset, count), cancellationToken).AsTask(); +#else + return WriteAsyncCore(buffer, offset, count, cancellationToken).AsTask(); +#endif + } + +#if NETCOREAPP || NETSTANDARD2_1 + public override ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) + { + EnsurePreWriteConditions(); + + if (cancellationToken.IsCancellationRequested) + { + return new ValueTask(Task.FromCanceled(cancellationToken)); + } + + if (buffer.IsEmpty) + { + // ValueTask.CompletedTask + return default; + } + + return WriteAsyncCore(buffer, cancellationToken); + async ValueTask WriteAsyncCore(ReadOnlyMemory remainingOuterEncodedBytes, CancellationToken cancellationToken) + { + int rentalLength = remainingOuterEncodedBytes.Length < MinWriteRentedArraySize ? MinWriteRentedArraySize : + remainingOuterEncodedBytes.Length > MaxWriteRentedArraySize ? MaxWriteRentedArraySize: + remainingOuterEncodedBytes.Length; + + char[] scratchChars = ArrayPool.Shared.Rent(rentalLength); + byte[] scratchBytes = ArrayPool.Shared.Rent(rentalLength); + + try + { + bool decoderFinished, encoderFinished; + do + { + // convert bytes [this] -> chars + + _thisDecoder.Convert( + bytes: buffer, + chars: scratchChars, + flush: false, + out int bytesConsumed, + out int charsWritten, + out decoderFinished); + + buffer = buffer.Slice(bytesConsumed); + + // convert chars -> bytes [inner] + + Span decodedChars = scratchChars.AsSpan(0, charsWritten); + + do + { + _innerEncoder.Convert( + chars: decodedChars, + bytes: scratchBytes, + flush: false, + out int charsConsumed, + out int bytesWritten, + out encoderFinished); + + decodedChars = decodedChars.Slice(charsConsumed); + + await _innerStream.WriteAsync(scratchBytes, 0, bytesWritten, cancellationToken).ConfigureAwait(false); + } while (!encoderFinished); + } while (!decoderFinished); + } + finally + { + ArrayPool.Shared.Return(scratchChars); + ArrayPool.Shared.Return(scratchBytes); + } + } + } +#else + private ValueTask WriteAsyncCore(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + EnsurePreWriteConditions(); + + if (cancellationToken.IsCancellationRequested) + { +#if NETSTANDARD + return new ValueTask(Task.FromCanceled(cancellationToken)); +#else + // Lose track of the CancellationToken in this case. + return new ValueTask(TaskHelpers.Canceled()); +#endif + } + + if (count == 0) + { + // ValueTask.CompletedTask + return default; + } + + return WriteAsyncCore(buffer, cancellationToken); + async ValueTask WriteAsyncCore(ReadOnlyMemory remainingOuterEncodedBytes, CancellationToken cancellationToken) + { + int rentalLength = remainingOuterEncodedBytes.Length < MinWriteRentedArraySize ? MinWriteRentedArraySize : + remainingOuterEncodedBytes.Length > MaxWriteRentedArraySize ? MaxWriteRentedArraySize : + remainingOuterEncodedBytes.Length; + + char[] scratchChars = ArrayPool.Shared.Rent(rentalLength); + byte[] scratchBytes = ArrayPool.Shared.Rent(rentalLength); + + try + { + bool decoderFinished, encoderFinished; + do + { + // convert bytes [this] -> chars + + _thisDecoder.Convert( + bytes: buffer, + byteIndex: offset, + byteCount: count, + chars: scratchChars, + charIndex: 0, + charCount: rentalLength, + flush: false, + out int bytesConsumed, + out int charsWritten, + out decoderFinished); + + offset += bytesConsumed; + count -= bytesConsumed; + + // convert chars -> bytes [inner] + + int scratchOffset = 0; + do + { + _innerEncoder.Convert( + chars: scratchChars, + charIndex: scratchOffset, + charCount: charsWritten, + bytes: scratchBytes, + byteIndex: 0, + byteCount: rentalLength, + flush: false, + out int charsConsumed, + out int bytesWritten, + out encoderFinished); + + scratchOffset += charsConsumed; + charsWritten -= charsConsumed; + + await _innerStream.WriteAsync(scratchBytes, 0, bytesWritten, cancellationToken).ConfigureAwait(false); + } while (!encoderFinished); + } while (!decoderFinished); + } + finally + { + ArrayPool.Shared.Return(scratchChars); + ArrayPool.Shared.Return(scratchBytes); + } + } + } +#endif + + public override void WriteByte(byte value) + { + _singleByteBuffer[0] = value; + Write(_singleByteBuffer, offset: 0, count: 1); + } + + // From https://github.com/dotnet/runtime/blob/88868b7a781f4e5b9037b8721f30440207a7aa42/src/libraries/System.Private.CoreLib/src/System/IO/Stream.cs + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void ValidateBufferArguments(byte[] buffer, int offset, int count) + { + if (buffer is null) + { + throw Error.ArgumentNull(nameof(buffer)); + } + + if (offset < 0) + { + throw Error.ArgumentMustBeGreaterThanOrEqualTo(nameof(offset), offset, minValue: 0); + } + + if ((uint)count > buffer.Length - offset) + { + throw Error.ArgumentOutOfRange(nameof(count), count, Properties.Resources.Argument_InvalidOffLen); + } + } + } +} diff --git a/src/System.Net.Http.Formatting/InvalidByteRangeException.cs b/src/System.Net.Http.Formatting/InvalidByteRangeException.cs index 230564dbd..7e7e677bf 100644 --- a/src/System.Net.Http.Formatting/InvalidByteRangeException.cs +++ b/src/System.Net.Http.Formatting/InvalidByteRangeException.cs @@ -9,7 +9,7 @@ namespace System.Net.Http { /// - /// An exception thrown by in case none of the requested ranges + /// An exception thrown by in case none of the requested ranges /// overlap with the current extend of the selected resource. The current extend of the resource /// is indicated in the ContentRange property. /// @@ -35,11 +35,13 @@ public InvalidByteRangeException(ContentRangeHeaderValue contentRange, string me Initialize(contentRange); } +#if !NETFX_CORE // Exception is not serializable in netstandard1.3. public InvalidByteRangeException(ContentRangeHeaderValue contentRange, SerializationInfo info, StreamingContext context) : base(info, context) { Initialize(contentRange); } +#endif /// /// The current extend of the resource indicated in terms of a ContentRange header field. diff --git a/src/System.Net.Http.Formatting/MultipartFormDataStreamProvider.cs b/src/System.Net.Http.Formatting/MultipartFormDataStreamProvider.cs index f2c997e92..1e012106b 100644 --- a/src/System.Net.Http.Formatting/MultipartFormDataStreamProvider.cs +++ b/src/System.Net.Http.Formatting/MultipartFormDataStreamProvider.cs @@ -11,12 +11,12 @@ namespace System.Net.Http { /// - /// A implementation suited for use with HTML file uploads for writing file - /// content to a . The stream provider looks at the Content-Disposition header + /// A implementation suited for use with HTML file uploads for writing file + /// content to a . The stream provider looks at the Content-Disposition header /// field and determines an output based on the presence of a filename parameter. - /// If a filename parameter is present in the Content-Disposition header field then the body + /// If a filename parameter is present in the Content-Disposition header field then the body /// part is written to a , otherwise it is written to a . - /// This makes it convenient to process MIME Multipart HTML Form data which is a combination of form + /// This makes it convenient to process MIME Multipart HTML Form data which is a combination of form /// data and file content. /// public class MultipartFormDataStreamProvider : MultipartFileStreamProvider @@ -52,7 +52,7 @@ public MultipartFormDataStreamProvider(string rootPath, int bufferSize) /// /// This body part stream provider examines the headers provided by the MIME multipart parser - /// and decides whether it should return a file stream or a memory stream for the body part to be + /// and decides whether it should return a file stream or a memory stream for the body part to be /// written to. /// /// The parent MIME multipart HttpContent instance. diff --git a/src/System.Net.Http.Formatting/Properties/AssemblyInfo.cs b/src/System.Net.Http.Formatting/Properties/AssemblyInfo.cs index 454c8861c..331be44ef 100644 --- a/src/System.Net.Http.Formatting/Properties/AssemblyInfo.cs +++ b/src/System.Net.Http.Formatting/Properties/AssemblyInfo.cs @@ -3,9 +3,7 @@ using System.Reflection; using System.Runtime.CompilerServices; -#if !NETFX_CORE using System.Runtime.InteropServices; -#endif // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information @@ -13,14 +11,12 @@ [assembly: AssemblyTitle("System.Net.Http.Formatting")] [assembly: AssemblyDescription("")] - -#if !NETFX_CORE // GuidAttibute is not supported in portable libraries. [assembly: Guid("7fa1ae84-36e2-46b6-812c-c985a8e65e9a")] -#endif #if NETSTANDARD2_0 [assembly: InternalsVisibleTo("System.Net.Http.Formatting.NetStandard.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")] #elif NETFX_CORE +[assembly: InternalsVisibleTo("Microsoft.TestCommon, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")] [assembly: InternalsVisibleTo("System.Net.Http.Formatting.NetCore.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")] #else [assembly: InternalsVisibleTo("System.Net.Http.Formatting.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")] diff --git a/src/System.Net.Http.Formatting/Properties/Resources.Designer.cs b/src/System.Net.Http.Formatting/Properties/Resources.Designer.cs index ede0dca5e..194d4eff1 100644 --- a/src/System.Net.Http.Formatting/Properties/Resources.Designer.cs +++ b/src/System.Net.Http.Formatting/Properties/Resources.Designer.cs @@ -11,7 +11,8 @@ namespace System.Net.Http.Properties { using System; using System.Reflection; - + + /// /// A strongly-typed resource class, for looking up localized strings, etc. /// @@ -19,19 +20,19 @@ namespace System.Net.Http.Properties { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { - + private static global::System.Resources.ResourceManager resourceMan; - + private static global::System.Globalization.CultureInfo resourceCulture; - + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal Resources() { } - + /// /// Returns the cached ResourceManager instance used by this class. /// @@ -50,7 +51,7 @@ internal Resources() { return resourceMan; } } - + /// /// Overrides the current thread's CurrentUICulture property for all /// resource lookups using this strongly typed resource class. @@ -64,7 +65,16 @@ internal Resources() { resourceCulture = value; } } - + + /// + /// Looks up a localized string similar to Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection.. + /// + internal static string Argument_InvalidOffLen { + get { + return ResourceManager.GetString("Argument_InvalidOffLen", resourceCulture); + } + } + /// /// Looks up a localized string similar to Async Callback threw an exception.. /// @@ -73,7 +83,7 @@ internal static string AsyncResult_CallbackThrewException { return ResourceManager.GetString("AsyncResult_CallbackThrewException", resourceCulture); } } - + /// /// Looks up a localized string similar to The IAsyncResult implementation '{0}' tried to complete a single operation multiple times. This could be caused by an incorrect application IAsyncResult implementation or other extensibility code, such as an IAsyncResult that returns incorrect CompletedSynchronously values or invokes the AsyncCallback multiple times.. /// @@ -82,7 +92,7 @@ internal static string AsyncResult_MultipleCompletes { return ResourceManager.GetString("AsyncResult_MultipleCompletes", resourceCulture); } } - + /// /// Looks up a localized string similar to End cannot be called twice on an AsyncResult.. /// @@ -91,7 +101,7 @@ internal static string AsyncResult_MultipleEnds { return ResourceManager.GetString("AsyncResult_MultipleEnds", resourceCulture); } } - + /// /// Looks up a localized string similar to An incorrect IAsyncResult was provided to an 'End' method. The IAsyncResult object passed to 'End' must be the one returned from the matching 'Begin' or passed to the callback provided to 'Begin'.. /// @@ -100,7 +110,7 @@ internal static string AsyncResult_ResultMismatch { return ResourceManager.GetString("AsyncResult_ResultMismatch", resourceCulture); } } - + /// /// Looks up a localized string similar to Found zero byte ranges. There must be at least one byte range provided.. /// @@ -109,7 +119,7 @@ internal static string ByteRangeStreamContentNoRanges { return ResourceManager.GetString("ByteRangeStreamContentNoRanges", resourceCulture); } } - + /// /// Looks up a localized string similar to The range unit '{0}' is not valid. The range must have a unit of '{1}'.. /// @@ -118,7 +128,7 @@ internal static string ByteRangeStreamContentNotBytesRange { return ResourceManager.GetString("ByteRangeStreamContentNotBytesRange", resourceCulture); } } - + /// /// Looks up a localized string similar to The stream over which '{0}' provides a range view must have a length greater than or equal to 1.. /// @@ -127,7 +137,7 @@ internal static string ByteRangeStreamEmpty { return ResourceManager.GetString("ByteRangeStreamEmpty", resourceCulture); } } - + /// /// Looks up a localized string similar to The 'From' value of the range must be less than or equal to {0}.. /// @@ -136,7 +146,7 @@ internal static string ByteRangeStreamInvalidFrom { return ResourceManager.GetString("ByteRangeStreamInvalidFrom", resourceCulture); } } - + /// /// Looks up a localized string similar to An attempt was made to move the position before the beginning of the stream.. /// @@ -145,7 +155,7 @@ internal static string ByteRangeStreamInvalidOffset { return ResourceManager.GetString("ByteRangeStreamInvalidOffset", resourceCulture); } } - + /// /// Looks up a localized string similar to None of the requested ranges ({0}) overlap with the current extent of the selected resource.. /// @@ -154,7 +164,7 @@ internal static string ByteRangeStreamNoneOverlap { return ResourceManager.GetString("ByteRangeStreamNoneOverlap", resourceCulture); } } - + /// /// Looks up a localized string similar to The requested range ({0}) does not overlap with the current extent of the selected resource.. /// @@ -163,7 +173,7 @@ internal static string ByteRangeStreamNoOverlap { return ResourceManager.GetString("ByteRangeStreamNoOverlap", resourceCulture); } } - + /// /// Looks up a localized string similar to The stream over which '{0}' provides a range view must be seekable.. /// @@ -172,7 +182,7 @@ internal static string ByteRangeStreamNotSeekable { return ResourceManager.GetString("ByteRangeStreamNotSeekable", resourceCulture); } } - + /// /// Looks up a localized string similar to This is a read-only stream.. /// @@ -181,7 +191,7 @@ internal static string ByteRangeStreamReadOnly { return ResourceManager.GetString("ByteRangeStreamReadOnly", resourceCulture); } } - + /// /// Looks up a localized string similar to A null '{0}' is not valid.. /// @@ -190,7 +200,7 @@ internal static string CannotHaveNullInList { return ResourceManager.GetString("CannotHaveNullInList", resourceCulture); } } - + /// /// Looks up a localized string similar to The '{0}' of '{1}' cannot be used as a supported media type because it is a media range.. /// @@ -199,7 +209,7 @@ internal static string CannotUseMediaRangeForSupportedMediaType { return ResourceManager.GetString("CannotUseMediaRangeForSupportedMediaType", resourceCulture); } } - + /// /// Looks up a localized string similar to The '{0}' type cannot accept a null value for the value type '{1}'.. /// @@ -208,7 +218,7 @@ internal static string CannotUseNullValueType { return ResourceManager.GetString("CannotUseNullValueType", resourceCulture); } } - + /// /// Looks up a localized string similar to The specified value is not a valid cookie name.. /// @@ -217,7 +227,7 @@ internal static string CookieInvalidName { return ResourceManager.GetString("CookieInvalidName", resourceCulture); } } - + /// /// Looks up a localized string similar to Cookie cannot be null.. /// @@ -226,7 +236,7 @@ internal static string CookieNull { return ResourceManager.GetString("CookieNull", resourceCulture); } } - + /// /// Looks up a localized string similar to The '{0}' list is invalid because it contains one or more null items.. /// @@ -235,7 +245,7 @@ internal static string DelegatingHandlerArrayContainsNullItem { return ResourceManager.GetString("DelegatingHandlerArrayContainsNullItem", resourceCulture); } } - + /// /// Looks up a localized string similar to The '{0}' list is invalid because the property '{1}' of '{2}' is not null.. /// @@ -244,7 +254,7 @@ internal static string DelegatingHandlerArrayHasNonNullInnerHandler { return ResourceManager.GetString("DelegatingHandlerArrayHasNonNullInnerHandler", resourceCulture); } } - + /// /// Looks up a localized string similar to Error reading HTML form URL-encoded data stream.. /// @@ -253,7 +263,7 @@ internal static string ErrorReadingFormUrlEncodedStream { return ResourceManager.GetString("ErrorReadingFormUrlEncodedStream", resourceCulture); } } - + /// /// Looks up a localized string similar to Mismatched types at node '{0}'.. /// @@ -262,7 +272,7 @@ internal static string FormUrlEncodedMismatchingTypes { return ResourceManager.GetString("FormUrlEncodedMismatchingTypes", resourceCulture); } } - + /// /// Looks up a localized string similar to Error parsing HTML form URL-encoded data, byte {0}.. /// @@ -271,7 +281,7 @@ internal static string FormUrlEncodedParseError { return ResourceManager.GetString("FormUrlEncodedParseError", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid HTTP status code: '{0}'. The status code must be between {1} and {2}.. /// @@ -280,7 +290,7 @@ internal static string HttpInvalidStatusCode { return ResourceManager.GetString("HttpInvalidStatusCode", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid HTTP version: '{0}'. The version must start with the characters '{1}'.. /// @@ -289,7 +299,7 @@ internal static string HttpInvalidVersion { return ResourceManager.GetString("HttpInvalidVersion", resourceCulture); } } - + /// /// Looks up a localized string similar to The '{0}' of the '{1}' has already been read.. /// @@ -298,7 +308,7 @@ internal static string HttpMessageContentAlreadyRead { return ResourceManager.GetString("HttpMessageContentAlreadyRead", resourceCulture); } } - + /// /// Looks up a localized string similar to The '{0}' must be seekable in order to create an '{1}' instance containing an entity body. . /// @@ -307,7 +317,7 @@ internal static string HttpMessageContentStreamMustBeSeekable { return ResourceManager.GetString("HttpMessageContentStreamMustBeSeekable", resourceCulture); } } - + /// /// Looks up a localized string similar to Error reading HTTP message.. /// @@ -316,7 +326,7 @@ internal static string HttpMessageErrorReading { return ResourceManager.GetString("HttpMessageErrorReading", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid '{0}' instance provided. It does not have a content type header with a value of '{1}'.. /// @@ -325,7 +335,7 @@ internal static string HttpMessageInvalidMediaType { return ResourceManager.GetString("HttpMessageInvalidMediaType", resourceCulture); } } - + /// /// Looks up a localized string similar to HTTP Request URI cannot be an empty string.. /// @@ -334,7 +344,7 @@ internal static string HttpMessageParserEmptyUri { return ResourceManager.GetString("HttpMessageParserEmptyUri", resourceCulture); } } - + /// /// Looks up a localized string similar to Error parsing HTTP message header byte {0} of message {1}.. /// @@ -343,7 +353,7 @@ internal static string HttpMessageParserError { return ResourceManager.GetString("HttpMessageParserError", resourceCulture); } } - + /// /// Looks up a localized string similar to An invalid number of '{0}' header fields were present in the HTTP Request. It must contain exactly one '{0}' header field but found {1}.. /// @@ -352,7 +362,7 @@ internal static string HttpMessageParserInvalidHostCount { return ResourceManager.GetString("HttpMessageParserInvalidHostCount", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid URI scheme: '{0}'. The URI scheme must be a valid '{1}' scheme.. /// @@ -361,7 +371,7 @@ internal static string HttpMessageParserInvalidUriScheme { return ResourceManager.GetString("HttpMessageParserInvalidUriScheme", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid array at node '{0}'.. /// @@ -370,7 +380,7 @@ internal static string InvalidArrayInsert { return ResourceManager.GetString("InvalidArrayInsert", resourceCulture); } } - + /// /// Looks up a localized string similar to Traditional style array without '[]' is not supported with nested object at location {0}.. /// @@ -379,7 +389,7 @@ internal static string JQuery13CompatModeNotSupportNestedJson { return ResourceManager.GetString("JQuery13CompatModeNotSupportNestedJson", resourceCulture); } } - + /// /// Looks up a localized string similar to The '{0}' method returned null. It must return a JSON serializer instance.. /// @@ -388,7 +398,7 @@ internal static string JsonSerializerFactoryReturnedNull { return ResourceManager.GetString("JsonSerializerFactoryReturnedNull", resourceCulture); } } - + /// /// Looks up a localized string similar to The '{0}' method threw an exception when attempting to create a JSON serializer.. /// @@ -397,7 +407,7 @@ internal static string JsonSerializerFactoryThrew { return ResourceManager.GetString("JsonSerializerFactoryThrew", resourceCulture); } } - + /// /// Looks up a localized string similar to The maximum read depth ({0}) has been exceeded because the form url-encoded data being read has more levels of nesting than is allowed.. /// @@ -406,7 +416,7 @@ internal static string MaxDepthExceeded { return ResourceManager.GetString("MaxDepthExceeded", resourceCulture); } } - + /// /// Looks up a localized string similar to The number of keys in a NameValueCollection has exceeded the limit of '{0}'. You can adjust it by modifying the MaxHttpCollectionKeys property on the '{1}' class.. /// @@ -415,7 +425,7 @@ internal static string MaxHttpCollectionKeyLimitReached { return ResourceManager.GetString("MaxHttpCollectionKeyLimitReached", resourceCulture); } } - + /// /// Looks up a localized string similar to Error parsing BSON data; unable to read content as a {0}.. /// @@ -424,7 +434,7 @@ internal static string MediaTypeFormatter_BsonParseError_MissingData { return ResourceManager.GetString("MediaTypeFormatter_BsonParseError_MissingData", resourceCulture); } } - + /// /// Looks up a localized string similar to Error parsing BSON data; unexpected dictionary content: {0} entries, first key '{1}'.. /// @@ -433,7 +443,7 @@ internal static string MediaTypeFormatter_BsonParseError_UnexpectedData { return ResourceManager.GetString("MediaTypeFormatter_BsonParseError_UnexpectedData", resourceCulture); } } - + /// /// Looks up a localized string similar to The '{0}' method returned null. It must return a JSON reader instance.. /// @@ -442,7 +452,7 @@ internal static string MediaTypeFormatter_JsonReaderFactoryReturnedNull { return ResourceManager.GetString("MediaTypeFormatter_JsonReaderFactoryReturnedNull", resourceCulture); } } - + /// /// Looks up a localized string similar to The '{0}' method returned null. It must return a JSON writer instance.. /// @@ -451,7 +461,7 @@ internal static string MediaTypeFormatter_JsonWriterFactoryReturnedNull { return ResourceManager.GetString("MediaTypeFormatter_JsonWriterFactoryReturnedNull", resourceCulture); } } - + /// /// Looks up a localized string similar to The media type formatter of type '{0}' does not support reading because it does not implement the ReadFromStreamAsync method.. /// @@ -460,7 +470,7 @@ internal static string MediaTypeFormatterCannotRead { return ResourceManager.GetString("MediaTypeFormatterCannotRead", resourceCulture); } } - + /// /// Looks up a localized string similar to The media type formatter of type '{0}' does not support reading because it does not implement the ReadFromStream method.. /// @@ -469,7 +479,7 @@ internal static string MediaTypeFormatterCannotReadSync { return ResourceManager.GetString("MediaTypeFormatterCannotReadSync", resourceCulture); } } - + /// /// Looks up a localized string similar to The media type formatter of type '{0}' does not support writing because it does not implement the WriteToStreamAsync method.. /// @@ -478,7 +488,7 @@ internal static string MediaTypeFormatterCannotWrite { return ResourceManager.GetString("MediaTypeFormatterCannotWrite", resourceCulture); } } - + /// /// Looks up a localized string similar to The media type formatter of type '{0}' does not support writing because it does not implement the WriteToStream method.. /// @@ -487,7 +497,7 @@ internal static string MediaTypeFormatterCannotWriteSync { return ResourceManager.GetString("MediaTypeFormatterCannotWriteSync", resourceCulture); } } - + /// /// Looks up a localized string similar to No encoding found for media type formatter '{0}'. There must be at least one supported encoding registered in order for the media type formatter to read or write content.. /// @@ -496,7 +506,7 @@ internal static string MediaTypeFormatterNoEncoding { return ResourceManager.GetString("MediaTypeFormatterNoEncoding", resourceCulture); } } - + /// /// Looks up a localized string similar to MIME multipart boundary cannot end with an empty space.. /// @@ -505,7 +515,7 @@ internal static string MimeMultipartParserBadBoundary { return ResourceManager.GetString("MimeMultipartParserBadBoundary", resourceCulture); } } - + /// /// Looks up a localized string similar to Did not find required '{0}' header field in MIME multipart body part.. /// @@ -514,7 +524,7 @@ internal static string MultipartFormDataStreamProviderNoContentDisposition { return ResourceManager.GetString("MultipartFormDataStreamProviderNoContentDisposition", resourceCulture); } } - + /// /// Looks up a localized string similar to Could not determine a valid local file name for the multipart body part.. /// @@ -523,7 +533,7 @@ internal static string MultipartStreamProviderInvalidLocalFileName { return ResourceManager.GetString("MultipartStreamProviderInvalidLocalFileName", resourceCulture); } } - + /// /// Looks up a localized string similar to Nested bracket is not valid for '{0}' data at position {1}.. /// @@ -532,7 +542,7 @@ internal static string NestedBracketNotValid { return ResourceManager.GetString("NestedBracketNotValid", resourceCulture); } } - + /// /// Looks up a localized string similar to A non-null request URI must be provided to determine if a '{0}' matches a given request or response message.. /// @@ -541,7 +551,7 @@ internal static string NonNullUriRequiredForMediaTypeMapping { return ResourceManager.GetString("NonNullUriRequiredForMediaTypeMapping", resourceCulture); } } - + /// /// Looks up a localized string similar to No MediaTypeFormatter is available to read an object of type '{0}' from content with media type '{1}'.. /// @@ -550,7 +560,34 @@ internal static string NoReadSerializerAvailable { return ResourceManager.GetString("NoReadSerializerAvailable", resourceCulture); } } - + + /// + /// Looks up a localized string similar to Stream does not support reading.. + /// + internal static string NotSupported_UnreadableStream { + get { + return ResourceManager.GetString("NotSupported_UnreadableStream", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Stream does not support seeking.. + /// + internal static string NotSupported_UnseekableStream { + get { + return ResourceManager.GetString("NotSupported_UnseekableStream", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Stream does not support writing.. + /// + internal static string NotSupported_UnwritableStream { + get { + return ResourceManager.GetString("NotSupported_UnwritableStream", resourceCulture); + } + } + /// /// Looks up a localized string similar to An object of type '{0}' cannot be used with a type parameter of '{1}'.. /// @@ -559,7 +596,7 @@ internal static string ObjectAndTypeDisagree { return ResourceManager.GetString("ObjectAndTypeDisagree", resourceCulture); } } - + /// /// Looks up a localized string similar to The configured formatter '{0}' cannot write an object of type '{1}'.. /// @@ -568,7 +605,16 @@ internal static string ObjectContent_FormatterCannotWriteType { return ResourceManager.GetString("ObjectContent_FormatterCannotWriteType", resourceCulture); } } - + + /// + /// Looks up a localized string similar to Cannot access a closed stream.. + /// + internal static string ObjectDisposed_StreamClosed { + get { + return ResourceManager.GetString("ObjectDisposed_StreamClosed", resourceCulture); + } + } + /// /// Looks up a localized string similar to Query string name cannot be null.. /// @@ -577,7 +623,7 @@ internal static string QueryStringNameShouldNotNull { return ResourceManager.GetString("QueryStringNameShouldNotNull", resourceCulture); } } - + /// /// Looks up a localized string similar to Unexpected end of HTTP message stream. HTTP message is not complete.. /// @@ -586,7 +632,7 @@ internal static string ReadAsHttpMessageUnexpectedTermination { return ResourceManager.GetString("ReadAsHttpMessageUnexpectedTermination", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid '{0}' instance provided. It does not have a '{1}' content-type header with a '{2}' parameter.. /// @@ -595,7 +641,7 @@ internal static string ReadAsMimeMultipartArgumentNoBoundary { return ResourceManager.GetString("ReadAsMimeMultipartArgumentNoBoundary", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid '{0}' instance provided. It does not have a content-type header value. '{0}' instances must have a content-type header starting with '{1}'.. /// @@ -604,7 +650,7 @@ internal static string ReadAsMimeMultipartArgumentNoContentType { return ResourceManager.GetString("ReadAsMimeMultipartArgumentNoContentType", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid '{0}' instance provided. It does not have a content type header starting with '{1}'.. /// @@ -613,7 +659,7 @@ internal static string ReadAsMimeMultipartArgumentNoMultipart { return ResourceManager.GetString("ReadAsMimeMultipartArgumentNoMultipart", resourceCulture); } } - + /// /// Looks up a localized string similar to Error reading MIME multipart body part.. /// @@ -622,7 +668,7 @@ internal static string ReadAsMimeMultipartErrorReading { return ResourceManager.GetString("ReadAsMimeMultipartErrorReading", resourceCulture); } } - + /// /// Looks up a localized string similar to Error writing MIME multipart body part to output stream.. /// @@ -631,7 +677,7 @@ internal static string ReadAsMimeMultipartErrorWriting { return ResourceManager.GetString("ReadAsMimeMultipartErrorWriting", resourceCulture); } } - + /// /// Looks up a localized string similar to Error parsing MIME multipart body part header byte {0} of data segment {1}.. /// @@ -640,7 +686,7 @@ internal static string ReadAsMimeMultipartHeaderParseError { return ResourceManager.GetString("ReadAsMimeMultipartHeaderParseError", resourceCulture); } } - + /// /// Looks up a localized string similar to Error parsing MIME multipart message byte {0} of data segment {1}.. /// @@ -649,7 +695,7 @@ internal static string ReadAsMimeMultipartParseError { return ResourceManager.GetString("ReadAsMimeMultipartParseError", resourceCulture); } } - + /// /// Looks up a localized string similar to The stream provider of type '{0}' threw an exception.. /// @@ -658,7 +704,7 @@ internal static string ReadAsMimeMultipartStreamProviderException { return ResourceManager.GetString("ReadAsMimeMultipartStreamProviderException", resourceCulture); } } - + /// /// Looks up a localized string similar to The stream provider of type '{0}' returned null. It must return a writable '{1}' instance.. /// @@ -667,7 +713,7 @@ internal static string ReadAsMimeMultipartStreamProviderNull { return ResourceManager.GetString("ReadAsMimeMultipartStreamProviderNull", resourceCulture); } } - + /// /// Looks up a localized string similar to The stream provider of type '{0}' returned a read-only stream. It must return a writable '{1}' instance.. /// @@ -676,7 +722,7 @@ internal static string ReadAsMimeMultipartStreamProviderReadOnly { return ResourceManager.GetString("ReadAsMimeMultipartStreamProviderReadOnly", resourceCulture); } } - + /// /// Looks up a localized string similar to Unexpected end of MIME multipart stream. MIME multipart message is not complete.. /// @@ -685,7 +731,7 @@ internal static string ReadAsMimeMultipartUnexpectedTermination { return ResourceManager.GetString("ReadAsMimeMultipartUnexpectedTermination", resourceCulture); } } - + /// /// Looks up a localized string similar to The '{0}' method in '{1}' returned null. It must return a RemoteStreamResult instance containing a writable stream and a valid URL.. /// @@ -694,7 +740,7 @@ internal static string RemoteStreamInfoCannotBeNull { return ResourceManager.GetString("RemoteStreamInfoCannotBeNull", resourceCulture); } } - + /// /// Looks up a localized string similar to The '{0}' serializer cannot serialize the type '{1}'.. /// @@ -703,7 +749,7 @@ internal static string SerializerCannotSerializeType { return ResourceManager.GetString("SerializerCannotSerializeType", resourceCulture); } } - + /// /// Looks up a localized string similar to There is an unmatched opened bracket for the '{0}' at position {1}.. /// @@ -712,7 +758,7 @@ internal static string UnMatchedBracketNotValid { return ResourceManager.GetString("UnMatchedBracketNotValid", resourceCulture); } } - + /// /// Looks up a localized string similar to Indentation is not supported by '{0}'.. /// @@ -721,7 +767,7 @@ internal static string UnsupportedIndent { return ResourceManager.GetString("UnsupportedIndent", resourceCulture); } } - + /// /// Looks up a localized string similar to The object of type '{0}' returned by {1} must be an instance of either XmlObjectSerializer or XmlSerializer.. /// @@ -730,7 +776,7 @@ internal static string XmlMediaTypeFormatter_InvalidSerializerType { return ResourceManager.GetString("XmlMediaTypeFormatter_InvalidSerializerType", resourceCulture); } } - + /// /// Looks up a localized string similar to The object returned by {0} must not be a null value.. /// diff --git a/src/System.Net.Http.Formatting/Properties/Resources.resx b/src/System.Net.Http.Formatting/Properties/Resources.resx index d20156c5a..1b8df2cd2 100644 --- a/src/System.Net.Http.Formatting/Properties/Resources.resx +++ b/src/System.Net.Http.Formatting/Properties/Resources.resx @@ -1,17 +1,17 @@  - @@ -342,4 +342,19 @@ An attempt was made to move the position before the beginning of the stream. + + Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection. + + + Stream does not support reading. + + + Stream does not support seeking. + + + Stream does not support writing. + + + Cannot access a closed stream. + \ No newline at end of file diff --git a/src/System.Net.Http.Formatting/Settings.StyleCop b/src/System.Net.Http.Formatting/Settings.StyleCop deleted file mode 100644 index 5b387864d..000000000 --- a/src/System.Net.Http.Formatting/Settings.StyleCop +++ /dev/null @@ -1,10 +0,0 @@ - - - UriQueryUtility.cs - - - False - - - - \ No newline at end of file diff --git a/src/System.Net.Http.Formatting/System.Net.Http.Formatting.csproj b/src/System.Net.Http.Formatting/System.Net.Http.Formatting.csproj index 793e175a8..d52549eec 100644 --- a/src/System.Net.Http.Formatting/System.Net.Http.Formatting.csproj +++ b/src/System.Net.Http.Formatting/System.Net.Http.Formatting.csproj @@ -14,173 +14,84 @@ Client 1591 + - - ..\..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll + + + ..\..\packages\System.Buffers.4.5.1\lib\netstandard2.0\System.Buffers.dll False False - - ..\..\packages\Newtonsoft.Json.Bson.1.0.2\lib\net45\Newtonsoft.Json.Bson.dll + + + + ..\..\packages\System.Memory.4.5.5\lib\netstandard2.0\System.Memory.dll False False - - - + + ..\..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll + False + False + - - - - Properties\CommonAssemblyInfo.cs - - - Common\CollectionExtensions.cs - - - Common\Error.cs - - - Common\ListWrapperCollection.cs - - - Common\TaskHelpers.cs - - - Common\TaskHelpersExtensions.cs - - - Common\UriQueryUtility.cs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - True - True - Resources.resx - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + ..\..\packages\NETStandard.Library.2.0.3\lib\netstandard2.0\netstandard.dll + False + False + + + ..\..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll + False + False + + + ..\..\packages\Newtonsoft.Json.Bson.1.0.2\lib\net45\Newtonsoft.Json.Bson.dll + False + False + + + + + + + + + + + - Properties\CommonWebApiResources.Designer.cs True - True CommonWebApiResources.resx + True + Properties\CommonWebApiResources.Designer.cs - - - Properties\CommonWebApiResources.resx ResXFileCodeGenerator CommonWebApiResources.Designer.cs + Properties\CommonWebApiResources.resx - - + + + True + Resources.resx + True + ResXFileCodeGenerator Resources.Designer.cs Designer - - - - CodeAnalysisDictionary.xml - - - + + + + - \ No newline at end of file + diff --git a/src/System.Net.Http.Formatting/UriExtensions.cs b/src/System.Net.Http.Formatting/UriExtensions.cs index ab83ec938..cf531431a 100644 --- a/src/System.Net.Http.Formatting/UriExtensions.cs +++ b/src/System.Net.Http.Formatting/UriExtensions.cs @@ -18,21 +18,12 @@ namespace System.Net.Http [EditorBrowsable(EditorBrowsableState.Never)] public static class UriExtensions { -#if NETFX_CORE - /// - /// Parses the query portion of the specified . - /// - /// The instance from which to read. - /// A containing the parsed result. - public static HttpValueCollection ParseQueryString(this Uri address) -#else /// /// Parses the query portion of the specified . /// /// The instance from which to read. /// A containing the parsed result. public static NameValueCollection ParseQueryString(this Uri address) -#endif { if (address == null) { diff --git a/src/System.Net.Http.Formatting/packages.config b/src/System.Net.Http.Formatting/packages.config index 509dcb7d1..1ff2795f6 100644 --- a/src/System.Net.Http.Formatting/packages.config +++ b/src/System.Net.Http.Formatting/packages.config @@ -2,4 +2,8 @@ + + + + \ No newline at end of file diff --git a/src/System.Web.Http/Settings.StyleCop b/src/System.Web.Http/Settings.StyleCop deleted file mode 100644 index ddf8ec764..000000000 --- a/src/System.Web.Http/Settings.StyleCop +++ /dev/null @@ -1,11 +0,0 @@ - - - DynamicQueryable.cs - UriQueryUtility.cs - - - False - - - - \ No newline at end of file diff --git a/src/System.Web.Http/System.Web.Http.csproj b/src/System.Web.Http/System.Web.Http.csproj index eaa991282..27041a371 100644 --- a/src/System.Web.Http/System.Web.Http.csproj +++ b/src/System.Web.Http/System.Web.Http.csproj @@ -102,9 +102,6 @@ Common\TypeExtensions.cs - - Common\UriQueryUtility.cs - diff --git a/test/Common/UriQueryUtilityTest.cs b/test/Common/UriQueryUtilityTest.cs index 4b325abbd..ac0307cae 100644 --- a/test/Common/UriQueryUtilityTest.cs +++ b/test/Common/UriQueryUtilityTest.cs @@ -10,7 +10,7 @@ namespace System.Net.Http { - public class UriQueryUtilityTest + public class WebUtilityTest { public static TheoryDataSet UriQueryData { @@ -23,19 +23,20 @@ public static TheoryDataSet UriQueryData [Fact] public void TypeIsCorrect() { - Assert.Type.HasProperties(typeof(UriQueryUtility), TypeAssert.TypeProperties.IsClass | TypeAssert.TypeProperties.IsStatic); + Assert.Type.HasProperties(typeof(WebUtility), + TypeAssert.TypeProperties.IsStatic | TypeAssert.TypeProperties.IsPublicVisibleClass); } [Fact] public void UrlEncode_ReturnsNull() { - Assert.Null(UriQueryUtility.UrlEncode(null)); + Assert.Null(WebUtility.UrlEncode(null)); } [Fact] public void UrlDecode_ReturnsNull() { - Assert.Null(UriQueryUtility.UrlDecode(null)); + Assert.Null(WebUtility.UrlDecode(null)); } [Fact] diff --git a/test/Microsoft.TestCommon/ExceptionAssertions.cs b/test/Microsoft.TestCommon/ExceptionAssertions.cs index 11b36e9e6..5cca7e7c8 100644 --- a/test/Microsoft.TestCommon/ExceptionAssertions.cs +++ b/test/Microsoft.TestCommon/ExceptionAssertions.cs @@ -6,6 +6,9 @@ using System.Reflection; using System.Threading.Tasks; using System.Web; +#if NETFX_CORE +using System.Web.Http; +#endif namespace Microsoft.TestCommon { @@ -494,12 +497,17 @@ public static HttpException ThrowsHttpException(Action testCode, string exceptio /// Pass true to allow exceptions which derive from TException; pass false, otherwise /// The exception that was thrown, when successful /// Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown - public static InvalidEnumArgumentException ThrowsInvalidEnumArgument(Action testCode, string paramName, int invalidValue, Type enumType, bool allowDerivedExceptions = false) + public static ArgumentException ThrowsInvalidEnumArgument(Action testCode, string paramName, int invalidValue, Type enumType, bool allowDerivedExceptions = false) { string message = String.Format(CultureReplacer.DefaultCulture, "The value of argument '{0}' ({1}) is invalid for Enum type '{2}'.{3}Parameter name: {0}", paramName, invalidValue, enumType.Name, Environment.NewLine); + +#if NETFX_CORE // InvalidEnumArgumentException not available in netstandard1.3. + return Throws(testCode, message, allowDerivedExceptions); +#else return Throws(testCode, message, allowDerivedExceptions); +#endif } /// diff --git a/test/Microsoft.TestCommon/Microsoft.TestCommon.csproj b/test/Microsoft.TestCommon/Microsoft.TestCommon.csproj index dae43e747..4def411d9 100644 --- a/test/Microsoft.TestCommon/Microsoft.TestCommon.csproj +++ b/test/Microsoft.TestCommon/Microsoft.TestCommon.csproj @@ -1,23 +1,34 @@  - netcoreapp2.1;net452 - ..\..\bin\$(Configuration)\Test\ + net452;net462;netcoreapp2.1 $(Configurations);CodeAnalysis + $(DefineConstants);NETFX_CORE false + ..\..\bin\$(Configuration)\Test\ + $(OutputPath)NetCore\ + - + + + - + Condition=" '$(TargetFrameworkIdentifier)' != '.NETFramework' " /> + + + diff --git a/test/System.Net.Http.Formatting.NetCore.Test/System.Net.Http.Formatting.NetCore.Test.csproj b/test/System.Net.Http.Formatting.NetCore.Test/System.Net.Http.Formatting.NetCore.Test.csproj index d60e9a90c..863474dbc 100644 --- a/test/System.Net.Http.Formatting.NetCore.Test/System.Net.Http.Formatting.NetCore.Test.csproj +++ b/test/System.Net.Http.Formatting.NetCore.Test/System.Net.Http.Formatting.NetCore.Test.csproj @@ -1,105 +1,38 @@  - net462 + netcoreapp2.1;net462 System.Net.Http - System.Net.Http.Formatting.NetCore.Test ..\..\bin\$(Configuration)\Test\NetCore\ $(Configurations);CodeAnalysis false $(DefineConstants);NETFX_CORE true + true + + + all runtime; build; native; contentfiles; analyzers - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + %(RecursiveDir)\%(Filename).cs + + - - - + + - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - diff --git a/test/System.Net.Http.Formatting.NetStandard.Test/System.Net.Http.Formatting.NetStandard.Test.csproj b/test/System.Net.Http.Formatting.NetStandard.Test/System.Net.Http.Formatting.NetStandard.Test.csproj index 64d06cf7e..6d6405cb6 100644 --- a/test/System.Net.Http.Formatting.NetStandard.Test/System.Net.Http.Formatting.NetStandard.Test.csproj +++ b/test/System.Net.Http.Formatting.NetStandard.Test/System.Net.Http.Formatting.NetStandard.Test.csproj @@ -3,32 +3,35 @@ netcoreapp2.1;net462 System.Net.Http - System.Net.Http.Formatting.NetStandard.Test ..\..\bin\$(Configuration)\Test\NetStandard\ $(Configurations);CodeAnalysis false + $(DefineConstants);Testing_NetStandard2_0 true + true + + + + all runtime; build; native; contentfiles; analyzers - - - + + %(RecursiveDir)\%(Filename).cs - - + - - + diff --git a/test/System.Net.Http.Formatting.Test/DataSets/HttpTestData.cs b/test/System.Net.Http.Formatting.Test/DataSets/HttpTestData.cs index 84178a3a6..5e7672b2e 100644 --- a/test/System.Net.Http.Formatting.Test/DataSets/HttpTestData.cs +++ b/test/System.Net.Http.Formatting.Test/DataSets/HttpTestData.cs @@ -356,7 +356,6 @@ public static TestData StandardHttpContents //// TODO: make this list compose from other data? // Collection of legal instances of all standard MediaTypeMapping types -#if !NETFX_CORE // not present in portable library version public static TestData StandardMediaTypeMappings { get @@ -375,7 +374,6 @@ public static TestData QueryStringMappings }); } } -#endif public static TestData LegalUriPathExtensions { diff --git a/test/System.Net.Http.Formatting.Test/Formatting/BsonMediaTypeFormatterTests.cs b/test/System.Net.Http.Formatting.Test/Formatting/BsonMediaTypeFormatterTests.cs index e28096df8..3082b265d 100644 --- a/test/System.Net.Http.Formatting.Test/Formatting/BsonMediaTypeFormatterTests.cs +++ b/test/System.Net.Http.Formatting.Test/Formatting/BsonMediaTypeFormatterTests.cs @@ -149,9 +149,7 @@ void CopyConstructor() // Arrange TestBsonMediaTypeFormatter formatter = new TestBsonMediaTypeFormatter() { -#if !NETFX_CORE // MaxDepth is not supported in portable library MaxDepth = 42, -#endif }; // Replace serializable settings and switch one property's value @@ -163,16 +161,13 @@ void CopyConstructor() TestBsonMediaTypeFormatter derivedFormatter = new TestBsonMediaTypeFormatter(formatter); // Assert -#if !NETFX_CORE // MaxDepth is not supported in portable library Assert.Equal(formatter.MaxDepth, derivedFormatter.MaxDepth); -#endif Assert.NotSame(oldSettings, formatter.SerializerSettings); Assert.NotEqual(oldSettings.CheckAdditionalContent, formatter.SerializerSettings.CheckAdditionalContent); Assert.Same(formatter.SerializerSettings, derivedFormatter.SerializerSettings); Assert.Same(formatter.SerializerSettings.ContractResolver, derivedFormatter.SerializerSettings.ContractResolver); } -#if !NETFX_CORE // MaxDepth is not supported in portable library [Fact] public void MaxDepth_RoundTrips() { @@ -187,7 +182,6 @@ public void MaxDepth_RoundTrips() illegalUpperValue: null, roundTripTestValue: 256); } -#endif [Theory] [TestDataSet(typeof(CommonUnitTestDataSets), "RepresentativeValueAndRefTypeTestDataCollection")] @@ -262,14 +256,8 @@ public async Task FormatterThrowsOnWriteWithInvalidContent() BsonMediaTypeFormatter formatter = new BsonMediaTypeFormatter(); HttpContent content = new StringContent(String.Empty); MemoryStream stream = new MemoryStream(); -#if NETFX_CORE // Separate Bson package (not yet used in NETCore project) calculates the path in exceptions differently - string expectedPath = string.Empty; -#else - string expectedPath = "Value"; -#endif - string expectedMessage = string.Format( - "Value is too large to fit in a signed 32 bit integer. BSON does not support unsigned values. Path '{0}'.", - expectedPath); + string expectedMessage = + "Value is too large to fit in a signed 32 bit integer. BSON does not support unsigned values. Path 'Value'."; // Act & Assert // Note error message is not quite correct: BSON supports byte, ushort, and smaller uint / ulong values. diff --git a/test/System.Net.Http.Formatting.Test/Formatting/DataContractJsonMediaTypeFormatterTests.cs b/test/System.Net.Http.Formatting.Test/Formatting/DataContractJsonMediaTypeFormatterTests.cs index e576a6924..55ad646b4 100644 --- a/test/System.Net.Http.Formatting.Test/Formatting/DataContractJsonMediaTypeFormatterTests.cs +++ b/test/System.Net.Http.Formatting.Test/Formatting/DataContractJsonMediaTypeFormatterTests.cs @@ -87,6 +87,7 @@ public void CanReadType_ReturnsExpectedValues(Type variationType, object testDat Assert.False(isSerializable != canSupport && isSerializable, String.Format("2nd CanReadType returned wrong value for '{0}'.", variationType)); } +#if !NETFX_CORE // XsdDataContractExporterMethods unconditionally return true without XsdDataContractExporter to use. [Fact] public void CanReadType_ReturnsFalse_ForInvalidDataContracts() { @@ -100,6 +101,7 @@ public void CanWriteType_ReturnsFalse_ForInvalidDataContracts() JsonMediaTypeFormatter formatter = new DataContractJsonMediaTypeFormatter(); Assert.False(formatter.CanWriteType(typeof(InvalidDataContract))); } +#endif public class InvalidDataContract { @@ -216,12 +218,6 @@ public void UseDataContractJsonSerializer_True_Indent_Throws() public override Task ReadFromStreamAsync_UsesCorrectCharacterEncoding(string content, string encoding, bool isDefaultEncoding) { - if (!isDefaultEncoding) - { - // XmlDictionaryReader/Writer only supports utf-8 and 16 - return TaskHelpers.Completed(); - } - // Arrange DataContractJsonMediaTypeFormatter formatter = new DataContractJsonMediaTypeFormatter(); string formattedContent = "\"" + content + "\""; @@ -234,14 +230,6 @@ public override Task ReadFromStreamAsync_UsesCorrectCharacterEncoding(string con public override Task WriteToStreamAsync_UsesCorrectCharacterEncoding(string content, string encoding, bool isDefaultEncoding) { - // DataContractJsonSerializer does not honor the value of byteOrderMark in the UnicodeEncoding ctor. - // It doesn't include the BOM when byteOrderMark is set to true. - if (!isDefaultEncoding || encoding != "utf-8") - { - // XmlDictionaryReader/Writer only supports utf-8 and 16 - return TaskHelpers.Completed(); - } - // Arrange DataContractJsonMediaTypeFormatter formatter = new DataContractJsonMediaTypeFormatter(); string formattedContent = "\"" + content + "\""; diff --git a/test/System.Net.Http.Formatting.Test/Formatting/FormUrlEncodedFromContentTests.cs b/test/System.Net.Http.Formatting.Test/Formatting/FormUrlEncodedFromContentTests.cs index dec45eab4..fcc01232d 100644 --- a/test/System.Net.Http.Formatting.Test/Formatting/FormUrlEncodedFromContentTests.cs +++ b/test/System.Net.Http.Formatting.Test/Formatting/FormUrlEncodedFromContentTests.cs @@ -340,11 +340,11 @@ private static void BuildParams(string prefix, JToken jsonValue, List re { dateStr = dateStr.Substring(1, dateStr.Length - 2); } - results.Add(prefix + "=" + UriQueryUtility.UrlEncode(dateStr)); + results.Add(prefix + "=" + WebUtility.UrlEncode(dateStr)); } else { - results.Add(prefix + "=" + UriQueryUtility.UrlEncode(jsonPrimitive.Value.ToString())); + results.Add(prefix + "=" + WebUtility.UrlEncode(jsonPrimitive.Value.ToString())); } } } diff --git a/test/System.Net.Http.Formatting.Test/Formatting/FormUrlEncodedFromUriQueryTests.cs b/test/System.Net.Http.Formatting.Test/Formatting/FormUrlEncodedFromUriQueryTests.cs index 4dee5366e..b56717039 100644 --- a/test/System.Net.Http.Formatting.Test/Formatting/FormUrlEncodedFromUriQueryTests.cs +++ b/test/System.Net.Http.Formatting.Test/Formatting/FormUrlEncodedFromUriQueryTests.cs @@ -279,11 +279,11 @@ private static void BuildParams(string prefix, JToken jsonValue, List re { dateStr = dateStr.Substring(1, dateStr.Length - 2); } - results.Add(prefix + "=" + UriQueryUtility.UrlEncode(dateStr)); + results.Add(prefix + "=" + WebUtility.UrlEncode(dateStr)); } else { - results.Add(prefix + "=" + UriQueryUtility.UrlEncode(jsonPrimitive.Value.ToString())); + results.Add(prefix + "=" + WebUtility.UrlEncode(jsonPrimitive.Value.ToString())); } } } diff --git a/test/System.Net.Http.Formatting.Test/Formatting/JsonMediaTypeFormatterTests.cs b/test/System.Net.Http.Formatting.Test/Formatting/JsonMediaTypeFormatterTests.cs index 3d7898ddb..76a497182 100644 --- a/test/System.Net.Http.Formatting.Test/Formatting/JsonMediaTypeFormatterTests.cs +++ b/test/System.Net.Http.Formatting.Test/Formatting/JsonMediaTypeFormatterTests.cs @@ -83,18 +83,14 @@ void CopyConstructor() TestJsonMediaTypeFormatter formatter = new TestJsonMediaTypeFormatter() { Indent = true, -#if !NETFX_CORE // MaxDepth and DCJS not supported in client portable library MaxDepth = 42, UseDataContractJsonSerializer = true -#endif }; TestJsonMediaTypeFormatter derivedFormatter = new TestJsonMediaTypeFormatter(formatter); -#if !NETFX_CORE // MaxDepth and DCJS not supported in client portable library Assert.Equal(formatter.MaxDepth, derivedFormatter.MaxDepth); Assert.Equal(formatter.UseDataContractJsonSerializer, derivedFormatter.UseDataContractJsonSerializer); -#endif Assert.Equal(formatter.Indent, derivedFormatter.Indent); Assert.Same(formatter.SerializerSettings, derivedFormatter.SerializerSettings); Assert.Same(formatter.SerializerSettings.ContractResolver, derivedFormatter.SerializerSettings.ContractResolver); @@ -117,7 +113,6 @@ public void Indent_RoundTrips() expectedDefaultValue: false); } -#if !NETFX_CORE // MaxDepth is not supported in portable libraries [Fact] public void MaxDepth_RoundTrips() { @@ -131,7 +126,6 @@ public void MaxDepth_RoundTrips() illegalUpperValue: null, roundTripTestValue: 256); } -#endif [Theory] [TestDataSet(typeof(CommonUnitTestDataSets), "RepresentativeValueAndRefTypeTestDataCollection")] @@ -230,7 +224,6 @@ public async Task FormatterThrowsOnReadWhenOverridenCreateReturnsNull() Assert.NotNull(formatter.InnerJsonSerializer); } -#if !NETFX_CORE [Fact] public async Task DataContractFormatterThrowsOnWriteWhenOverridenCreateFails() { @@ -315,7 +308,6 @@ public async Task DataContractFormatterThrowsOnReadWhenOverridenCreateReturnsNul Assert.NotNull(formatter.InnerDataContractSerializer); Assert.Null(formatter.InnerJsonSerializer); } -#endif [Fact] public void CanReadType_ReturnsTrueOnJtoken() @@ -499,9 +491,7 @@ public async Task UseDataContractJsonSerializer_False() { JsonMediaTypeFormatter formatter = new JsonMediaTypeFormatter { -#if !NETFX_CORE // No JsonSerializer in portable libraries UseDataContractJsonSerializer = false -#endif }; MemoryStream memoryStream = new MemoryStream(); HttpContent content = new StringContent(String.Empty); @@ -518,9 +508,7 @@ public async Task UseDataContractJsonSerializer_False_Indent() { JsonMediaTypeFormatter formatter = new JsonMediaTypeFormatter { -#if !NETFX_CORE // No JsonSerializer in portable libraries UseDataContractJsonSerializer = false, -#endif Indent = true }; MemoryStream memoryStream = new MemoryStream(); @@ -538,9 +526,7 @@ public async Task UseJsonFormatterWithNull(Type type) { JsonMediaTypeFormatter formatter = new JsonMediaTypeFormatter { -#if !NETFX_CORE // No JsonSerializer in portable libraries UseDataContractJsonSerializer = false -#endif }; MemoryStream memoryStream = new MemoryStream(); HttpContent content = new StringContent(String.Empty); @@ -633,7 +619,6 @@ public override JsonSerializer CreateJsonSerializer() return InnerJsonSerializer; } -#if !NETFX_CORE public override DataContractJsonSerializer CreateDataContractSerializer(Type type) { InnerDataContractSerializer = base.CreateDataContractSerializer(type); @@ -650,7 +635,6 @@ public override DataContractJsonSerializer CreateDataContractSerializer(Type typ return InnerDataContractSerializer; } -#endif } private bool IsTypeSerializableWithJsonSerializer(Type type, object obj) diff --git a/test/System.Net.Http.Formatting.Test/Formatting/JsonNetValidationTest.cs b/test/System.Net.Http.Formatting.Test/Formatting/JsonNetValidationTest.cs index eac53df04..60bad376d 100644 --- a/test/System.Net.Http.Formatting.Test/Formatting/JsonNetValidationTest.cs +++ b/test/System.Net.Http.Formatting.Test/Formatting/JsonNetValidationTest.cs @@ -43,7 +43,6 @@ public static TheoryDataSet Theories } } -#if !NETFX_CORE // IRequiredMemeberSelector is not in portable libraries because there is no model state on the client. [Theory] [PropertyData("Theories")] public async Task ModelErrorsPopulatedWithValidationErrors(string json, Type type, int expectedErrors) @@ -56,7 +55,6 @@ public async Task ModelErrorsPopulatedWithValidationErrors(string json, Type typ mockLogger.Verify(mock => mock.LogError(It.IsAny(), It.IsAny()), Times.Exactly(expectedErrors)); } -#endif [Fact] public async Task HittingMaxDepthRaisesOnlyOneValidationError() @@ -81,7 +79,6 @@ public async Task HittingMaxDepthRaisesOnlyOneValidationError() } } -#if !NETFX_CORE // IRequiredMemeberSelector is not in portable libraries because there is no model state on the client. // this IRMS treats all member names that start with "Required" as required public class SimpleRequiredMemberSelector : IRequiredMemberSelector { @@ -90,7 +87,6 @@ public bool IsRequiredMember(MemberInfo member) return member.Name.StartsWith("Required"); } } -#endif public class DataContractWithRequiredMembers { diff --git a/test/System.Net.Http.Formatting.Test/Formatting/MediaTypeFormatterCollectionTests.cs b/test/System.Net.Http.Formatting.Test/Formatting/MediaTypeFormatterCollectionTests.cs index cd1c9e03b..9c8643757 100644 --- a/test/System.Net.Http.Formatting.Test/Formatting/MediaTypeFormatterCollectionTests.cs +++ b/test/System.Net.Http.Formatting.Test/Formatting/MediaTypeFormatterCollectionTests.cs @@ -361,9 +361,7 @@ public void FindWriter_ReturnsFormatterOnMatch(Type variationType, object testDa [InlineData(typeof(XAttribute))] [InlineData(typeof(Type))] [InlineData(typeof(byte[]))] -#if !NETFX_CORE [InlineData(typeof(XmlElement))] -#endif [InlineData(typeof(FormDataCollection))] public void IsTypeExcludedFromValidation_ReturnsTrueForExcludedTypes(Type type) { diff --git a/test/System.Net.Http.Formatting.Test/Formatting/MediaTypeFormatterTests.cs b/test/System.Net.Http.Formatting.Test/Formatting/MediaTypeFormatterTests.cs index 0d75a9634..526e0734f 100644 --- a/test/System.Net.Http.Formatting.Test/Formatting/MediaTypeFormatterTests.cs +++ b/test/System.Net.Http.Formatting.Test/Formatting/MediaTypeFormatterTests.cs @@ -51,12 +51,10 @@ public void Constructor() Collection supportedMediaTypes = formatter.SupportedMediaTypes; Assert.NotNull(supportedMediaTypes); Assert.Empty(supportedMediaTypes); -#if !NETFX_CORE // No MediaTypeMapping support in portable libraries Collection mappings = formatter.MediaTypeMappings; Assert.NotNull(mappings); Assert.Empty(mappings); -#endif } [Fact] @@ -65,11 +63,9 @@ void CopyConstructor() TestMediaTypeFormatter formatter = new TestMediaTypeFormatter(); TestMediaTypeFormatter derivedFormatter = new TestMediaTypeFormatter(formatter); -#if !NETFX_CORE // No MediaTypeMapping or RequiredMemberSelector in client libraries Assert.Same(formatter.MediaTypeMappings, derivedFormatter.MediaTypeMappings); Assert.Same(formatter.MediaTypeMappingsInternal, derivedFormatter.MediaTypeMappingsInternal); Assert.Equal(formatter.RequiredMemberSelector, derivedFormatter.RequiredMemberSelector); -#endif Assert.Same(formatter.SupportedMediaTypes, derivedFormatter.SupportedMediaTypes); Assert.Same(formatter.SupportedMediaTypesInternal, derivedFormatter.SupportedMediaTypesInternal); @@ -151,7 +147,6 @@ public void SupportedMediaTypes_InsertThrowsWithMediaRange(MediaTypeHeaderValue Assert.ThrowsArgument(() => supportedMediaTypes.Insert(0, mediaType), "item", Error.Format(Properties.Resources.CannotUseMediaRangeForSupportedMediaType, typeof(MediaTypeHeaderValue).Name, mediaType.MediaType)); } -#if !NETFX_CORE // No MediaTypeMapping support in portable libraries [Fact] public void MediaTypeMappings_IsMutable() { @@ -165,7 +160,6 @@ public void MediaTypeMappings_IsMutable() Assert.True(standardMappings.SequenceEqual(formatter.MediaTypeMappings)); } -#endif [Fact] public void SelectCharacterEncoding_ThrowsIfNoSupportedEncodings() diff --git a/test/System.Net.Http.Formatting.Test/Formatting/StringComparisonHelperTest.cs b/test/System.Net.Http.Formatting.Test/Formatting/StringComparisonHelperTest.cs index 77a8d2361..f18764086 100644 --- a/test/System.Net.Http.Formatting.Test/Formatting/StringComparisonHelperTest.cs +++ b/test/System.Net.Http.Formatting.Test/Formatting/StringComparisonHelperTest.cs @@ -12,15 +12,7 @@ public StringComparisonHelperTest() { } -#if NETFX_CORE // InvariantCulture and InvarianteCultureIgnore case are not supported in portable library projects - protected override void AssertForUndefinedValue(Action testCode, string parameterName, int invalidValue, Type enumType, bool allowDerivedExceptions = false) - { - Assert.ThrowsArgument( - testCode, - parameterName, - allowDerivedExceptions); - } - +#if NETFX_CORE // InvariantCulture and InvariantCultureIgnoreCase case are not supported in portable library projects protected override bool ValueExistsForFramework(StringComparison value) { return !(value == StringComparison.InvariantCulture || value == StringComparison.InvariantCultureIgnoreCase); diff --git a/test/System.Net.Http.Formatting.Test/Formatting/XmlMediaTypeFormatterTests.cs b/test/System.Net.Http.Formatting.Test/Formatting/XmlMediaTypeFormatterTests.cs index 3d7fd1557..d10e927d3 100644 --- a/test/System.Net.Http.Formatting.Test/Formatting/XmlMediaTypeFormatterTests.cs +++ b/test/System.Net.Http.Formatting.Test/Formatting/XmlMediaTypeFormatterTests.cs @@ -67,18 +67,14 @@ void CopyConstructor() TestXmlMediaTypeFormatter formatter = new TestXmlMediaTypeFormatter() { Indent = true, -#if !NETFX_CORE // We don't support MaxDepth in the portable library MaxDepth = 42, -#endif UseXmlSerializer = true }; TestXmlMediaTypeFormatter derivedFormatter = new TestXmlMediaTypeFormatter(formatter); Assert.Equal(formatter.Indent, derivedFormatter.Indent); -#if !NETFX_CORE // We don't support MaxDepth in the portable library Assert.Equal(formatter.MaxDepth, derivedFormatter.MaxDepth); -#endif Assert.Equal(formatter.UseXmlSerializer, derivedFormatter.UseXmlSerializer); } @@ -90,7 +86,6 @@ public void DefaultMediaType_ReturnsApplicationXml() Assert.Equal("application/xml", mediaType.MediaType); } -#if !NETFX_CORE // We don't support MaxDepth in the portable library [Fact] public void MaxDepthReturnsCorrectValue() { @@ -115,7 +110,6 @@ public async Task ReadDeeplyNestedObjectThrows() stream.Position = 0; await Assert.ThrowsAsync(() => formatter.ReadFromStreamAsync(typeof(SampleType), stream, null, null)); } -#endif [Fact] public void Indent_RoundTrips() @@ -520,23 +514,10 @@ public async Task ReadFromStreamAsync_RoundTripsWriteToStreamAsyncUsingDataContr public override Task ReadFromStreamAsync_UsesCorrectCharacterEncoding(string content, string encoding, bool isDefaultEncoding) { - if (!isDefaultEncoding) - { - // XmlDictionaryReader/Writer only supports utf-8 and 16 - return TaskHelpers.Completed(); - } - // Arrange XmlMediaTypeFormatter formatter = new XmlMediaTypeFormatter(); string formattedContent = "" + content + ""; -#if NETFX_CORE - // We need to supply the xml declaration when compiled in portable library for non utf-8 content - if (String.Equals("utf-16", encoding, StringComparison.OrdinalIgnoreCase)) - { - formattedContent = "" + formattedContent; - } -#endif string mediaType = string.Format("application/xml; charset={0}", encoding); // Act & assert @@ -588,12 +569,6 @@ public Task ReadFromStreamAsync_ThrowsException_WhenGetDeserializerReturnsInvali public override Task WriteToStreamAsync_UsesCorrectCharacterEncoding(string content, string encoding, bool isDefaultEncoding) { - if (!isDefaultEncoding) - { - // XmlDictionaryReader/Writer only supports utf-8 and 16 - return TaskHelpers.Completed(); - } - // Arrange XmlMediaTypeFormatter formatter = new XmlMediaTypeFormatter(); string formattedContent = "" + content + diff --git a/test/System.Net.Http.Formatting.Test/Formatting/XmlSerializerMediaTypeFormatterTests.cs b/test/System.Net.Http.Formatting.Test/Formatting/XmlSerializerMediaTypeFormatterTests.cs index 0b48c73ff..865b2be43 100644 --- a/test/System.Net.Http.Formatting.Test/Formatting/XmlSerializerMediaTypeFormatterTests.cs +++ b/test/System.Net.Http.Formatting.Test/Formatting/XmlSerializerMediaTypeFormatterTests.cs @@ -61,9 +61,7 @@ public async Task ReadDeeplyNestedObjectWorks() { XmlSerializerMediaTypeFormatter formatter = new XmlSerializerMediaTypeFormatter() { -#if !NETFX_CORE // We don't support MaxDepth in the portable library MaxDepth = 5001 -#endif }; StringContent content = new StringContent(GetDeeplyNestedObject(5000)); @@ -250,22 +248,9 @@ public async Task ReadFromStreamAsync_RoundTripsWriteToStreamAsyncUsingXmlSerial public override Task ReadFromStreamAsync_UsesCorrectCharacterEncoding(string content, string encoding, bool isDefaultEncoding) { - if (!isDefaultEncoding) - { - // XmlDictionaryReader/Writer only supports utf-8 and 16 - return TaskHelpers.Completed(); - } - // Arrange XmlSerializerMediaTypeFormatter formatter = new XmlSerializerMediaTypeFormatter(); string formattedContent = "" + content + ""; -#if NETFX_CORE - if (String.Equals("utf-16", encoding, StringComparison.OrdinalIgnoreCase)) - { - // We need to supply the xml declaration when compiled in portable library for non utf-8 content - formattedContent = "" + formattedContent; - } -#endif string mediaType = string.Format("application/xml; charset={0}", encoding); // Act & assert @@ -274,12 +259,6 @@ public override Task ReadFromStreamAsync_UsesCorrectCharacterEncoding(string con public override Task WriteToStreamAsync_UsesCorrectCharacterEncoding(string content, string encoding, bool isDefaultEncoding) { - if (!isDefaultEncoding) - { - // XmlDictionaryReader/Writer only supports utf-8 and 16 - return TaskHelpers.Completed(); - } - // Arrange XmlSerializerMediaTypeFormatter formatter = new XmlSerializerMediaTypeFormatter(); string formattedContent = "" + content + ""; diff --git a/test/System.Net.Http.Formatting.Test/Handlers/ProgressMessageHandlerTest.cs b/test/System.Net.Http.Formatting.Test/Handlers/ProgressMessageHandlerTest.cs index b7d71b4e5..36f50cde6 100644 --- a/test/System.Net.Http.Formatting.Test/Handlers/ProgressMessageHandlerTest.cs +++ b/test/System.Net.Http.Formatting.Test/Handlers/ProgressMessageHandlerTest.cs @@ -125,16 +125,13 @@ public ShortCircuitMessageHandler(bool includeResponseEntity) protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { -#if NETFX_CORE // Extension method only available on non portable library - HttpResponseMessage response = new HttpResponseMessage() { RequestMessage = request }; -#else HttpResponseMessage response = request.CreateResponse(); -#endif if (_includeResponseEntity) { response.Content = new StringContent("Response Entity"); response.Content.Headers.Add(TestHeader, TestValue); } + return Task.FromResult(response); } } diff --git a/test/System.Net.Http.Formatting.Test/Headers/CookieStateTest.cs b/test/System.Net.Http.Formatting.Test/Headers/CookieStateTest.cs index a00af171c..68383c238 100644 --- a/test/System.Net.Http.Formatting.Test/Headers/CookieStateTest.cs +++ b/test/System.Net.Http.Formatting.Test/Headers/CookieStateTest.cs @@ -29,19 +29,21 @@ public static TheoryDataSet EncodedCookieStateStrings { get { - return new TheoryDataSet + TheoryDataSet data = new TheoryDataSet { - { "?", "%3f" }, - { "=", "%3d" }, - { "", "%3cacb%3e" }, - { "{acb}", "%7bacb%7d" }, - { "[acb]", "%5bacb%5d" }, + { "?", "%3F" }, + { "=", "%3D" }, + { "", "%3Cacb%3E" }, + { "{acb}", "%7Bacb%7D" }, + { "[acb]", "%5Bacb%5D" }, { "\"acb\"", "%22acb%22" }, - { "a,b", "a%2cb" }, - { "a;b", "a%3bb" }, - { "a\\b", "a%5cb" }, - { "[]{}\\|!@#$%^&*()_-+=", "%5b%5d%7b%7d%5c%7c!%40%23%24%25%5e%26*()_-%2b%3d" }, + { "a,b", "a%2Cb" }, + { "a;b", "a%3Bb" }, + { "a\\b", "a%5Cb" }, + { "[]{}\\|!@#$%^&*()_-+=", "%5B%5D%7B%7D%5C%7C!%40%23%24%25%5E%26*()_-%2B%3D" }, }; + + return data; } } diff --git a/test/System.Net.Http.Formatting.Test/HttpContentFormDataExtensionsTest.cs b/test/System.Net.Http.Formatting.Test/HttpContentFormDataExtensionsTest.cs index d82bc3687..cf787bf37 100644 --- a/test/System.Net.Http.Formatting.Test/HttpContentFormDataExtensionsTest.cs +++ b/test/System.Net.Http.Formatting.Test/HttpContentFormDataExtensionsTest.cs @@ -8,9 +8,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.TestCommon; -#if NETFX_CORE -using NameValueCollection = System.Net.Http.Formatting.HttpValueCollection; -#endif namespace System.Net.Http { diff --git a/test/System.Net.Http.Formatting.Test/HttpRequestHeadersExtensionsTest.cs b/test/System.Net.Http.Formatting.Test/HttpRequestHeadersExtensionsTest.cs index a02eaa6da..b385cb423 100644 --- a/test/System.Net.Http.Formatting.Test/HttpRequestHeadersExtensionsTest.cs +++ b/test/System.Net.Http.Formatting.Test/HttpRequestHeadersExtensionsTest.cs @@ -45,7 +45,7 @@ public static TheoryDataSet CookieMatches new string[] { "adxcs=-", - "ADXCS=si=0%3a1" + "ADXCS=si=0%3A1" } }, { diff --git a/test/System.Net.Http.Formatting.Test/Internal/ByteRangeStreamTest.cs b/test/System.Net.Http.Formatting.Test/Internal/ByteRangeStreamTest.cs index eb193b51a..391f31b09 100644 --- a/test/System.Net.Http.Formatting.Test/Internal/ByteRangeStreamTest.cs +++ b/test/System.Net.Http.Formatting.Test/Internal/ByteRangeStreamTest.cs @@ -303,6 +303,7 @@ public async Task Position_PositionsNextRead() } } +#if !NETFX_CORE // BeginX and EndX are not supported on streams in portable libraries [Theory] [PropertyData("ReadBoundsDataWithLimit")] public void BeginRead_ReadsEffectiveLengthBytes(int from, int to, int innerLength, int effectiveLength) @@ -330,6 +331,7 @@ public void BeginRead_ReadsEffectiveLengthBytes(int from, int to, int innerLengt Assert.Equal(effectiveLength, rangeStream.Position); } } +#endif [Fact] public async Task BeginRead_CanReadAfterLength() diff --git a/test/System.Net.Http.Formatting.Test/Internal/ConcurrentDictionaryTests.cs b/test/System.Net.Http.Formatting.Test/Internal/ConcurrentDictionaryTests.cs index 2294f8ff5..cc08f4d92 100644 --- a/test/System.Net.Http.Formatting.Test/Internal/ConcurrentDictionaryTests.cs +++ b/test/System.Net.Http.Formatting.Test/Internal/ConcurrentDictionaryTests.cs @@ -4,26 +4,10 @@ using System.Collections.Generic; using Microsoft.TestCommon; -#if NETFX_CORE -namespace System.Net.Http.Internal -#else namespace System.Collections.Concurrent -#endif { public class ConcurrentDictionaryTests { -#if NETFX_CORE // This doesn't exist on the ConcurrentDictionary in the full framework - [Fact] - public void IsReadOnly_ReturnsFalse() - { - // Arrange - ConcurrentDictionary dictionary = new ConcurrentDictionary(); - - // Act & Assert - Assert.False(dictionary.IsReadOnly); - } -#endif - [Fact] public void ContainsKey_ReturnsFalseWhenKeyIsNotPresent() { @@ -41,7 +25,7 @@ public void ContainsKey_ReturnsTrueWhenKeyIsPresent() ConcurrentDictionary dictionary = new ConcurrentDictionary(); // Act - dictionary.TryAdd(1, 2); + dictionary.TryAdd(1, 2); // Assert Assert.True(dictionary.ContainsKey(1)); @@ -129,211 +113,5 @@ public void AddOrUpdate_UpdatesValueWhenKeyIsPresent() // Assert Assert.Equal(3, result); } - -#if NETFX_CORE - [Fact] - public void Add_ThrowsNotImplementedException() - { - // Arrange - ConcurrentDictionary dictionary = new ConcurrentDictionary(); - - // Act/Assert - Assert.Throws(() => dictionary.Add(0, 0)); - } - - [Fact] - public void Add_KeyValuePairThrowsNotImplementedException() - { - // Arrange - ConcurrentDictionary dictionary = new ConcurrentDictionary(); - - // Act/Assert - Assert.Throws(() => dictionary.Add(new KeyValuePair(0, 0))); - } - - [Fact] - public void Clear_ThrowsNotImplementedException() - { - // Arrange - ConcurrentDictionary dictionary = new ConcurrentDictionary(); - - // Act/Assert - Assert.Throws(() => dictionary.Clear()); - } - - [Fact] - public void Contains_KeyValuePairThrowsNotImplementedException() - { - // Arrange - ConcurrentDictionary dictionary = new ConcurrentDictionary(); - - // Act/Assert - Assert.Throws(() => dictionary.Contains(new KeyValuePair(0, 0))); - } - - [Fact] - public void CopyTo_ThrowsNotImplementedException() - { - // Arrange - ConcurrentDictionary dictionary = new ConcurrentDictionary(); - - // Act/Assert - Assert.Throws(() => dictionary.CopyTo(new KeyValuePair[1], 1)); - } - - [Fact] - public void GetEnumerator_ThrowsNotImplementedException() - { - // Arrange - ConcurrentDictionary dictionary = new ConcurrentDictionary(); - - // Act/Assert - Assert.Throws(() => dictionary.GetEnumerator()); - } - - [Fact] - public void Remove_ThrowsNotImplementedException() - { - // Arrange - ConcurrentDictionary dictionary = new ConcurrentDictionary(); - - // Act/Assert - Assert.Throws(() => dictionary.Remove(0)); - } - - [Fact] - public void Remove_WithKeyValuePairThrowsNotImplementedException() - { - // Arrange - ConcurrentDictionary dictionary = new ConcurrentDictionary(); - - // Act/Assert - Assert.Throws(() => dictionary.Remove(new KeyValuePair(0, 0))); - } - - [Fact] - public void GetEnumerator_AsEnumerableThrowsNotImplementedException() - { - // Arrange - ConcurrentDictionary dictionary = new ConcurrentDictionary(); - - // Act/Assert - Assert.Throws(() => ((System.Collections.IEnumerable)dictionary).GetEnumerator()); - } - - [Fact] - public void TryGetValue_ReturnsTrueAndValueWhenPresent() - { - // Arrange - ConcurrentDictionary dictionary = new ConcurrentDictionary(); - dictionary.TryAdd(1, -1); - - // Act - int returnedValue; - bool tryResult = dictionary.TryGetValue(1, out returnedValue); - - // Assert - Assert.Equal(-1, returnedValue); - Assert.True(tryResult); - } - - [Fact] - public void TryGetValue_ReturnsFalseAndDefaultWhenMissing() - { - // Arrange - ConcurrentDictionary dictionary = new ConcurrentDictionary(); - dictionary.TryAdd(1, -1); - - // Act - int returnedValue; - bool tryResult = dictionary.TryGetValue(2, out returnedValue); - - // Assert - Assert.Equal(0, returnedValue); - Assert.False(tryResult); - } - - [Fact] - public void TryRemove_ReturnsTrueAndRemovesWhenPresent() - { - // Arrange - ConcurrentDictionary dictionary = new ConcurrentDictionary(); - dictionary.TryAdd(1, -1); - - // Act - int returnedValue; - bool tryResult = dictionary.TryGetValue(1, out returnedValue); - - // Assert - Assert.Equal(-1, returnedValue); - Assert.True(tryResult); - } - - [Fact] - public void TryRemove_ReturnsFalseAndDefaultWhenMissing() - { - // Arrange - ConcurrentDictionary dictionary = new ConcurrentDictionary(); - dictionary.TryAdd(1, -1); - - // Act - int returnedValue; - bool tryResult = dictionary.TryGetValue(2, out returnedValue); - - // Assert - Assert.Equal(0, returnedValue); - Assert.False(tryResult); - } - - [Fact] - public void Count_ThrowsNotImplementedException() - { - // Arrange - ConcurrentDictionary dictionary = new ConcurrentDictionary(); - - // Act/Assert - Assert.Throws(() => dictionary.Count); - } - - [Fact] - public void GetItem_ThrowsNotImplementedException() - { - // Arrange - ConcurrentDictionary dictionary = new ConcurrentDictionary(); - - // Act/Assert - Assert.Throws(() => dictionary[0]); - } - - [Fact] - public void SetItem_ThrowsNotImplementedException() - { - // Arrange - ConcurrentDictionary dictionary = new ConcurrentDictionary(); - - // Act/Assert - Assert.Throws(() => dictionary[0] = 1); - } - - [Fact] - public void GetKeys_ThrowsNotImplementedException() - { - // Arrange - ConcurrentDictionary dictionary = new ConcurrentDictionary(); - - // Act/Assert - Assert.Throws(() => dictionary.Keys); - } - - [Fact] - public void GetValues_ThrowsNotImplementedException() - { - // Arrange - ConcurrentDictionary dictionary = new ConcurrentDictionary(); - - // Act/Assert - Assert.Throws(() => dictionary.Values); - } -#endif } } diff --git a/test/System.Net.Http.Formatting.Test/Internal/HttpValueCollectionTest.cs b/test/System.Net.Http.Formatting.Test/Internal/HttpValueCollectionTest.cs index 03b5aadf0..fdf8a58cb 100644 --- a/test/System.Net.Http.Formatting.Test/Internal/HttpValueCollectionTest.cs +++ b/test/System.Net.Http.Formatting.Test/Internal/HttpValueCollectionTest.cs @@ -4,9 +4,7 @@ using System.Collections.Generic; using System.Linq; using System.Net.Http.Formatting; -#if !NETFX_CORE using System.Net.Http.Formatting.Internal; -#endif using System.Web.WebPages.TestUtils; using Microsoft.TestCommon; @@ -20,11 +18,7 @@ public class HttpValueCollectionTest private static HttpValueCollection CreateInstance() { -#if NETFX_CORE - return new HttpValueCollection(); -#else return HttpValueCollection.Create(); -#endif } #if !NETCOREAPP @@ -79,11 +73,7 @@ public static TheoryDataSet ToStringTestData hvc4.Add("na me", ""); dataSet.Add(hvc4, "na+me"); -#if NETFX_CORE string encoded5 = "n%22%2C%3B%5Cn"; -#else - string encoded5 = "n%22%2c%3b%5cn"; -#endif var hvc5 = CreateInstance(); hvc5.Add("n\",;\\n", ""); @@ -103,22 +93,14 @@ public static TheoryDataSet ToStringTestData hvc7.Add("n4", "v4"); dataSet.Add(hvc7, "n1=v1&n2=v2&n3=v3&n4=v4"); -#if NETFX_CORE string encoded8 = "n%2C1=v%2C1&n%3B2=v%3B2"; -#else - string encoded8 = "n%2c1=v%2c1&n%3b2=v%3b2"; -#endif var hvc8 = CreateInstance(); hvc8.Add("n,1", "v,1"); hvc8.Add("n;2", "v;2"); dataSet.Add(hvc8, encoded8); -#if NETFX_CORE string encoded9 = "n1=%26&n2=%3B&n3=%26&n4=%2B&n5=%26&n6=%3D&n7=%26"; -#else - string encoded9 = "n1=%26&n2=%3b&n3=%26&n4=%2b&n5=%26&n6=%3d&n7=%26"; -#endif var hvc9 = CreateInstance(); hvc9.Add("n1", "&"); @@ -268,14 +250,8 @@ public void Create_InitializesCorrectly(IEnumerable string expectedKey = kvp.Key ?? String.Empty; string expectedValue = kvp.Value ?? String.Empty; -#if NETFX_CORE - KeyValuePair actualKvp = nvc.List[index]; - string actualKey = actualKvp.Key; - string actualValue = actualKvp.Value; -#else string actualKey = nvc.AllKeys[index]; string actualValue = nvc[index]; -#endif index++; Assert.Equal(expectedKey, actualKey); diff --git a/test/System.Net.Http.Formatting.Test/Internal/ReadOnlyStreamWithEncodingPreambleTest.cs b/test/System.Net.Http.Formatting.Test/Internal/ReadOnlyStreamWithEncodingPreambleTest.cs deleted file mode 100644 index fc7fa40ac..000000000 --- a/test/System.Net.Http.Formatting.Test/Internal/ReadOnlyStreamWithEncodingPreambleTest.cs +++ /dev/null @@ -1,75 +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.IO; -using System.Reflection; -using System.Text; -using Microsoft.TestCommon; - -namespace System.Net.Http.Internal -{ - public class ReadOnlyStreamWithEncodingPreambleTest - { - [Theory] - [EncodingData] - public void StreamWithoutPreamble(Encoding encoding, bool includePreambleInInputStream) - { - using (MemoryStream inputStream = new MemoryStream()) - { - // Arrange - string message = "Hello, world" + Environment.NewLine // English - + "こんにちは、世界" + Environment.NewLine // Japanese - + "مرحبا، العالم"; // Arabic - - byte[] preamble = encoding.GetPreamble(); - byte[] encodedMessage = encoding.GetBytes(message); - - if (includePreambleInInputStream) - { - inputStream.Write(preamble, 0, preamble.Length); - } - - inputStream.Write(encodedMessage, 0, encodedMessage.Length); - - byte[] expectedBytes = new byte[preamble.Length + encodedMessage.Length]; - preamble.CopyTo(expectedBytes, 0); - encodedMessage.CopyTo(expectedBytes, preamble.Length); - - inputStream.Seek(0, SeekOrigin.Begin); - - using (ReadOnlyStreamWithEncodingPreamble wrapperStream = new ReadOnlyStreamWithEncodingPreamble(inputStream, encoding)) - { - // Act - int totalRead = 0; - byte[] readBuffer = new byte[expectedBytes.Length]; - - while (totalRead < readBuffer.Length) - { - int read = wrapperStream.Read(readBuffer, totalRead, readBuffer.Length - totalRead); - totalRead += read; - - if (read == 0) - break; - } - - // Assert - Assert.Equal(expectedBytes.Length, totalRead); - Assert.Equal(expectedBytes, readBuffer); - Assert.Equal(0, wrapperStream.Read(readBuffer, 0, 1)); // Make sure there are no stray bytes left in the stream - } - } - } - - class EncodingDataAttribute : DataAttribute - { - public override IEnumerable GetData(MethodInfo methodUnderTest, Type[] parameterTypes) - { - return new MatrixTheoryDataSet( - new[] { Encoding.UTF7, Encoding.UTF8, Encoding.BigEndianUnicode, Encoding.Unicode, Encoding.UTF32, Encoding.ASCII }, - new[] { false, true } - ); - } - } - } -} diff --git a/test/System.Net.Http.Formatting.Test/Internal/TranscodingStreamTests.cs b/test/System.Net.Http.Formatting.Test/Internal/TranscodingStreamTests.cs new file mode 100644 index 000000000..8f9a43b88 --- /dev/null +++ b/test/System.Net.Http.Formatting.Test/Internal/TranscodingStreamTests.cs @@ -0,0 +1,1145 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// From https://github.com/dotnet/runtime/blob/88868b7a781f4e5b9037b8721f30440207a7aa42/src/libraries/System.Text.Encoding/tests/Encoding/TranscodingStreamTests.cs + +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.IO.Pipelines; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.TestCommon; +using Moq; + +#nullable enable annotations + +namespace System.Text.Tests +{ + public class TranscodingStreamTests + { + public static IEnumerable ReadWriteTestBufferLengths + { + get + { + yield return new object[] { 1 }; + yield return new object[] { 4 * 1024 }; + yield return new object[] { 128 * 1024 }; + yield return new object[] { 2 * 1024 * 1024 }; + } + } + +#if NETFX_CORE || Testing_NetStandard2_0 // .NET Framework implementation loses track of cancellation token. + [Fact] + public void AsyncMethods_ReturnCanceledTaskIfCancellationTokenTripped() + { + // Arrange + + CancellationTokenSource cts = new(); + CancellationToken expectedCancellationToken = cts.Token; + cts.Cancel(); + + var innerStreamMock = new Mock(MockBehavior.Strict); // only CanRead/CanWrite should ever be invoked + innerStreamMock.Setup(o => o.CanRead).Returns(true); + innerStreamMock.Setup(o => o.CanWrite).Returns(true); + + Stream transcodingStream = new TranscodingStream(innerStreamMock.Object, Encoding.UTF8, Encoding.UTF8, leaveOpen: true); + + // Act & assert + + RunTest(() => transcodingStream.ReadAsync(new byte[0], 0, 0, expectedCancellationToken)); + RunTest(() => transcodingStream.WriteAsync(new byte[0], 0, 0, expectedCancellationToken)); +#if NETCOREAPP || NETSTANDARD2_1 + RunTest(() => transcodingStream.ReadAsync(Memory.Empty, expectedCancellationToken).AsTask()); + RunTest(() => transcodingStream.WriteAsync(ReadOnlyMemory.Empty, expectedCancellationToken).AsTask()); +#endif + + void RunTest(Func callback) + { + Task task = callback(); + Assert.True(task.IsCanceled); + Assert.Equal(expectedCancellationToken, Assert.Throws(() => task.GetAwaiter().GetResult()).CancellationToken); + } + } +#endif + + [Fact] + public void CreateTranscodingStream_InvalidArgs() + { + Assert.ThrowsArgumentNull(() => new TranscodingStream(null, Encoding.UTF8, Encoding.UTF8), "innerStream"); + Assert.ThrowsArgumentNull(() => new TranscodingStream(Stream.Null, null, Encoding.UTF8), "innerEncoding"); + Assert.ThrowsArgumentNull(() => new TranscodingStream(Stream.Null, Encoding.UTF8, null), "thisEncoding"); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void CanRead_DelegatesToInnerStream(bool expectedCanRead) + { + // Arrange + + var innerStreamMock = new Mock(); + innerStreamMock.Setup(o => o.CanRead).Returns(expectedCanRead); + Stream transcodingStream = new TranscodingStream(innerStreamMock.Object, Encoding.UTF8, Encoding.UTF8, leaveOpen: true); + + // Act + + bool actualCanReadBeforeDispose = transcodingStream.CanRead; + transcodingStream.Dispose(); + bool actualCanReadAfterDispose = transcodingStream.CanRead; + + // Assert + + Assert.Equal(expectedCanRead, actualCanReadBeforeDispose); + Assert.False(actualCanReadAfterDispose); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void CanWrite_DelegatesToInnerStream(bool expectedCanWrite) + { + // Arrange + + var innerStreamMock = new Mock(); + innerStreamMock.Setup(o => o.CanWrite).Returns(expectedCanWrite); + Stream transcodingStream = new TranscodingStream(innerStreamMock.Object, Encoding.UTF8, Encoding.UTF8, leaveOpen: true); + + // Act + + bool actualCanWriteBeforeDispose = transcodingStream.CanWrite; + transcodingStream.Dispose(); + bool actualCanWriteAfterDispose = transcodingStream.CanWrite; + + // Assert + + Assert.Equal(expectedCanWrite, actualCanWriteBeforeDispose); + Assert.False(actualCanWriteAfterDispose); + } + + [Fact] + public void Dispose_MakesMostSubsequentOperationsThrow() + { + // Arrange + + MemoryStream innerStream = new(); + Stream transcodingStream = new TranscodingStream(innerStream, Encoding.UTF8, Encoding.UTF8, leaveOpen: true); + + // Act + + transcodingStream.Dispose(); + + // Assert + // For Task/ValueTask-returning methods, we want the exception to be thrown synchronously. + + Assert.False(transcodingStream.CanRead); + Assert.False(transcodingStream.CanSeek); + Assert.False(transcodingStream.CanWrite); + +#if true // Not overriding these and base Stream's BeginXYZ methods check CanXYZ first, throwing NotSupportedException. + Assert.Throws(() => transcodingStream.BeginRead(new byte[0], 0, 0, null, null)); + Assert.Throws(() => transcodingStream.BeginWrite(new byte[0], 0, 0, null, null)); +#else + Assert.Throws(() => transcodingStream.BeginRead(new byte[0], 0, 0, null, null)); + Assert.Throws(() => transcodingStream.BeginWrite(new byte[0], 0, 0, null, null)); +#endif +#if NETCOREAPP || NETSTANDARD2_1 + Assert.Throws(() => transcodingStream.Read(Span.Empty)); + Assert.Throws(() => (object)transcodingStream.ReadAsync(Memory.Empty)); + Assert.Throws(() => transcodingStream.Write(ReadOnlySpan.Empty)); + Assert.Throws(() => (object)transcodingStream.WriteAsync(ReadOnlyMemory.Empty)); +#endif + Assert.Throws(() => transcodingStream.Flush()); + Assert.Throws(() => (object)transcodingStream.FlushAsync()); + Assert.Throws(() => transcodingStream.Read(new byte[0], 0, 0)); + Assert.Throws(() => (object)transcodingStream.ReadAsync(new byte[0], 0, 0)); + Assert.Throws(() => transcodingStream.ReadByte()); + Assert.Throws(() => transcodingStream.Write(new byte[0], 0, 0)); + Assert.Throws(() => (object)transcodingStream.WriteAsync(new byte[0], 0, 0)); + Assert.Throws(() => transcodingStream.WriteByte((byte)'x')); + } + + [Fact] + public void Dispose_WithLeaveOpenFalse_DisposesInnerStream() + { + // Sync + + MemoryStream innerStream = new(); + Stream transcodingStream = new TranscodingStream(innerStream, Encoding.UTF8, Encoding.UTF8, leaveOpen: false); + transcodingStream.Dispose(); + transcodingStream.Dispose(); // calling it a second time should no-op + Assert.Throws(() => innerStream.Read(TranscodingStream.EmptyByteBuffer, 0, 0)); + + // Async + +#if NETCOREAPP3_1 || NET5_0_OR_GREATER || NETSTANDARD2_1 + innerStream = new MemoryStream(); + transcodingStream = new TranscodingStream(innerStream, Encoding.UTF8, Encoding.UTF8, leaveOpen: false); + transcodingStream.DisposeAsync().GetAwaiter().GetResult(); + transcodingStream.DisposeAsync().GetAwaiter().GetResult(); // calling it a second time should no-op + Assert.Throws(() => innerStream.Read(Span.Empty)); +#endif + } + + [Fact] + public void Dispose_WithLeaveOpenTrue_DoesNotDisposeInnerStream() + { + // Sync + + MemoryStream innerStream = new(); + Stream transcodingStream = new TranscodingStream(innerStream, Encoding.UTF8, Encoding.UTF8, leaveOpen: true); + transcodingStream.Dispose(); + transcodingStream.Dispose(); // calling it a second time should no-op + innerStream.Read(TranscodingStream.EmptyByteBuffer, 0, 0); // shouldn't throw + + // Async + +#if NETCOREAPP3_1 || NET5_0_OR_GREATER || NETSTANDARD2_1 + innerStream = new MemoryStream(); + transcodingStream = new TranscodingStream(innerStream, Encoding.UTF8, Encoding.UTF8, leaveOpen: true); + transcodingStream.DisposeAsync().GetAwaiter().GetResult(); + transcodingStream.DisposeAsync().GetAwaiter().GetResult(); // calling it a second time should no-op + innerStream.Read(Span.Empty); // shouldn't throw +#endif + } + + // Moq heavily utilizes RefEmit, which does not work on most aot workloads + [Fact] + public void Flush_FlushesInnerStreamButNotDecodedState() + { + // Arrange + + CancellationToken expectedCancellationToken = new CancellationTokenSource().Token; + Task expectedFlushAsyncTask = Task.FromResult("just some task"); + + var innerStreamMock = new Mock() { CallBase = true }; + innerStreamMock.Setup(o => o.FlushAsync(expectedCancellationToken)).Returns(expectedFlushAsyncTask); + Stream transcodingStream = new TranscodingStream(innerStreamMock.Object, Encoding.UTF8, Encoding.UTF8, leaveOpen: true); + + transcodingStream.Write(new byte[] { 0x7A, 0xE0 }, 0, 2); + innerStreamMock.Verify(o => o.Flush(), Times.Never); + innerStreamMock.Verify(o => o.FlushAsync(It.IsAny()), Times.Never); + + // Act & assert - sync flush + + transcodingStream.Flush(); + innerStreamMock.Verify(o => o.Flush(), Times.Once); + innerStreamMock.Verify(o => o.FlushAsync(It.IsAny()), Times.Never); + + // Act & assert - async flush + // This also validates that we flowed the CancellationToken as expected + + Task actualFlushAsyncReturnedTask = transcodingStream.FlushAsync(expectedCancellationToken); + Assert.Same(expectedFlushAsyncTask, actualFlushAsyncReturnedTask); + innerStreamMock.Verify(o => o.Flush(), Times.Once); + innerStreamMock.Verify(o => o.FlushAsync(expectedCancellationToken), Times.Once); + + Assert.Equal("z", Encoding.UTF8.GetString(innerStreamMock.Object.ToArray())); // [ E0 ] shouldn't have been flushed + } + + [Fact] + public void IdenticalInnerAndOuterEncodings_DoesNotActAsPassthrough() + { + // Test read + // [ C0 ] is never a valid UTF-8 byte, should be replaced with U+FFFD + + MemoryStream innerStream = new(new byte[] { 0xC0 }); + Stream transcodingStream = new TranscodingStream(innerStream, Encoding.UTF8, Encoding.UTF8); + + Assert.Equal(0xEF, transcodingStream.ReadByte()); + Assert.Equal(0xBF, transcodingStream.ReadByte()); + Assert.Equal(0xBD, transcodingStream.ReadByte()); + Assert.Equal(-1 /* eof */, transcodingStream.ReadByte()); + + // Test write + + innerStream = new MemoryStream(); + transcodingStream = new TranscodingStream(innerStream, Encoding.UTF8, Encoding.UTF8); + transcodingStream.WriteByte(0xC0); + Assert.Equal(new byte[] { 0xEF, 0xBF, 0xBD }, innerStream.ToArray()); + } + + [Theory] + [PropertyData(nameof(ReadWriteTestBufferLengths))] + public void Read_ByteArray(int bufferLength) + { + // Tests TranscodingStream.Read(byte[], int, int) + + byte[] buffer = new byte[bufferLength + 3]; + + RunReadTest((transcodingStream, sink) => + { + int numBytesRead = transcodingStream.Read(buffer, 1, bufferLength); + Assert.True(numBytesRead >= 0); + Assert.True(numBytesRead <= bufferLength); + + sink.Write(buffer, 1, numBytesRead); + return numBytesRead; + }); + } + + [Fact] + public void Read_ByteArray_WithInvalidArgs_Throws() + { + Stream transcodingStream = new TranscodingStream(new MemoryStream(), Encoding.UTF8, Encoding.UTF8); + + Assert.ThrowsArgumentNull(() => transcodingStream.Read(null, 0, 0), "buffer"); + Assert.Throws(() => transcodingStream.Read(new byte[5], -1, -1)); + Assert.Throws(() => transcodingStream.Read(new byte[5], 3, -1)); + Assert.Throws(() => transcodingStream.Read(new byte[5], 5, 1)); + Assert.Throws(() => transcodingStream.Read(new byte[5], 6, -1)); + Assert.Throws(() => transcodingStream.Read(new byte[5], 6, 0)); + } + + [Fact] + public void Read_ByteByByte() + { + // Tests TranscodingStream.ReadByte + + RunReadTest((transcodingStream, sink) => + { + int value = transcodingStream.ReadByte(); + if (value < 0) + { + return 0; + } + + sink.WriteByte(checked((byte)value)); + return 1; + }); + } + +#if NETCOREAPP || NETSTANDARD2_1 + [Theory] + [PropertyData(nameof(ReadWriteTestBufferLengths))] + public void Read_Span(int bufferLength) + { + // Tests TranscodingStream.Read(Span) + + byte[] buffer = new byte[bufferLength]; + + RunReadTest((transcodingStream, sink) => + { + int numBytesRead = transcodingStream.Read(buffer.AsSpan()); + Assert.True(numBytesRead >= 0); + Assert.True(numBytesRead <= bufferLength); + + sink.Write(buffer.AsSpan(0, numBytesRead)); + return numBytesRead; + }); + } +#endif + + private void RunReadTest(Func callback) + { + MemoryStream sink = new(); + + MemoryStream innerStream = new(); + Stream transcodingStream = new TranscodingStream(innerStream, + innerEncoding: Encoding.UTF8, + thisEncoding: CustomAsciiEncoding); + + // Test with a small string, then test with a large string + + RunOneTestIteration(128); + RunOneTestIteration(10 * 1024 * 1024); + + Assert.Equal(-1, transcodingStream.ReadByte()); // should've reached EOF + + // Now put some invalid data into the inner stream, followed by EOF, and ensure we get U+FFFD back out. + + innerStream.SetLength(0); // reset + innerStream.WriteByte(0xC0); // [ C0 ] is never valid in UTF-8 + innerStream.Position = 0; + + sink.SetLength(0); // reset + int numBytesReadJustNow; + do + { + numBytesReadJustNow = callback(transcodingStream, sink); + Assert.True(numBytesReadJustNow >= 0); + } while (numBytesReadJustNow > 0); + + Assert.Equal("[FFFD]", ErrorCheckingAsciiEncoding.GetString(sink.ToArray())); + Assert.Equal(-1, transcodingStream.ReadByte()); // should've reached EOF + + // Now put some incomplete data into the inner stream, followed by EOF, and ensure we get U+FFFD back out. + + innerStream.SetLength(0); // reset + innerStream.WriteByte(0xC2); // [ C2 ] must be followed by [ 80..BF ] in UTF-8 + innerStream.Position = 0; + + sink.SetLength(0); // reset + do + { + numBytesReadJustNow = callback(transcodingStream, sink); + Assert.True(numBytesReadJustNow >= 0); + } while (numBytesReadJustNow > 0); + + Assert.Equal("[FFFD]", ErrorCheckingAsciiEncoding.GetString(sink.ToArray())); + Assert.Equal(-1, transcodingStream.ReadByte()); // should've reached EOF + + void RunOneTestIteration(int stringLength) + { + sink.SetLength(0); // reset + + string expectedStringContents = GetVeryLongAsciiString(stringLength); + innerStream.SetLength(0); // reset + var bytes = Encoding.UTF8.GetBytes(expectedStringContents); + innerStream.Write(bytes, 0, bytes.Length); + innerStream.Position = 0; + + int numBytesReadJustNow; + do + { + numBytesReadJustNow = callback(transcodingStream, sink); + Assert.True(numBytesReadJustNow >= 0); + } while (numBytesReadJustNow > 0); + + Assert.Equal(expectedStringContents, ErrorCheckingAsciiEncoding.GetString(sink.ToArray())); + } + } + + [Fact] + public Task ReadApm() + { + // Tests TranscodingStream.BeginRead / EndRead + + byte[] buffer = new byte[1024 * 1024]; + + return RunReadTestAsync((transcodingStream, cancellationToken, sink) => + { + TaskCompletionSource tcs = new(); + object expectedState = new(); + + try + { + IAsyncResult asyncResult = transcodingStream.BeginRead(buffer, 1, buffer.Length - 2, (asyncResult) => + { + try + { + int numBytesReadJustNow = transcodingStream.EndRead(asyncResult); + Assert.True(numBytesReadJustNow >= 0); + Assert.True(numBytesReadJustNow < buffer.Length - 3); + sink.Write(buffer, 1, numBytesReadJustNow); + tcs.SetResult(numBytesReadJustNow); + } + catch (Exception ex) + { + tcs.SetException(ex); + } + }, expectedState); + Assert.Same(expectedState, asyncResult.AsyncState); + } + catch (Exception ex) + { + tcs.SetException(ex); + } + + return new ValueTask(tcs.Task); + }, + suppressExpectedCancellationTokenAsserts: true); // APM pattern doesn't allow flowing CancellationToken + } + + [Theory] + [PropertyData(nameof(ReadWriteTestBufferLengths))] + public Task ReadAsync_ByteArray(int bufferLength) + { + // Tests TranscodingStream.ReadAsync(byte[], int, int, CancellationToken) + + byte[] buffer = new byte[bufferLength + 3]; + + return RunReadTestAsync(async (transcodingStream, cancellationToken, sink) => + { + int numBytesRead = await transcodingStream.ReadAsync(buffer, 1, bufferLength, cancellationToken); + Assert.True(numBytesRead >= 0); + Assert.True(numBytesRead <= bufferLength); + + sink.Write(buffer, 1, numBytesRead); + return numBytesRead; + }); + } + +#if NETCOREAPP || NETSTANDARD2_1 + [Theory] + [PropertyData(nameof(ReadWriteTestBufferLengths))] + public async Task ReadAsync_Memory(int bufferLength) + { + // Tests TranscodingStream.ReadAsync(Memory, CancellationToken) + + byte[] buffer = new byte[bufferLength]; + + await RunReadTestAsync(async (transcodingStream, cancellationToken, sink) => + { + int numBytesRead = await transcodingStream.ReadAsync(buffer.AsMemory(), cancellationToken); + Assert.True(numBytesRead >= 0); + Assert.True(numBytesRead <= bufferLength); + + sink.Write(buffer.AsSpan(0, numBytesRead)); + return numBytesRead; + }); + } +#endif + + [Fact] + public async Task ReadAsync_LoopsWhenPartialDataReceived() + { + // Validates that the TranscodingStream will loop instead of returning 0 + // if the inner stream read partial data and GetBytes cannot make forward progress. + + using AsyncComms comms = new(); + Stream transcodingStream = new TranscodingStream(comms.ReadStream, Encoding.UTF8, Encoding.UTF8); + + // First, ensure that writing [ C0 ] (always invalid UTF-8) to the stream + // causes the reader to return immediately with fallback behavior. + + byte[] readBuffer = new byte[1024]; + comms.WriteBytes(new byte[] { 0xC0 }); + + int numBytesRead = await transcodingStream.ReadAsync(readBuffer, 0, readBuffer.Length); + Assert.Equal(new byte[] { 0xEF, 0xBF, 0xBD }, readBuffer.AsSpan(0, numBytesRead).ToArray()); // fallback substitution + + // Next, ensure that writing [ C2 ] (partial UTF-8, needs more data) to the stream + // causes the reader to asynchronously loop, returning "not yet complete". + + readBuffer = new byte[1024]; + comms.WriteBytes(new byte[] { 0xC2 }); + + var task = transcodingStream.ReadAsync(readBuffer, 0, readBuffer.Length); + Assert.False(task.IsCompleted); + comms.WriteBytes(new byte[] { 0x80 }); // [ C2 80 ] is valid UTF-8 + + numBytesRead = await task; // should complete successfully + Assert.Equal(new byte[] { 0xC2, 0x80 }, readBuffer.AsSpan(0, numBytesRead).ToArray()); + + // Finally, ensure that writing [ C2 ] (partial UTF-8, needs more data) to the stream + // followed by EOF causes the reader to perform substitution before returning EOF. + + readBuffer = new byte[1024]; + comms.WriteBytes(new byte[] { 0xC2 }); + + task = transcodingStream.ReadAsync(readBuffer, 0, readBuffer.Length); + Assert.False(task.IsCompleted); + comms.WriteEof(); + + numBytesRead = await task; // should complete successfully + Assert.Equal(new byte[] { 0xEF, 0xBF, 0xBD }, readBuffer.AsSpan(0, numBytesRead).ToArray()); // fallback substitution + + // Next call really should return "EOF reached" + + readBuffer = new byte[1024]; + Assert.Equal(0, await transcodingStream.ReadAsync(readBuffer, 0, readBuffer.Length)); + } + + [Fact] + public void ReadAsync_WithInvalidArgs_Throws() + { + Stream transcodingStream = new TranscodingStream(new MemoryStream(), Encoding.UTF8, Encoding.UTF8); + + Assert.ThrowsArgumentNull(() => { transcodingStream.ReadAsync(null, 0, 0); }, "buffer"); + Assert.Throws(() => (object)transcodingStream.ReadAsync(new byte[5], -1, -1)); + Assert.Throws(() => (object)transcodingStream.ReadAsync(new byte[5], 3, -1)); + Assert.Throws(() => (object)transcodingStream.ReadAsync(new byte[5], 5, 1)); + Assert.Throws(() => (object)transcodingStream.ReadAsync(new byte[5], 6, -1)); + Assert.Throws(() => (object)transcodingStream.ReadAsync(new byte[5], 6, 0)); + } + + [Fact] + public void ReadApm_WithInvalidArgs_ThrowsAsync() + { + Stream transcodingStream = new TranscodingStream(new MemoryStream(), Encoding.UTF8, Encoding.UTF8); + +#if true + // Not overriding BeginRead and base Stream's method returns a Task as its IAsyncResult, delaying parameter checks. + Assert.ThrowsArgumentNull(() => transcodingStream.EndRead(transcodingStream.BeginRead(null, 0, 0, null, null)), "buffer"); + Assert.Throws(() => transcodingStream.EndRead(transcodingStream.BeginRead(new byte[5], -1, -1, null, null))); + Assert.Throws(() => transcodingStream.EndRead(transcodingStream.BeginRead(new byte[5], 3, -1, null, null))); + Assert.Throws(() => transcodingStream.EndRead(transcodingStream.BeginRead(new byte[5], 5, 1, null, null))); + Assert.Throws(() => transcodingStream.EndRead(transcodingStream.BeginRead(new byte[5], 6, -1, null, null))); + Assert.Throws(() => transcodingStream.EndRead(transcodingStream.BeginRead(new byte[5], 6, 0, null, null))); +#else + Assert.ThrowsArgumentNull(() => transcodingStream.BeginRead(null, 0, 0, null, null), "buffer"); + Assert.Throws(() => transcodingStream.BeginRead(new byte[5], -1, -1, null, null)); + Assert.Throws(() => transcodingStream.BeginRead(new byte[5], 3, -1, null, null)); + Assert.Throws(() => transcodingStream.BeginRead(new byte[5], 5, 1, null, null)); + Assert.Throws(() => transcodingStream.BeginRead(new byte[5], 6, -1, null, null)); + Assert.Throws(() => transcodingStream.BeginRead(new byte[5], 6, 0, null, null)); +#endif + } + + private async Task RunReadTestAsync(Func> callback, bool suppressExpectedCancellationTokenAsserts = false) + { + CancellationToken expectedCancellationToken = new CancellationTokenSource().Token; + MemoryStream sink = new(); + MemoryStream innerStream = new(); + + var delegatingInnerStreamMock = new Mock(MockBehavior.Strict); + delegatingInnerStreamMock.Setup(o => o.CanRead).Returns(true); + + // Needed for ReadByte calls. + delegatingInnerStreamMock.Setup(o => o.Read(It.IsAny(), It.IsAny(), It.IsAny())) + .Returns(innerStream.Read); + +#if true // In current src/ projects, always pass byte array to inner Stream. + if (suppressExpectedCancellationTokenAsserts) + { + delegatingInnerStreamMock.Setup(o => o.ReadAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .Returns(innerStream.ReadAsync); + } + else + { + delegatingInnerStreamMock.Setup(o => o.ReadAsync(It.IsAny(), It.IsAny(), It.IsAny(), expectedCancellationToken)) + .Returns(innerStream.ReadAsync); + } +#else + if (suppressExpectedCancellationTokenAsserts) + { + delegatingInnerStreamMock.Setup(o => o.ReadAsync(It.IsAny>(), It.IsAny())) + .Returns, CancellationToken>(innerStream.ReadAsync); + } + else + { + delegatingInnerStreamMock.Setup(o => o.ReadAsync(It.IsAny>(), expectedCancellationToken)) + .Returns, CancellationToken>(innerStream.ReadAsync); + } +#endif + + Stream transcodingStream = new TranscodingStream( + innerStream: delegatingInnerStreamMock.Object, + innerEncoding: Encoding.UTF8, + thisEncoding: CustomAsciiEncoding); + + // Test with a small string, then test with a large string + + await RunOneTestIteration(128); + await RunOneTestIteration(10 * 1024 * 1024); + + Assert.Equal(-1, transcodingStream.ReadByte()); // should've reached EOF + + // Now put some invalid data into the inner stream, followed by EOF, and ensure we get U+FFFD back out. + + innerStream.SetLength(0); // reset + innerStream.WriteByte(0xC0); // [ C0 ] is never valid in UTF-8 + innerStream.Position = 0; + + sink.SetLength(0); // reset + int numBytesReadJustNow; + do + { + numBytesReadJustNow = await callback(transcodingStream, expectedCancellationToken, sink); + Assert.True(numBytesReadJustNow >= 0); + } while (numBytesReadJustNow > 0); + + Assert.Equal("[FFFD]", ErrorCheckingAsciiEncoding.GetString(sink.ToArray())); + Assert.Equal(-1, transcodingStream.ReadByte()); // should've reached EOF + + // Now put some incomplete data into the inner stream, followed by EOF, and ensure we get U+FFFD back out. + + innerStream.SetLength(0); // reset + innerStream.WriteByte(0xC2); // [ C2 ] must be followed by [ 80..BF ] in UTF-8 + innerStream.Position = 0; + + sink.SetLength(0); // reset + do + { + numBytesReadJustNow = await callback(transcodingStream, expectedCancellationToken, sink); + Assert.True(numBytesReadJustNow >= 0); + } while (numBytesReadJustNow > 0); + + Assert.Equal("[FFFD]", ErrorCheckingAsciiEncoding.GetString(sink.ToArray())); + Assert.Equal(-1, transcodingStream.ReadByte()); // should've reached EOF + + async Task RunOneTestIteration(int stringLength) + { + sink.SetLength(0); // reset + + string expectedStringContents = GetVeryLongAsciiString(stringLength); + innerStream.SetLength(0); // reset + var bytes = Encoding.UTF8.GetBytes(expectedStringContents); + innerStream.Write(bytes, 0, bytes.Length); + innerStream.Position = 0; + + int numBytesReadJustNow; + do + { + numBytesReadJustNow = await callback(transcodingStream, expectedCancellationToken, sink); + Assert.True(numBytesReadJustNow >= 0); + } while (numBytesReadJustNow > 0); + + Assert.Equal(expectedStringContents, ErrorCheckingAsciiEncoding.GetString(sink.ToArray())); + } + } + + [Fact] + public void ReadTimeout_WriteTimeout_NotSupported() + { + // Arrange - allow inner stream to support ReadTimeout + WriteTimeout + + var innerStreamMock = new Mock(); + innerStreamMock.SetupProperty(o => o.ReadTimeout); + innerStreamMock.SetupProperty(o => o.WriteTimeout); + Stream transcodingStream = new TranscodingStream(Stream.Null, Encoding.UTF8, Encoding.UTF8, leaveOpen: true); + + // Act & assert - TranscodingStream shouldn't support ReadTimeout + WriteTimeout + + Assert.False(transcodingStream.CanTimeout); + Assert.Throws(() => transcodingStream.ReadTimeout); + Assert.Throws(() => transcodingStream.ReadTimeout = 42); + Assert.Throws(() => transcodingStream.WriteTimeout); + Assert.Throws(() => transcodingStream.WriteTimeout = 42); + } + + [Fact] + public void Seek_AlwaysThrows() + { + // MemoryStream is seekable, but we're not + Stream transcodingStream = new TranscodingStream(new MemoryStream(), Encoding.UTF8, Encoding.UTF8); + + Assert.False(transcodingStream.CanSeek); + Assert.Throws(() => transcodingStream.Length); + Assert.Throws(() => transcodingStream.Position); + Assert.Throws(() => transcodingStream.Position = 0); + Assert.Throws(() => transcodingStream.Seek(0, SeekOrigin.Current)); + Assert.Throws(() => transcodingStream.SetLength(0)); + } + + [Fact] + public void Write() + { + MemoryStream innerStream = new(); + Stream transcodingStream = new TranscodingStream( + innerStream, + innerEncoding: ErrorCheckingUnicodeEncoding /* throws on error */, + thisEncoding: Encoding.UTF8 /* performs substitution */, + leaveOpen: true); + + // First, test Write(byte[], int, int) + + transcodingStream.Write(Encoding.UTF8.GetBytes("abcdefg"), 2, 3); + Assert.Equal("cde", ErrorCheckingUnicodeEncoding.GetString(innerStream.ToArray())); + + // Then test WriteByte(byte) + + transcodingStream.WriteByte((byte)'z'); + Assert.Equal("cdez", ErrorCheckingUnicodeEncoding.GetString(innerStream.ToArray())); + + // We'll write U+00E0 (utf-8: [C3 A0]) byte-by-byte. + // We shouldn't flush any intermediate bytes. + + transcodingStream.WriteByte((byte)0xC3); + Assert.Equal("cdez", ErrorCheckingUnicodeEncoding.GetString(innerStream.ToArray())); + + transcodingStream.WriteByte((byte)0xA0); + Assert.Equal("cdez\u00E0", ErrorCheckingUnicodeEncoding.GetString(innerStream.ToArray())); + + innerStream.SetLength(0); // reset inner stream + + // Then test Write(ROS), once with a short string and once with a long string + + string asciiString = GetVeryLongAsciiString(128); + byte[] asciiBytesAsUtf8 = Encoding.UTF8.GetBytes(asciiString); + transcodingStream.Write(asciiBytesAsUtf8, 0, asciiBytesAsUtf8.Length); + Assert.Equal(asciiString, ErrorCheckingUnicodeEncoding.GetString(innerStream.ToArray())); + + innerStream.SetLength(0); // reset inner stream + + asciiString = GetVeryLongAsciiString(16 * 1024 * 1024); + asciiBytesAsUtf8 = Encoding.UTF8.GetBytes(asciiString); + transcodingStream.Write(asciiBytesAsUtf8, 0, asciiBytesAsUtf8.Length); + Assert.Equal(asciiString, ErrorCheckingUnicodeEncoding.GetString(innerStream.ToArray())); + + innerStream.SetLength(0); // reset inner stream + + // Close the outer stream and ensure no leftover data was written to the inner stream + + transcodingStream.Close(); + Assert.Equal(0, innerStream.Position); + } + + [Fact] + public void Write_WithPartialData() + { + MemoryStream innerStream = new(); + Stream transcodingStream = new TranscodingStream( + innerStream, + innerEncoding: CustomAsciiEncoding /* performs custom substitution */, + thisEncoding: Encoding.UTF8 /* performs U+FFFD substitution */, + leaveOpen: true); + + // First, write some incomplete data + + transcodingStream.Write(new byte[] { 0x78, 0x79, 0x7A, 0xC3 }, 0, 4); // [C3] shouldn't be flushed yet + Assert.Equal("xyz", ErrorCheckingAsciiEncoding.GetString(innerStream.ToArray())); + + // Flushing should have no effect + + transcodingStream.Flush(); + Assert.Equal("xyz", ErrorCheckingAsciiEncoding.GetString(innerStream.ToArray())); + + // Provide the second byte of the multi-byte sequence + + transcodingStream.WriteByte(0xA0); // [C3 A0] = U+00E0 + Assert.Equal("xyz[00E0]", ErrorCheckingAsciiEncoding.GetString(innerStream.ToArray())); + + // Provide an incomplete sequence, then close the stream. + // Closing the stream should flush the underlying buffers and write the replacement char. + + transcodingStream.Write(new byte[] { 0xE0, 0xBF }, 0, 1); // first 2 bytes of incomplete 3-byte sequence + Assert.Equal("xyz[00E0]", ErrorCheckingAsciiEncoding.GetString(innerStream.ToArray())); // wasn't flushed yet + + transcodingStream.Close(); + Assert.Equal("xyz[00E0][FFFD]", ErrorCheckingAsciiEncoding.GetString(innerStream.ToArray())); + } + + [Fact] + public void Write_WithInvalidArgs_Throws() + { + Stream transcodingStream = new TranscodingStream(new MemoryStream(), Encoding.UTF8, Encoding.UTF8); + + Assert.ThrowsArgumentNull(() => transcodingStream.Write(null, 0, 0), "buffer"); + Assert.Throws(() => transcodingStream.Write(new byte[5], -1, -1)); + Assert.Throws(() => transcodingStream.Write(new byte[5], 3, -1)); + Assert.Throws(() => transcodingStream.Write(new byte[5], 5, 1)); + Assert.Throws(() => transcodingStream.Write(new byte[5], 6, -1)); + Assert.Throws(() => transcodingStream.Write(new byte[5], 6, 0)); + } + + // Moq heavily utilizes RefEmit, which does not work on most aot workloads + [Fact] + public async Task WriteAsync_WithFullData() + { + MemoryStream sink = new(); + CancellationToken expectedFlushAsyncCancellationToken = new CancellationTokenSource().Token; + CancellationToken expectedWriteAsyncCancellationToken = new CancellationTokenSource().Token; + + var innerStreamMock = new Mock(MockBehavior.Strict); + innerStreamMock.Setup(o => o.CanWrite).Returns(true); +#if true // In current src/ projects, always pass byte array to inner Stream. + innerStreamMock.Setup(o => o.WriteAsync(It.IsAny(), It.IsAny(), It.IsAny(), expectedWriteAsyncCancellationToken)) + .Returns(sink.WriteAsync); +#else + innerStreamMock.Setup(o => o.WriteAsync(It.IsAny>(), expectedWriteAsyncCancellationToken)) + .Returns, CancellationToken>(sink.WriteAsync); +#endif + innerStreamMock.Setup(o => o.FlushAsync(expectedFlushAsyncCancellationToken)).Returns(TaskHelpers.Completed()); + + Stream transcodingStream = new TranscodingStream( + innerStreamMock.Object, + innerEncoding: ErrorCheckingUnicodeEncoding, + thisEncoding: Encoding.UTF8 /* performs U+FFFD substitution */, + leaveOpen: true); + + // First, test WriteAsync(byte[], int, int, CancellationToken) + + await transcodingStream.WriteAsync(Encoding.UTF8.GetBytes("abcdefg"), 2, 3, expectedWriteAsyncCancellationToken); + Assert.Equal("cde", ErrorCheckingUnicodeEncoding.GetString(sink.ToArray())); + + // We'll write U+00E0 (utf-8: [C3 A0]) byte-by-byte. + // We shouldn't flush any intermediate bytes. + + await transcodingStream.WriteAsync(new byte[] { 0xC3, 0xA0 }, 0, 1, expectedWriteAsyncCancellationToken); + await transcodingStream.FlushAsync(expectedFlushAsyncCancellationToken); + Assert.Equal("cde", ErrorCheckingUnicodeEncoding.GetString(sink.ToArray())); + + await transcodingStream.WriteAsync(new byte[] { 0xC3, 0xA0 }, 1, 1, expectedWriteAsyncCancellationToken); + Assert.Equal("cde\u00E0", ErrorCheckingUnicodeEncoding.GetString(sink.ToArray())); + + sink.SetLength(0); // reset sink + + // Then test WriteAsync(ROM, CancellationToken), once with a short string and once with a long string + + string asciiString = GetVeryLongAsciiString(128); + byte[] asciiBytesAsUtf8 = Encoding.UTF8.GetBytes(asciiString); + await transcodingStream.WriteAsync(asciiBytesAsUtf8, 0, asciiBytesAsUtf8.Length, expectedWriteAsyncCancellationToken); + Assert.Equal(asciiString, ErrorCheckingUnicodeEncoding.GetString(sink.ToArray())); + + sink.SetLength(0); // reset sink + + asciiString = GetVeryLongAsciiString(16 * 1024 * 1024); + asciiBytesAsUtf8 = Encoding.UTF8.GetBytes(asciiString); + await transcodingStream.WriteAsync(asciiBytesAsUtf8, 0, asciiBytesAsUtf8.Length, expectedWriteAsyncCancellationToken); + Assert.Equal(asciiString, ErrorCheckingUnicodeEncoding.GetString(sink.ToArray())); + + sink.SetLength(0); // reset sink + + // Close the outer stream and ensure no leftover data was written to the inner stream + + transcodingStream.Dispose(); + Assert.Equal(0, sink.Position); + } + + // Moq heavily utilizes RefEmit, which does not work on most aot workloads + [Fact] + public async Task WriteAsync_WithPartialData() + { + MemoryStream sink = new(); + CancellationToken expectedCancellationToken = new CancellationTokenSource().Token; + + var innerStreamMock = new Mock(MockBehavior.Strict); + innerStreamMock.Setup(o => o.CanWrite).Returns(true); +#if true // In current src/ projects, always pass byte array to inner Stream. + innerStreamMock.Setup(o => o.WriteAsync(It.IsAny(), It.IsAny(), It.IsAny(), expectedCancellationToken)) + .Returns(sink.WriteAsync); +#else + innerStreamMock.Setup(o => o.WriteAsync(It.IsAny>(), expectedCancellationToken)) + .Returns, CancellationToken>(sink.WriteAsync); +#endif + + Stream transcodingStream = new TranscodingStream( + innerStreamMock.Object, + innerEncoding: CustomAsciiEncoding /* performs custom substitution */, + thisEncoding: Encoding.UTF8 /* performs U+FFFD substitution */, + leaveOpen: true); + + // First, write some incomplete data + + await transcodingStream.WriteAsync(new byte[] { 0x78, 0x79, 0x7A, 0xC3 }, 0, 4, expectedCancellationToken); // [C3] shouldn't be flushed yet + Assert.Equal("xyz", ErrorCheckingAsciiEncoding.GetString(sink.ToArray())); + + // Provide the second byte of the multi-byte sequence + + await transcodingStream.WriteAsync(new byte[] { 0xA0 }, 0, 1, expectedCancellationToken); // [C3 A0] = U+00E0 + Assert.Equal("xyz[00E0]", ErrorCheckingAsciiEncoding.GetString(sink.ToArray())); + + // Provide an incomplete sequence, then close the stream. + // Closing the stream should flush the underlying buffers and write the replacement char. + + await transcodingStream.WriteAsync(new byte[] { 0xE0, 0xBF }, 0, 2, expectedCancellationToken); // first 2 bytes of incomplete 3-byte sequence + Assert.Equal("xyz[00E0]", ErrorCheckingAsciiEncoding.GetString(sink.ToArray())); // wasn't flushed yet + + // The call to Dispose() will call innerStream.Write. + + innerStreamMock.Setup(o => o.Write(It.IsAny(), It.IsAny(), It.IsAny())) + .Callback(sink.Write); + transcodingStream.Dispose(); + Assert.Equal("xyz[00E0][FFFD]", ErrorCheckingAsciiEncoding.GetString(sink.ToArray())); + } + + [Fact] + public void WriteAsync_WithInvalidArgs_Throws() + { + Stream transcodingStream = new TranscodingStream(new MemoryStream(), Encoding.UTF8, Encoding.UTF8); + + Assert.ThrowsArgumentNull(() => { transcodingStream.WriteAsync(null, 0, 0); }, "buffer"); + Assert.Throws(() => (object)transcodingStream.WriteAsync(new byte[5], -1, -1)); + Assert.Throws(() => (object)transcodingStream.WriteAsync(new byte[5], 3, -1)); + Assert.Throws(() => (object)transcodingStream.WriteAsync(new byte[5], 5, 1)); + Assert.Throws(() => (object)transcodingStream.WriteAsync(new byte[5], 6, -1)); + Assert.Throws(() => (object)transcodingStream.WriteAsync(new byte[5], 6, 0)); + } + + // Moq heavily utilizes RefEmit, which does not work on most aot workloads + [Fact] + public void WriteApm() + { + // Arrange + + MemoryStream sink = new(); + object expectedState = new(); + + var innerStreamMock = new Mock(MockBehavior.Strict); + innerStreamMock.Setup(o => o.CanWrite).Returns(true); +#if true // In current src/ projects, base Stream's BeginWrite method relies on Write and passes the byte array to the inner stream. + innerStreamMock.Setup(o => o.Write(It.IsAny(), It.IsAny(), It.IsAny())) + .Callback(sink.Write); +#else + innerStreamMock.Setup(o => o.WriteAsync(It.IsAny>(), CancellationToken.None)) + .Returns, CancellationToken>(sink.WriteAsync); +#endif + + Stream transcodingStream = new TranscodingStream(innerStreamMock.Object, Encoding.UTF8, Encoding.UTF8); + + // Act + + IAsyncResult asyncResult = transcodingStream.BeginWrite(Encoding.UTF8.GetBytes("abcdefg"), 1, 3, null, expectedState); + transcodingStream.EndWrite(asyncResult); + + // Assert + + Assert.Equal(expectedState, asyncResult.AsyncState); + Assert.Equal("bcd", Encoding.UTF8.GetString(sink.ToArray())); + } + + [Fact] + public void WriteApm_WithInvalidArgs_Throws() + { + Stream transcodingStream = new TranscodingStream(new MemoryStream(), Encoding.UTF8, Encoding.UTF8); + +#if true // Not overriding BeginRead and base Stream's method returns a Task as its IAsyncResult, delaying parameter checks. + Assert.ThrowsArgumentNull(() => transcodingStream.EndWrite(transcodingStream.BeginWrite(null, 0, 0, null, null)), "buffer"); + Assert.Throws(() => transcodingStream.EndWrite(transcodingStream.BeginWrite(new byte[5], -1, -1, null, null))); + Assert.Throws(() => transcodingStream.EndWrite(transcodingStream.BeginWrite(new byte[5], 3, -1, null, null))); + Assert.Throws(() => transcodingStream.EndWrite(transcodingStream.BeginWrite(new byte[5], 5, 1, null, null))); + Assert.Throws(() => transcodingStream.EndWrite(transcodingStream.BeginWrite(new byte[5], 6, -1, null, null))); + Assert.Throws(() => transcodingStream.EndWrite(transcodingStream.BeginWrite(new byte[5], 6, 0, null, null))); +#else + Assert.ThrowsArgumentNull(() => transcodingStream.BeginWrite(null, 0, 0, null, null), "buffer"); + Assert.Throws(() => transcodingStream.BeginWrite(new byte[5], -1, -1, null, null)); + Assert.Throws(() => transcodingStream.BeginWrite(new byte[5], 3, -1, null, null)); + Assert.Throws(() => transcodingStream.BeginWrite(new byte[5], 5, 1, null, null)); + Assert.Throws(() => transcodingStream.BeginWrite(new byte[5], 6, -1, null, null)); + Assert.Throws(() => transcodingStream.BeginWrite(new byte[5], 6, 0, null, null)); +#endif + } + + // returns "abc...xyzabc...xyzabc..." + private static string GetVeryLongAsciiString(int length) + { +#if NETCOREAPP || NETSTANDARD2_1 + return string.Create(length, (object)null, (buffer, _) => + { + for (int i = 0; i < buffer.Length; i++) + { + buffer[i] = (char)('a' + (i % 26)); + } + }); +#else + // Somewhat minor that the string just repeats a single character. + return new string('z', length); +#endif + } + + // A custom ASCIIEncoding where both encoder + decoder fallbacks have been specified + private static readonly Encoding CustomAsciiEncoding = Encoding.GetEncoding( + "ascii", new CustomEncoderFallback(), new DecoderReplacementFallback("\uFFFD")); + + private static readonly Encoding ErrorCheckingAsciiEncoding + = Encoding.GetEncoding("ascii", EncoderFallback.ExceptionFallback, DecoderFallback.ExceptionFallback); + + private static readonly UnicodeEncoding ErrorCheckingUnicodeEncoding + = new(bigEndian: false, byteOrderMark: false, throwOnInvalidBytes: true); + + // A custom encoder fallback which substitutes unknown chars with "[xxxx]" (the code point as hex) + private sealed class CustomEncoderFallback : EncoderFallback + { + public override int MaxCharCount => 8; // = "[10FFFF]".Length + + public override EncoderFallbackBuffer CreateFallbackBuffer() + { + return new CustomEncoderFallbackBuffer(); + } + + private sealed class CustomEncoderFallbackBuffer : EncoderFallbackBuffer + { + private string _remaining = string.Empty; + private int _remainingIdx = 0; + + public override int Remaining => _remaining.Length - _remainingIdx; + + public override bool Fallback(char charUnknownHigh, char charUnknownLow, int index) + => FallbackCommon((uint)char.ConvertToUtf32(charUnknownHigh, charUnknownLow)); + + public override bool Fallback(char charUnknown, int index) + => FallbackCommon(charUnknown); + + private bool FallbackCommon(uint codePoint) + { + Assert.True(codePoint <= 0x10FFFF); + _remaining = String.Format(CultureInfo.InvariantCulture, "[{0:X4}]", codePoint); + _remainingIdx = 0; + return true; + } + + public override char GetNextChar() + { + return (_remainingIdx < _remaining.Length) + ? _remaining[_remainingIdx++] + : '\0' /* end of string reached */; + } + + public override bool MovePrevious() + { + if (_remainingIdx == 0) + { + return false; + } + + _remainingIdx--; + return true; + } + } + } + + /// A custom encoding that's used to roundtrip from bytes to bytes through a string. + private sealed class IdentityEncoding : Encoding + { + public override int GetByteCount(char[] chars, int index, int count) => count; + + public override int GetBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex) + { + Span span = chars.AsSpan(charIndex, charCount); + for (int i = 0; i < span.Length; i++) + { + Debug.Assert(span[i] <= 0xFF); + bytes[byteIndex + i] = (byte)span[i]; + } + return charCount; + } + + public override int GetCharCount(byte[] bytes, int index, int count) => count; + + public override int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex) + { + Span span = bytes.AsSpan(byteIndex, byteCount); + for (int i = 0; i < span.Length; i++) + { + Debug.Assert(span[i] <= 0xFF); + chars[charIndex + i] = (char)span[i]; + } + return byteCount; + } + + public override int GetMaxByteCount(int charCount) => charCount; + + public override int GetMaxCharCount(int byteCount) => byteCount; + + public override byte[] GetPreamble() => TranscodingStream.EmptyByteBuffer; + } + + // A helper type that allows synchronously writing to a stream while asynchronously + // reading from it. + private sealed class AsyncComms : IDisposable + { + private readonly BlockingCollection _blockingCollection; + private readonly PipeWriter _writer; + + public AsyncComms() + { + _blockingCollection = new BlockingCollection(); + var pipe = new Pipe(); + ReadStream = pipe.Reader.AsStream(); + _writer = pipe.Writer; + Task.Run(DrainWorker); + } + + public Stream ReadStream { get; } + + public void Dispose() + { + _blockingCollection.Dispose(); + } + + public void WriteBytes(ReadOnlySpan bytes) + { + _blockingCollection.Add(bytes.ToArray()); + } + + public void WriteEof() + { + _blockingCollection.Add(null); + } + + private async Task DrainWorker() + { + byte[] buffer; + while ((buffer = _blockingCollection.Take()) is not null) + { + await _writer.WriteAsync(buffer); + } + _writer.Complete(); + } + } + } +} diff --git a/test/System.Net.Http.Formatting.Test/Mocks/MockDelegatingHandler.cs b/test/System.Net.Http.Formatting.Test/Mocks/MockDelegatingHandler.cs index 2a617479e..013287eda 100644 --- a/test/System.Net.Http.Formatting.Test/Mocks/MockDelegatingHandler.cs +++ b/test/System.Net.Http.Formatting.Test/Mocks/MockDelegatingHandler.cs @@ -40,11 +40,7 @@ protected override Task SendAsync(HttpRequestMessage reques SendAsyncException = new Exception("SendAsync exception"); throw SendAsyncException; } -#if !NETFX_CORE // Extension method only available on non portable library return Task.FromResult(request.CreateResponse()); -#else - return Task.FromResult(new HttpResponseMessage { RequestMessage = request }); -#endif } } } diff --git a/test/System.Net.Http.Formatting.Test/System.Net.Http.Formatting.Test.csproj b/test/System.Net.Http.Formatting.Test/System.Net.Http.Formatting.Test.csproj index caec66151..bef6e4406 100644 --- a/test/System.Net.Http.Formatting.Test/System.Net.Http.Formatting.Test.csproj +++ b/test/System.Net.Http.Formatting.Test/System.Net.Http.Formatting.Test.csproj @@ -12,8 +12,44 @@ ..\..\bin\$(Configuration)\Test\ + true + + + + ..\..\packages\System.Buffers.4.5.1\lib\netstandard2.0\System.Buffers.dll + False + False + + + + + ..\..\packages\System.IO.Pipelines.4.7.5\lib\netstandard2.0\System.IO.Pipelines.dll + False + True + + + ..\..\packages\System.Memory.4.5.5\lib\netstandard2.0\System.Memory.dll + False + True + + + + + ..\..\packages\System.Runtime.CompilerServices.Unsafe.4.7.1\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll + False + True + + + + ..\..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\portable-net45+win8+wp8+wpa81\System.Threading.Tasks.Extensions.dll + False + True + + + + ..\..\packages\Castle.Core.4.2.1\lib\net45\Castle.Core.dll True @@ -22,6 +58,10 @@ ..\..\packages\Moq.4.7.142\lib\net45\Moq.dll True + + False + False + ..\..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll True @@ -30,14 +70,6 @@ ..\..\packages\Newtonsoft.Json.Bson.1.0.2\lib\net45\Newtonsoft.Json.Bson.dll True - - - - - - - - ..\..\packages\xunit.abstractions.2.0.1\lib\net35\xunit.abstractions.dll True @@ -54,123 +86,13 @@ ..\..\packages\xunit.extensibility.execution.2.3.0\lib\net452\xunit.execution.desktop.dll True - - + False - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + {668E9021-CE84-49D9-98FB-DF125A9FCDB0} System.Net.Http.Formatting @@ -179,26 +101,28 @@ {FCCC4CB7-BAF7-4A57-9F89-E5766FE536C0} Microsoft.TestCommon - - + Designer - - + - - + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - + + + - \ No newline at end of file diff --git a/test/System.Net.Http.Formatting.Test/packages.config b/test/System.Net.Http.Formatting.Test/packages.config index 7025597c7..7d7c7a6e3 100644 --- a/test/System.Net.Http.Formatting.Test/packages.config +++ b/test/System.Net.Http.Formatting.Test/packages.config @@ -2,8 +2,14 @@ + + + + + + diff --git a/tools/WebStack.settings.targets b/tools/WebStack.settings.targets index f24c1ce7f..f8f062c6b 100644 --- a/tools/WebStack.settings.targets +++ b/tools/WebStack.settings.targets @@ -36,8 +36,8 @@ false false - - 5 + + 9.0 true From 169d95fc063feb401736e85aab1aa26518e78a92 Mon Sep 17 00:00:00 2001 From: Doug Bunting <6431421+dougbu@users.noreply.github.com> Date: Mon, 30 Jan 2023 20:52:17 -0800 Subject: [PATCH 35/54] Bump test project dependencies (#383) Bump test project dependencies - Castle.Core, Moq, and xUnit versions were all out of date - hold xunit.runner.visualstudio version back in .NET SDK test projects - can be moved to latest version after we stop testing on netcoreapp2.1 - add missing xunit.analyzers reference to System.Web.Razor.Test project - move all test projects to .NET v4.6.2 (a supported framework) - remove `netstandard` reference in System.Net.Http.Formatting.Test; not needed w/ new TFM & updated references - further separate build of Microsoft.TestCommon project when invoked from NetCore.Test project - special case `RestorePackages` for this case - add System.Net.Http references to avoid conflicting versions e.g. src/ and test/ TFMs differ React to changed xUnit APIs - adjust Microsoft.TestCommon code - nit: use `Array.Empty()` in `TranscodingStreamTests` - `TranscodingStream` `internal`s can be `private` instead Resolve xUnit issues new analyzers find - address xUnit2000 warnings - pass expected values to `Assert.Equal(...)` as correct (left) argument - make generic method types explicit to avoid `error CS0121: The call is ambiguous between the following methods or properties: ...` - note: cannot remove unnecessary xUnit1013 suppression - related bug (xunit/xunit#1466) apparently not fixed in 1.0.0 analyzers package - was xunit/xunit.analyzers#82 fix (in 2017) insufficient? React to new Moq changes - avoid `ProtectedMock\`1.ThrowIfPublicMethod(...)` `throw`ing - use new overloads introduced in the Moq 4.11.0 release - adjust to Moq hiding the `ObjectProxy` type better - update `ControllerContext` mocking to avoid NREs - setting `HttpContext.User` on the `Object` left `get` value `null` (did nothing) - nit: use `SetupGet(...)` for another property --- .nuget/packages.config | 2 +- Runtime.msbuild | 8 ++- .../Internal/TranscodingStream.cs | 4 +- test/Directory.Build.props | 2 +- test/Directory.Build.targets | 2 +- .../Microsoft.AspNet.Facebook.Test.csproj | 36 +++++------ .../packages.config | 24 ++++---- .../Directory.Build.props | 9 +++ test/Microsoft.TestCommon/FactDiscoverer.cs | 1 + .../Microsoft.TestCommon.csproj | 19 +++--- .../SkippedXunitTestCase.cs | 3 +- test/Microsoft.TestCommon/TheoryDiscoverer.cs | 1 + .../Microsoft.Web.Helpers.Test.csproj | 36 +++++------ .../packages.config | 20 +++---- .../Microsoft.Web.Mvc.Test.csproj | 36 +++++------ test/Microsoft.Web.Mvc.Test/packages.config | 22 +++---- .../Microsoft.Web.WebPages.OAuth.Test.csproj | 38 ++++++------ .../packages.config | 32 +++++----- ...em.Net.Http.Formatting.NetCore.Test.csproj | 17 ++++-- ...et.Http.Formatting.NetStandard.Test.csproj | 12 ++-- .../Internal/DelegatingStreamTest.cs | 4 +- .../NonClosingDelegatingStreamTest.cs | 4 +- .../Internal/TranscodingStreamTests.cs | 6 +- .../PushStreamContentTest.cs | 6 +- .../System.Net.Http.Formatting.Test.csproj | 60 +++++++++---------- .../packages.config | 35 ++++++----- .../System.Web.Cors.Test.csproj | 36 +++++------ test/System.Web.Cors.Test/packages.config | 20 +++---- .../System.Web.Helpers.Test.csproj | 36 +++++------ test/System.Web.Helpers.Test/packages.config | 20 +++---- .../System.Web.Http.Cors.Test.csproj | 36 +++++------ .../System.Web.Http.Cors.Test/packages.config | 22 +++---- .../System.Web.Http.Integration.Test.csproj | 36 +++++------ .../packages.config | 22 +++---- .../NonOwnedStreamTests.cs | 4 +- .../System.Web.Http.Owin.Test.csproj | 36 +++++------ .../System.Web.Http.Owin.Test/packages.config | 30 +++++----- .../System.Web.Http.SelfHost.Test.csproj | 36 +++++------ .../packages.config | 22 +++---- .../System.Web.Http.SignalR.Test.csproj | 36 +++++------ .../packages.config | 24 ++++---- .../DefaultHttpControllerActivatorTest.cs | 2 +- .../DirectRouteProviderContextTests.cs | 2 +- .../System.Web.Http.Test.csproj | 36 +++++------ test/System.Web.Http.Test/packages.config | 22 +++---- .../System.Web.Http.Tracing.Test.csproj | 28 ++++----- .../packages.config | 18 +++--- .../System.Web.Http.WebHost.Test.csproj | 36 +++++------ .../packages.config | 22 +++---- .../System.Web.Mvc.Test.csproj | 36 +++++------ .../Test/ControllerActionInvokerTest.cs | 3 +- .../Test/ControllerTest.cs | 2 +- test/System.Web.Mvc.Test/packages.config | 22 +++---- .../System.Web.Razor.Test.csproj | 35 +++++------ test/System.Web.Razor.Test/packages.config | 17 +++--- ...em.Web.WebPages.Administration.Test.csproj | 36 +++++------ .../packages.config | 22 +++---- ...System.Web.WebPages.Deployment.Test.csproj | 28 ++++----- .../packages.config | 16 ++--- .../System.Web.WebPages.Razor.Test.csproj | 36 +++++------ .../packages.config | 20 +++---- .../ApplicationParts/ApplicationPartTest.cs | 12 ++-- .../ApplicationParts/ResourceHandlerTest.cs | 2 +- .../System.Web.WebPages.Test.csproj | 36 +++++------ .../Validation/ValidationHelperTest.cs | 2 +- .../WebPage/PageDataDictionaryTest.cs | 8 +-- test/System.Web.WebPages.Test/packages.config | 20 +++---- .../WebApiHelpPage.Test.csproj | 36 +++++------ test/WebApiHelpPage.Test/packages.config | 24 ++++---- .../WebApiHelpPage.VB.Test.csproj | 36 +++++------ .../WebMatrix.Data.Test.csproj | 36 +++++------ test/WebMatrix.Data.Test/packages.config | 20 +++---- .../WebMatrix.WebData.Test.csproj | 36 +++++------ test/WebMatrix.WebData.Test/packages.config | 20 +++---- tools/WebStack.testing.targets | 2 +- 75 files changed, 808 insertions(+), 776 deletions(-) create mode 100644 test/Microsoft.TestCommon/Directory.Build.props diff --git a/.nuget/packages.config b/.nuget/packages.config index ed6c18bcb..a8fe9612a 100644 --- a/.nuget/packages.config +++ b/.nuget/packages.config @@ -3,5 +3,5 @@ - + \ No newline at end of file diff --git a/Runtime.msbuild b/Runtime.msbuild index d53e2e46d..ac847731a 100644 --- a/Runtime.msbuild +++ b/Runtime.msbuild @@ -65,8 +65,14 @@ + + <_ToRestore Include="@(SolutionsToBuild)" /> + <_ToRestore Include="test\Microsoft.TestCommon\Microsoft.TestCommon.csproj" + AdditionalProperties="NetFX_Core=true" + Condition=" '$(BuildPortable)' == 'true' " /> + - diff --git a/src/System.Net.Http.Formatting/Internal/TranscodingStream.cs b/src/System.Net.Http.Formatting/Internal/TranscodingStream.cs index 9f89eeee8..9d392d469 100644 --- a/src/System.Net.Http.Formatting/Internal/TranscodingStream.cs +++ b/src/System.Net.Http.Formatting/Internal/TranscodingStream.cs @@ -31,8 +31,8 @@ internal sealed class TranscodingStream : Stream private const int MinWriteRentedArraySize = 4 * 1024; private const int MaxWriteRentedArraySize = 1024 * 1024; - internal static readonly byte[] EmptyByteBuffer = new byte[0]; - internal static readonly char[] EmptyCharBuffer = new char[0]; + private static readonly byte[] EmptyByteBuffer = new byte[0]; + private static readonly char[] EmptyCharBuffer = new char[0]; private readonly Encoding _innerEncoding; private readonly Encoding _thisEncoding; diff --git a/test/Directory.Build.props b/test/Directory.Build.props index 64681b2ef..23c8b064c 100644 --- a/test/Directory.Build.props +++ b/test/Directory.Build.props @@ -7,6 +7,6 @@ v4.5.2 + '$(MSBuildProjectName)' != 'System.Net.Http.Formatting.NetStandard.Test' ">v4.6.2 diff --git a/test/Directory.Build.targets b/test/Directory.Build.targets index b1167ac05..99772c023 100644 --- a/test/Directory.Build.targets +++ b/test/Directory.Build.targets @@ -1,6 +1,6 @@ - diff --git a/test/Microsoft.AspNet.Facebook.Test/Microsoft.AspNet.Facebook.Test.csproj b/test/Microsoft.AspNet.Facebook.Test/Microsoft.AspNet.Facebook.Test.csproj index f9003b7dd..bedf43f90 100644 --- a/test/Microsoft.AspNet.Facebook.Test/Microsoft.AspNet.Facebook.Test.csproj +++ b/test/Microsoft.AspNet.Facebook.Test/Microsoft.AspNet.Facebook.Test.csproj @@ -1,7 +1,7 @@  - - + + {C3BEF382-C7C4-454D-B017-1EAC03E9A82C} @@ -14,16 +14,16 @@ - - ..\..\packages\Castle.Core.4.2.1\lib\net45\Castle.Core.dll + + ..\..\packages\Castle.Core.5.1.1\lib\net462\Castle.Core.dll True ..\..\packages\Facebook.6.4.2\lib\net45\Facebook.dll - - ..\..\packages\Moq.4.7.142\lib\net45\Moq.dll + + ..\..\packages\Moq.4.18.4\lib\net462\Moq.dll True @@ -36,19 +36,19 @@ - ..\..\packages\xunit.abstractions.2.0.1\lib\net35\xunit.abstractions.dll + ..\..\packages\xunit.abstractions.2.0.3\lib\net35\xunit.abstractions.dll True - - ..\..\packages\xunit.assert.2.3.0\lib\netstandard1.1\xunit.assert.dll + + ..\..\packages\xunit.assert.2.4.2\lib\netstandard1.1\xunit.assert.dll True - - ..\..\packages\xunit.extensibility.core.2.3.0\lib\netstandard1.1\xunit.core.dll + + ..\..\packages\xunit.extensibility.core.2.4.2\lib\net452\xunit.core.dll True - - ..\..\packages\xunit.extensibility.execution.2.3.0\lib\net452\xunit.execution.desktop.dll + + ..\..\packages\xunit.extensibility.execution.2.4.2\lib\net452\xunit.execution.desktop.dll True @@ -129,18 +129,18 @@ - + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - + + + - + + obj\NetCore\ + $(DefaultItemExcludes);obj\** + + diff --git a/test/Microsoft.TestCommon/FactDiscoverer.cs b/test/Microsoft.TestCommon/FactDiscoverer.cs index db913e188..4be650293 100644 --- a/test/Microsoft.TestCommon/FactDiscoverer.cs +++ b/test/Microsoft.TestCommon/FactDiscoverer.cs @@ -76,6 +76,7 @@ public override IEnumerable Discover( var testCase = new SkippedXunitTestCase( _diagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), + TestMethodDisplayOptions.None, skipReason, baseCase.TestMethod, baseCase.TestMethodArguments); diff --git a/test/Microsoft.TestCommon/Microsoft.TestCommon.csproj b/test/Microsoft.TestCommon/Microsoft.TestCommon.csproj index 4def411d9..65c984aff 100644 --- a/test/Microsoft.TestCommon/Microsoft.TestCommon.csproj +++ b/test/Microsoft.TestCommon/Microsoft.TestCommon.csproj @@ -1,7 +1,7 @@  - net452;net462;netcoreapp2.1 + net462;netcoreapp2.1 $(Configurations);CodeAnalysis $(DefineConstants);NETFX_CORE @@ -14,15 +14,20 @@ - + + + + - - - - - + + + + + diff --git a/test/Microsoft.TestCommon/SkippedXunitTestCase.cs b/test/Microsoft.TestCommon/SkippedXunitTestCase.cs index e055b1e67..b5d536d3a 100644 --- a/test/Microsoft.TestCommon/SkippedXunitTestCase.cs +++ b/test/Microsoft.TestCommon/SkippedXunitTestCase.cs @@ -29,10 +29,11 @@ public class SkippedXunitTestCase : XunitTestCase public SkippedXunitTestCase( IMessageSink diagnosticMessageSink, TestMethodDisplay defaultMethodDisplay, + TestMethodDisplayOptions defaultMethodDisplayOptions, String skipReason, ITestMethod testMethod, object[] testMethodArguments = null) - : base(diagnosticMessageSink, defaultMethodDisplay, testMethod, testMethodArguments) + : base(diagnosticMessageSink, defaultMethodDisplay, defaultMethodDisplayOptions, testMethod, testMethodArguments) { _skipReason = skipReason; } diff --git a/test/Microsoft.TestCommon/TheoryDiscoverer.cs b/test/Microsoft.TestCommon/TheoryDiscoverer.cs index 8ca4c834e..cf62536fe 100644 --- a/test/Microsoft.TestCommon/TheoryDiscoverer.cs +++ b/test/Microsoft.TestCommon/TheoryDiscoverer.cs @@ -77,6 +77,7 @@ public override IEnumerable Discover( var testCase = new SkippedXunitTestCase( _diagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), + TestMethodDisplayOptions.None, skipReason, baseCase.TestMethod, baseCase.TestMethodArguments); diff --git a/test/Microsoft.Web.Helpers.Test/Microsoft.Web.Helpers.Test.csproj b/test/Microsoft.Web.Helpers.Test/Microsoft.Web.Helpers.Test.csproj index ca98914c7..1fdbb5fc0 100644 --- a/test/Microsoft.Web.Helpers.Test/Microsoft.Web.Helpers.Test.csproj +++ b/test/Microsoft.Web.Helpers.Test/Microsoft.Web.Helpers.Test.csproj @@ -1,7 +1,7 @@  - - + + {2C653A66-8159-4A41-954F-A67915DFDA87} @@ -14,31 +14,31 @@ - - ..\..\packages\Castle.Core.4.2.1\lib\net45\Castle.Core.dll + + ..\..\packages\Castle.Core.5.1.1\lib\net462\Castle.Core.dll - - ..\..\packages\Moq.4.7.142\lib\net45\Moq.dll + + ..\..\packages\Moq.4.18.4\lib\net462\Moq.dll True - ..\..\packages\xunit.abstractions.2.0.1\lib\net35\xunit.abstractions.dll + ..\..\packages\xunit.abstractions.2.0.3\lib\net35\xunit.abstractions.dll True - - ..\..\packages\xunit.assert.2.3.0\lib\netstandard1.1\xunit.assert.dll + + ..\..\packages\xunit.assert.2.4.2\lib\netstandard1.1\xunit.assert.dll True - - ..\..\packages\xunit.extensibility.core.2.3.0\lib\netstandard1.1\xunit.core.dll + + ..\..\packages\xunit.extensibility.core.2.4.2\lib\net452\xunit.core.dll True - - ..\..\packages\xunit.extensibility.execution.2.3.0\lib\net452\xunit.execution.desktop.dll + + ..\..\packages\xunit.extensibility.execution.2.4.2\lib\net452\xunit.execution.desktop.dll True @@ -93,16 +93,16 @@ - + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - + + + - + \ No newline at end of file diff --git a/test/Microsoft.Web.Helpers.Test/packages.config b/test/Microsoft.Web.Helpers.Test/packages.config index b06fb5e7a..cafc6212c 100644 --- a/test/Microsoft.Web.Helpers.Test/packages.config +++ b/test/Microsoft.Web.Helpers.Test/packages.config @@ -1,13 +1,13 @@  - - - - - - - - - - + + + + + + + + + + \ No newline at end of file diff --git a/test/Microsoft.Web.Mvc.Test/Microsoft.Web.Mvc.Test.csproj b/test/Microsoft.Web.Mvc.Test/Microsoft.Web.Mvc.Test.csproj index 52fd9cf7a..23b4b28f3 100644 --- a/test/Microsoft.Web.Mvc.Test/Microsoft.Web.Mvc.Test.csproj +++ b/test/Microsoft.Web.Mvc.Test/Microsoft.Web.Mvc.Test.csproj @@ -1,7 +1,7 @@  - - + + {6C28DA70-60F1-4442-967F-591BF3962EC5} @@ -16,13 +16,13 @@ - - ..\..\packages\Castle.Core.4.2.1\lib\net45\Castle.Core.dll + + ..\..\packages\Castle.Core.5.1.1\lib\net462\Castle.Core.dll True - - ..\..\packages\Moq.4.7.142\lib\net45\Moq.dll + + ..\..\packages\Moq.4.18.4\lib\net462\Moq.dll True @@ -37,19 +37,19 @@ - ..\..\packages\xunit.abstractions.2.0.1\lib\net35\xunit.abstractions.dll + ..\..\packages\xunit.abstractions.2.0.3\lib\net35\xunit.abstractions.dll True - - ..\..\packages\xunit.assert.2.3.0\lib\netstandard1.1\xunit.assert.dll + + ..\..\packages\xunit.assert.2.4.2\lib\netstandard1.1\xunit.assert.dll True - - ..\..\packages\xunit.extensibility.core.2.3.0\lib\netstandard1.1\xunit.core.dll + + ..\..\packages\xunit.extensibility.core.2.4.2\lib\net452\xunit.core.dll True - - ..\..\packages\xunit.extensibility.execution.2.3.0\lib\net452\xunit.execution.desktop.dll + + ..\..\packages\xunit.extensibility.execution.2.4.2\lib\net452\xunit.execution.desktop.dll True @@ -159,16 +159,16 @@ - + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - + + + - + \ No newline at end of file diff --git a/test/Microsoft.Web.Mvc.Test/packages.config b/test/Microsoft.Web.Mvc.Test/packages.config index 6e4cf51b5..72e333be0 100644 --- a/test/Microsoft.Web.Mvc.Test/packages.config +++ b/test/Microsoft.Web.Mvc.Test/packages.config @@ -1,14 +1,14 @@  - - - - - - - - - - - + + + + + + + + + + + \ No newline at end of file diff --git a/test/Microsoft.Web.WebPages.OAuth.Test/Microsoft.Web.WebPages.OAuth.Test.csproj b/test/Microsoft.Web.WebPages.OAuth.Test/Microsoft.Web.WebPages.OAuth.Test.csproj index 3d56fbe66..5985200ea 100644 --- a/test/Microsoft.Web.WebPages.OAuth.Test/Microsoft.Web.WebPages.OAuth.Test.csproj +++ b/test/Microsoft.Web.WebPages.OAuth.Test/Microsoft.Web.WebPages.OAuth.Test.csproj @@ -1,7 +1,7 @@  - - + + {694C6EDF-EA52-438F-B745-82B025ECC0E7} @@ -14,8 +14,8 @@ - - ..\..\packages\Castle.Core.4.2.1\lib\net45\Castle.Core.dll + + ..\..\packages\Castle.Core.5.1.1\lib\net462\Castle.Core.dll True @@ -42,8 +42,8 @@ False ..\..\packages\DotNetOpenAuth.OpenId.RelyingParty.4.0.3.12153\lib\net40-full\DotNetOpenAuth.OpenId.RelyingParty.dll - - ..\..\packages\Moq.4.7.142\lib\net45\Moq.dll + + ..\..\packages\Moq.4.18.4\lib\net462\Moq.dll True @@ -51,19 +51,19 @@ - ..\..\packages\xunit.abstractions.2.0.1\lib\net35\xunit.abstractions.dll + ..\..\packages\xunit.abstractions.2.0.3\lib\net35\xunit.abstractions.dll True - - ..\..\packages\xunit.assert.2.3.0\lib\netstandard1.1\xunit.assert.dll + + ..\..\packages\xunit.assert.2.4.2\lib\netstandard1.1\xunit.assert.dll True - - ..\..\packages\xunit.extensibility.core.2.3.0\lib\netstandard1.1\xunit.core.dll + + ..\..\packages\xunit.extensibility.core.2.4.2\lib\net452\xunit.core.dll True - - ..\..\packages\xunit.extensibility.execution.2.3.0\lib\net452\xunit.execution.desktop.dll + + ..\..\packages\xunit.extensibility.execution.2.4.2\lib\net452\xunit.execution.desktop.dll True @@ -90,19 +90,19 @@ - + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - + + + - - + <_VSRunnerVersion Condition=" '$(TargetFramework)' == 'netcoreapp2.1' ">2.4.3 + <_VSRunnerVersion Condition=" '$(TargetFramework)' != 'netcoreapp2.1' ">2.4.5 - - - - - + + + + + + + all runtime; build; native; contentfiles; analyzers diff --git a/test/System.Net.Http.Formatting.NetStandard.Test/System.Net.Http.Formatting.NetStandard.Test.csproj b/test/System.Net.Http.Formatting.NetStandard.Test/System.Net.Http.Formatting.NetStandard.Test.csproj index 6d6405cb6..bdcc1288d 100644 --- a/test/System.Net.Http.Formatting.NetStandard.Test/System.Net.Http.Formatting.NetStandard.Test.csproj +++ b/test/System.Net.Http.Formatting.NetStandard.Test/System.Net.Http.Formatting.NetStandard.Test.csproj @@ -9,16 +9,20 @@ $(DefineConstants);Testing_NetStandard2_0 true true + + + <_VSRunnerVersion Condition=" '$(TargetFramework)' == 'netcoreapp2.1' ">2.4.3 + <_VSRunnerVersion Condition=" '$(TargetFramework)' != 'netcoreapp2.1' ">2.4.5 - - - - + + + + all runtime; build; native; contentfiles; analyzers diff --git a/test/System.Net.Http.Formatting.Test/Internal/DelegatingStreamTest.cs b/test/System.Net.Http.Formatting.Test/Internal/DelegatingStreamTest.cs index 70d419804..8f24a05d3 100644 --- a/test/System.Net.Http.Formatting.Test/Internal/DelegatingStreamTest.cs +++ b/test/System.Net.Http.Formatting.Test/Internal/DelegatingStreamTest.cs @@ -141,7 +141,7 @@ public void DelegatingStream_Dispose() mockStream.Dispose(); // Assert - mockInnerStream.Protected().Verify("Dispose", Times.Once(), true); + mockInnerStream.Protected().Verify("Dispose", Times.Once(), exactParameterMatch: true, args: true); mockInnerStream.Verify(s => s.Close(), Times.Once()); } @@ -156,7 +156,7 @@ public void DelegatingStream_Close() mockStream.Close(); // Assert - mockInnerStream.Protected().Verify("Dispose", Times.Once(), true); + mockInnerStream.Protected().Verify("Dispose", Times.Once(), exactParameterMatch: true, args: true); mockInnerStream.Verify(s => s.Close(), Times.Once()); } diff --git a/test/System.Net.Http.Formatting.Test/Internal/NonClosingDelegatingStreamTest.cs b/test/System.Net.Http.Formatting.Test/Internal/NonClosingDelegatingStreamTest.cs index fa73637b9..838dc8634 100644 --- a/test/System.Net.Http.Formatting.Test/Internal/NonClosingDelegatingStreamTest.cs +++ b/test/System.Net.Http.Formatting.Test/Internal/NonClosingDelegatingStreamTest.cs @@ -22,7 +22,7 @@ public void NonClosingDelegatingStream_Dispose() mockStream.Dispose(); // Assert - mockInnerStream.Protected().Verify("Dispose", Times.Never(), true); + mockInnerStream.Protected().Verify("Dispose", Times.Never(), exactParameterMatch: true, args: true); mockInnerStream.Verify(s => s.Close(), Times.Never()); } @@ -37,7 +37,7 @@ public void NonClosingDelegatingStream_Close() mockStream.Close(); // Assert - mockInnerStream.Protected().Verify("Dispose", Times.Never(), true); + mockInnerStream.Protected().Verify("Dispose", Times.Never(), exactParameterMatch: true, args: true); mockInnerStream.Verify(s => s.Close(), Times.Never()); } } diff --git a/test/System.Net.Http.Formatting.Test/Internal/TranscodingStreamTests.cs b/test/System.Net.Http.Formatting.Test/Internal/TranscodingStreamTests.cs index 8f9a43b88..7d6e0a506 100644 --- a/test/System.Net.Http.Formatting.Test/Internal/TranscodingStreamTests.cs +++ b/test/System.Net.Http.Formatting.Test/Internal/TranscodingStreamTests.cs @@ -170,7 +170,7 @@ public void Dispose_WithLeaveOpenFalse_DisposesInnerStream() Stream transcodingStream = new TranscodingStream(innerStream, Encoding.UTF8, Encoding.UTF8, leaveOpen: false); transcodingStream.Dispose(); transcodingStream.Dispose(); // calling it a second time should no-op - Assert.Throws(() => innerStream.Read(TranscodingStream.EmptyByteBuffer, 0, 0)); + Assert.Throws(() => innerStream.Read(Array.Empty(), 0, 0)); // Async @@ -192,7 +192,7 @@ public void Dispose_WithLeaveOpenTrue_DoesNotDisposeInnerStream() Stream transcodingStream = new TranscodingStream(innerStream, Encoding.UTF8, Encoding.UTF8, leaveOpen: true); transcodingStream.Dispose(); transcodingStream.Dispose(); // calling it a second time should no-op - innerStream.Read(TranscodingStream.EmptyByteBuffer, 0, 0); // shouldn't throw + innerStream.Read(Array.Empty(), 0, 0); // shouldn't throw // Async @@ -1095,7 +1095,7 @@ public override int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] public override int GetMaxCharCount(int byteCount) => byteCount; - public override byte[] GetPreamble() => TranscodingStream.EmptyByteBuffer; + public override byte[] GetPreamble() => Array.Empty(); } // A helper type that allows synchronously writing to a stream while asynchronously diff --git a/test/System.Net.Http.Formatting.Test/PushStreamContentTest.cs b/test/System.Net.Http.Formatting.Test/PushStreamContentTest.cs index 3edd521b2..a3414019d 100644 --- a/test/System.Net.Http.Formatting.Test/PushStreamContentTest.cs +++ b/test/System.Net.Http.Formatting.Test/PushStreamContentTest.cs @@ -92,7 +92,7 @@ public async Task CompleteTaskOnCloseStream_Dispose_CompletesTaskButDoNotDispose mockStream.Dispose(); // Assert - mockInnerStream.Protected().Verify("Dispose", Times.Never(), true); + mockInnerStream.Protected().Verify("Dispose", Times.Never(), exactParameterMatch: true, args: true); Assert.Equal(TaskStatus.RanToCompletion, serializeToStreamTask.Task.Status); Assert.True(await serializeToStreamTask.Task); } @@ -109,7 +109,7 @@ public async Task CompleteTaskOnCloseStream_Dispose_CompletesTaskButDoNotCloseIn mockStream.Dispose(); // Assert - mockInnerStream.Protected().Verify("Dispose", Times.Never(), true); + mockInnerStream.Protected().Verify("Dispose", Times.Never(), exactParameterMatch: true, args: true); mockInnerStream.Verify(s => s.Close(), Times.Never()); Assert.Equal(TaskStatus.RanToCompletion, serializeToStreamTask.Task.Status); Assert.True(await serializeToStreamTask.Task); @@ -127,7 +127,7 @@ public async Task NonClosingDelegatingStream_Close_CompletesTaskButDoNotCloseInn mockStream.Close(); // Assert - mockInnerStream.Protected().Verify("Dispose", Times.Never(), true); + mockInnerStream.Protected().Verify("Dispose", Times.Never(), exactParameterMatch: true, args: true); mockInnerStream.Verify(s => s.Close(), Times.Never()); Assert.Equal(TaskStatus.RanToCompletion, serializeToStreamTask.Task.Status); Assert.True(await serializeToStreamTask.Task); diff --git a/test/System.Net.Http.Formatting.Test/System.Net.Http.Formatting.Test.csproj b/test/System.Net.Http.Formatting.Test/System.Net.Http.Formatting.Test.csproj index bef6e4406..ab9d953a1 100644 --- a/test/System.Net.Http.Formatting.Test/System.Net.Http.Formatting.Test.csproj +++ b/test/System.Net.Http.Formatting.Test/System.Net.Http.Formatting.Test.csproj @@ -1,7 +1,7 @@  - - + + {7AF77741-9158-4D5F-8782-8F21FADF025F} @@ -18,50 +18,46 @@ - ..\..\packages\System.Buffers.4.5.1\lib\netstandard2.0\System.Buffers.dll + ..\..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll False False - ..\..\packages\System.IO.Pipelines.4.7.5\lib\netstandard2.0\System.IO.Pipelines.dll + ..\..\packages\System.IO.Pipelines.4.7.5\lib\net461\System.IO.Pipelines.dll False True - ..\..\packages\System.Memory.4.5.5\lib\netstandard2.0\System.Memory.dll + ..\..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll False True - ..\..\packages\System.Runtime.CompilerServices.Unsafe.4.7.1\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll + ..\..\packages\System.Runtime.CompilerServices.Unsafe.4.7.1\lib\net461\System.Runtime.CompilerServices.Unsafe.dll False True - ..\..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\portable-net45+win8+wp8+wpa81\System.Threading.Tasks.Extensions.dll + ..\..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll False True - - ..\..\packages\Castle.Core.4.2.1\lib\net45\Castle.Core.dll + + ..\..\packages\Castle.Core.5.1.1\lib\net462\Castle.Core.dll True - - ..\..\packages\Moq.4.7.142\lib\net45\Moq.dll + + ..\..\packages\Moq.4.18.4\lib\net462\Moq.dll True - - False - False - ..\..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll True @@ -71,19 +67,19 @@ True - ..\..\packages\xunit.abstractions.2.0.1\lib\net35\xunit.abstractions.dll + ..\..\packages\xunit.abstractions.2.0.3\lib\net35\xunit.abstractions.dll True - - ..\..\packages\xunit.assert.2.3.0\lib\netstandard1.1\xunit.assert.dll + + ..\..\packages\xunit.assert.2.4.2\lib\netstandard1.1\xunit.assert.dll True - - ..\..\packages\xunit.extensibility.core.2.3.0\lib\netstandard1.1\xunit.core.dll + + ..\..\packages\xunit.extensibility.core.2.4.2\lib\net452\xunit.core.dll True - - ..\..\packages\xunit.extensibility.execution.2.3.0\lib\net452\xunit.execution.desktop.dll + + ..\..\packages\xunit.extensibility.execution.2.4.2\lib\net452\xunit.execution.desktop.dll True @@ -108,21 +104,21 @@ - + - + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - + + + - \ No newline at end of file + diff --git a/test/System.Net.Http.Formatting.Test/packages.config b/test/System.Net.Http.Formatting.Test/packages.config index 7d7c7a6e3..baf1c70f1 100644 --- a/test/System.Net.Http.Formatting.Test/packages.config +++ b/test/System.Net.Http.Formatting.Test/packages.config @@ -1,21 +1,20 @@  - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/System.Web.Cors.Test/System.Web.Cors.Test.csproj b/test/System.Web.Cors.Test/System.Web.Cors.Test.csproj index 62b4ffd51..eea07163a 100644 --- a/test/System.Web.Cors.Test/System.Web.Cors.Test.csproj +++ b/test/System.Web.Cors.Test/System.Web.Cors.Test.csproj @@ -1,7 +1,7 @@  - - + + Library @@ -14,31 +14,31 @@ - - ..\..\packages\Castle.Core.4.2.1\lib\net45\Castle.Core.dll + + ..\..\packages\Castle.Core.5.1.1\lib\net462\Castle.Core.dll True - - ..\..\packages\Moq.4.7.142\lib\net45\Moq.dll + + ..\..\packages\Moq.4.18.4\lib\net462\Moq.dll True - ..\..\packages\xunit.abstractions.2.0.1\lib\net35\xunit.abstractions.dll + ..\..\packages\xunit.abstractions.2.0.3\lib\net35\xunit.abstractions.dll True - - ..\..\packages\xunit.assert.2.3.0\lib\netstandard1.1\xunit.assert.dll + + ..\..\packages\xunit.assert.2.4.2\lib\netstandard1.1\xunit.assert.dll True - - ..\..\packages\xunit.extensibility.core.2.3.0\lib\netstandard1.1\xunit.core.dll + + ..\..\packages\xunit.extensibility.core.2.4.2\lib\net452\xunit.core.dll True - - ..\..\packages\xunit.extensibility.execution.2.3.0\lib\net452\xunit.execution.desktop.dll + + ..\..\packages\xunit.extensibility.execution.2.4.2\lib\net452\xunit.execution.desktop.dll True @@ -68,16 +68,16 @@ - + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - + + + - + \ No newline at end of file diff --git a/test/System.Web.Cors.Test/packages.config b/test/System.Web.Cors.Test/packages.config index b06fb5e7a..cafc6212c 100644 --- a/test/System.Web.Cors.Test/packages.config +++ b/test/System.Web.Cors.Test/packages.config @@ -1,13 +1,13 @@  - - - - - - - - - - + + + + + + + + + + \ No newline at end of file diff --git a/test/System.Web.Helpers.Test/System.Web.Helpers.Test.csproj b/test/System.Web.Helpers.Test/System.Web.Helpers.Test.csproj index dbb552e83..1b14044ab 100644 --- a/test/System.Web.Helpers.Test/System.Web.Helpers.Test.csproj +++ b/test/System.Web.Helpers.Test/System.Web.Helpers.Test.csproj @@ -1,7 +1,7 @@  - - + + {D3313BDF-8071-4AC8-9D98-ABF7F9E88A57} @@ -14,12 +14,12 @@ - - ..\..\packages\Castle.Core.4.2.1\lib\net45\Castle.Core.dll + + ..\..\packages\Castle.Core.5.1.1\lib\net462\Castle.Core.dll True - - ..\..\packages\Moq.4.7.142\lib\net45\Moq.dll + + ..\..\packages\Moq.4.18.4\lib\net462\Moq.dll True @@ -31,19 +31,19 @@ - ..\..\packages\xunit.abstractions.2.0.1\lib\net35\xunit.abstractions.dll + ..\..\packages\xunit.abstractions.2.0.3\lib\net35\xunit.abstractions.dll True - - ..\..\packages\xunit.assert.2.3.0\lib\netstandard1.1\xunit.assert.dll + + ..\..\packages\xunit.assert.2.4.2\lib\netstandard1.1\xunit.assert.dll True - - ..\..\packages\xunit.extensibility.core.2.3.0\lib\netstandard1.1\xunit.core.dll + + ..\..\packages\xunit.extensibility.core.2.4.2\lib\net452\xunit.core.dll True - - ..\..\packages\xunit.extensibility.execution.2.3.0\lib\net452\xunit.execution.desktop.dll + + ..\..\packages\xunit.extensibility.execution.2.4.2\lib\net452\xunit.execution.desktop.dll True @@ -94,16 +94,16 @@ - + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - + + + - + \ No newline at end of file diff --git a/test/System.Web.Helpers.Test/packages.config b/test/System.Web.Helpers.Test/packages.config index b06fb5e7a..cafc6212c 100644 --- a/test/System.Web.Helpers.Test/packages.config +++ b/test/System.Web.Helpers.Test/packages.config @@ -1,13 +1,13 @@  - - - - - - - - - - + + + + + + + + + + \ No newline at end of file diff --git a/test/System.Web.Http.Cors.Test/System.Web.Http.Cors.Test.csproj b/test/System.Web.Http.Cors.Test/System.Web.Http.Cors.Test.csproj index db4049525..b270959ce 100644 --- a/test/System.Web.Http.Cors.Test/System.Web.Http.Cors.Test.csproj +++ b/test/System.Web.Http.Cors.Test/System.Web.Http.Cors.Test.csproj @@ -1,7 +1,7 @@  - - + + {1E89A3E9-0A7F-418F-B4BE-6E38A6315373} @@ -14,12 +14,12 @@ - - ..\..\packages\Castle.Core.4.2.1\lib\net45\Castle.Core.dll + + ..\..\packages\Castle.Core.5.1.1\lib\net462\Castle.Core.dll True - - ..\..\packages\Moq.4.7.142\lib\net45\Moq.dll + + ..\..\packages\Moq.4.18.4\lib\net462\Moq.dll True @@ -31,19 +31,19 @@ - ..\..\packages\xunit.abstractions.2.0.1\lib\net35\xunit.abstractions.dll + ..\..\packages\xunit.abstractions.2.0.3\lib\net35\xunit.abstractions.dll True - - ..\..\packages\xunit.assert.2.3.0\lib\netstandard1.1\xunit.assert.dll + + ..\..\packages\xunit.assert.2.4.2\lib\netstandard1.1\xunit.assert.dll True - - ..\..\packages\xunit.extensibility.core.2.3.0\lib\netstandard1.1\xunit.core.dll + + ..\..\packages\xunit.extensibility.core.2.4.2\lib\net452\xunit.core.dll True - - ..\..\packages\xunit.extensibility.execution.2.3.0\lib\net452\xunit.execution.desktop.dll + + ..\..\packages\xunit.extensibility.execution.2.4.2\lib\net452\xunit.execution.desktop.dll True @@ -97,16 +97,16 @@ - + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - + + + - + \ No newline at end of file diff --git a/test/System.Web.Http.Cors.Test/packages.config b/test/System.Web.Http.Cors.Test/packages.config index 6e4cf51b5..72e333be0 100644 --- a/test/System.Web.Http.Cors.Test/packages.config +++ b/test/System.Web.Http.Cors.Test/packages.config @@ -1,14 +1,14 @@  - - - - - - - - - - - + + + + + + + + + + + \ No newline at end of file diff --git a/test/System.Web.Http.Integration.Test/System.Web.Http.Integration.Test.csproj b/test/System.Web.Http.Integration.Test/System.Web.Http.Integration.Test.csproj index 22df805eb..6edd73613 100644 --- a/test/System.Web.Http.Integration.Test/System.Web.Http.Integration.Test.csproj +++ b/test/System.Web.Http.Integration.Test/System.Web.Http.Integration.Test.csproj @@ -1,7 +1,7 @@  - - + + {3267DFC6-B34D-4011-BC0F-D3B56AF6F608} @@ -14,12 +14,12 @@ - - ..\..\packages\Castle.Core.4.2.1\lib\net45\Castle.Core.dll + + ..\..\packages\Castle.Core.5.1.1\lib\net462\Castle.Core.dll True - - ..\..\packages\Moq.4.7.142\lib\net45\Moq.dll + + ..\..\packages\Moq.4.18.4\lib\net462\Moq.dll True @@ -39,19 +39,19 @@ - ..\..\packages\xunit.abstractions.2.0.1\lib\net35\xunit.abstractions.dll + ..\..\packages\xunit.abstractions.2.0.3\lib\net35\xunit.abstractions.dll True - - ..\..\packages\xunit.assert.2.3.0\lib\netstandard1.1\xunit.assert.dll + + ..\..\packages\xunit.assert.2.4.2\lib\netstandard1.1\xunit.assert.dll True - - ..\..\packages\xunit.extensibility.core.2.3.0\lib\netstandard1.1\xunit.core.dll + + ..\..\packages\xunit.extensibility.core.2.4.2\lib\net452\xunit.core.dll True - - ..\..\packages\xunit.extensibility.execution.2.3.0\lib\net452\xunit.execution.desktop.dll + + ..\..\packages\xunit.extensibility.execution.2.4.2\lib\net452\xunit.execution.desktop.dll True @@ -150,16 +150,16 @@ - + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - + + + - + \ No newline at end of file diff --git a/test/System.Web.Http.Integration.Test/packages.config b/test/System.Web.Http.Integration.Test/packages.config index 6e4cf51b5..72e333be0 100644 --- a/test/System.Web.Http.Integration.Test/packages.config +++ b/test/System.Web.Http.Integration.Test/packages.config @@ -1,14 +1,14 @@  - - - - - - - - - - - + + + + + + + + + + + \ No newline at end of file diff --git a/test/System.Web.Http.Owin.Test/NonOwnedStreamTests.cs b/test/System.Web.Http.Owin.Test/NonOwnedStreamTests.cs index 4591e067a..c21948fb5 100644 --- a/test/System.Web.Http.Owin.Test/NonOwnedStreamTests.cs +++ b/test/System.Web.Http.Owin.Test/NonOwnedStreamTests.cs @@ -121,7 +121,7 @@ public void Dispose_DoesNotDisposeInnerStream() Mock mock = new Mock(MockBehavior.Strict); mock.Setup(s => s.Close()).Callback(() => innerStreamDisposed = true); mock.As().Setup(s => s.Dispose()); - mock.Protected().Setup("Dispose", true).Callback(() => innerStreamDisposed = true); + mock.Protected().Setup("Dispose", exactParameterMatch: true, args: true).Callback(() => innerStreamDisposed = true); using (Stream innerStream = mock.Object) using (Stream product = CreateProductUnderTest(innerStream)) @@ -159,7 +159,7 @@ public void Close_DoesNotDisposeInnerStream() Mock mock = new Mock(MockBehavior.Strict); mock.Setup(s => s.Close()).Callback(() => innerStreamDisposed = true); mock.As().Setup(s => s.Dispose()); - mock.Protected().Setup("Dispose", true).Callback(() => innerStreamDisposed = true); + mock.Protected().Setup("Dispose", exactParameterMatch: true, args: true).Callback(() => innerStreamDisposed = true); using (Stream innerStream = mock.Object) using (Stream product = CreateProductUnderTest(innerStream)) diff --git a/test/System.Web.Http.Owin.Test/System.Web.Http.Owin.Test.csproj b/test/System.Web.Http.Owin.Test/System.Web.Http.Owin.Test.csproj index 6e89f0a11..7cf636838 100644 --- a/test/System.Web.Http.Owin.Test/System.Web.Http.Owin.Test.csproj +++ b/test/System.Web.Http.Owin.Test/System.Web.Http.Owin.Test.csproj @@ -1,7 +1,7 @@  - - + + {C19267DD-3984-430C-AE18-4034F85DE4E5} @@ -14,8 +14,8 @@ - - ..\..\packages\Castle.Core.4.2.1\lib\net45\Castle.Core.dll + + ..\..\packages\Castle.Core.5.1.1\lib\net462\Castle.Core.dll True @@ -29,8 +29,8 @@ False ..\..\packages\Microsoft.Owin.Hosting.4.2.2\lib\net45\Microsoft.Owin.Hosting.dll - - ..\..\packages\Moq.4.7.142\lib\net45\Moq.dll + + ..\..\packages\Moq.4.18.4\lib\net462\Moq.dll True @@ -45,19 +45,19 @@ - ..\..\packages\xunit.abstractions.2.0.1\lib\net35\xunit.abstractions.dll + ..\..\packages\xunit.abstractions.2.0.3\lib\net35\xunit.abstractions.dll True - - ..\..\packages\xunit.assert.2.3.0\lib\netstandard1.1\xunit.assert.dll + + ..\..\packages\xunit.assert.2.4.2\lib\netstandard1.1\xunit.assert.dll True - - ..\..\packages\xunit.extensibility.core.2.3.0\lib\netstandard1.1\xunit.core.dll + + ..\..\packages\xunit.extensibility.core.2.4.2\lib\net452\xunit.core.dll True - - ..\..\packages\xunit.extensibility.execution.2.3.0\lib\net452\xunit.execution.desktop.dll + + ..\..\packages\xunit.extensibility.execution.2.4.2\lib\net452\xunit.execution.desktop.dll True @@ -106,16 +106,16 @@ - + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - + + + - + \ No newline at end of file diff --git a/test/System.Web.Http.Owin.Test/packages.config b/test/System.Web.Http.Owin.Test/packages.config index 1c3c24447..f789b6961 100644 --- a/test/System.Web.Http.Owin.Test/packages.config +++ b/test/System.Web.Http.Owin.Test/packages.config @@ -1,18 +1,18 @@  - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/System.Web.Http.SelfHost.Test/System.Web.Http.SelfHost.Test.csproj b/test/System.Web.Http.SelfHost.Test/System.Web.Http.SelfHost.Test.csproj index bf99a8ccc..c16be2756 100644 --- a/test/System.Web.Http.SelfHost.Test/System.Web.Http.SelfHost.Test.csproj +++ b/test/System.Web.Http.SelfHost.Test/System.Web.Http.SelfHost.Test.csproj @@ -1,7 +1,7 @@  - - + + {7F29EE87-6A63-43C6-B7FF-74DD06815830} @@ -14,12 +14,12 @@ - - ..\..\packages\Castle.Core.4.2.1\lib\net45\Castle.Core.dll + + ..\..\packages\Castle.Core.5.1.1\lib\net462\Castle.Core.dll True - - ..\..\packages\Moq.4.7.142\lib\net45\Moq.dll + + ..\..\packages\Moq.4.18.4\lib\net462\Moq.dll True @@ -37,19 +37,19 @@ - ..\..\packages\xunit.abstractions.2.0.1\lib\net35\xunit.abstractions.dll + ..\..\packages\xunit.abstractions.2.0.3\lib\net35\xunit.abstractions.dll True - - ..\..\packages\xunit.assert.2.3.0\lib\netstandard1.1\xunit.assert.dll + + ..\..\packages\xunit.assert.2.4.2\lib\netstandard1.1\xunit.assert.dll True - - ..\..\packages\xunit.extensibility.core.2.3.0\lib\netstandard1.1\xunit.core.dll + + ..\..\packages\xunit.extensibility.core.2.4.2\lib\net452\xunit.core.dll True - - ..\..\packages\xunit.extensibility.execution.2.3.0\lib\net452\xunit.execution.desktop.dll + + ..\..\packages\xunit.extensibility.execution.2.4.2\lib\net452\xunit.execution.desktop.dll True @@ -101,16 +101,16 @@ - + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - + + + - + \ No newline at end of file diff --git a/test/System.Web.Http.SelfHost.Test/packages.config b/test/System.Web.Http.SelfHost.Test/packages.config index 6e4cf51b5..72e333be0 100644 --- a/test/System.Web.Http.SelfHost.Test/packages.config +++ b/test/System.Web.Http.SelfHost.Test/packages.config @@ -1,14 +1,14 @@  - - - - - - - - - - - + + + + + + + + + + + \ No newline at end of file diff --git a/test/System.Web.Http.SignalR.Test/System.Web.Http.SignalR.Test.csproj b/test/System.Web.Http.SignalR.Test/System.Web.Http.SignalR.Test.csproj index a7a6ce203..bea9c73c3 100644 --- a/test/System.Web.Http.SignalR.Test/System.Web.Http.SignalR.Test.csproj +++ b/test/System.Web.Http.SignalR.Test/System.Web.Http.SignalR.Test.csproj @@ -1,7 +1,7 @@  - - + + {E22245AF-D5E1-46F6-B443-C886983EC50C} @@ -13,15 +13,15 @@ - - ..\..\packages\Castle.Core.4.2.1\lib\net45\Castle.Core.dll + + ..\..\packages\Castle.Core.5.1.1\lib\net462\Castle.Core.dll True ..\..\packages\Microsoft.AspNet.SignalR.Core.1.0.0\lib\net40\Microsoft.AspNet.SignalR.Core.dll - - ..\..\packages\Moq.4.7.142\lib\net45\Moq.dll + + ..\..\packages\Moq.4.18.4\lib\net462\Moq.dll True @@ -35,19 +35,19 @@ - ..\..\packages\xunit.abstractions.2.0.1\lib\net35\xunit.abstractions.dll + ..\..\packages\xunit.abstractions.2.0.3\lib\net35\xunit.abstractions.dll True - - ..\..\packages\xunit.assert.2.3.0\lib\netstandard1.1\xunit.assert.dll + + ..\..\packages\xunit.assert.2.4.2\lib\netstandard1.1\xunit.assert.dll True - - ..\..\packages\xunit.extensibility.core.2.3.0\lib\netstandard1.1\xunit.core.dll + + ..\..\packages\xunit.extensibility.core.2.4.2\lib\net452\xunit.core.dll True - - ..\..\packages\xunit.extensibility.execution.2.3.0\lib\net452\xunit.execution.desktop.dll + + ..\..\packages\xunit.extensibility.execution.2.4.2\lib\net452\xunit.execution.desktop.dll True @@ -81,16 +81,16 @@ - + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - + + + - + \ No newline at end of file diff --git a/test/System.Web.Http.SignalR.Test/packages.config b/test/System.Web.Http.SignalR.Test/packages.config index 420ed134e..76583074d 100644 --- a/test/System.Web.Http.SignalR.Test/packages.config +++ b/test/System.Web.Http.SignalR.Test/packages.config @@ -1,15 +1,15 @@  - - - - - - - - - - - - + + + + + + + + + + + + \ No newline at end of file diff --git a/test/System.Web.Http.Test/Dispatcher/DefaultHttpControllerActivatorTest.cs b/test/System.Web.Http.Test/Dispatcher/DefaultHttpControllerActivatorTest.cs index 7db1b5780..191397e83 100644 --- a/test/System.Web.Http.Test/Dispatcher/DefaultHttpControllerActivatorTest.cs +++ b/test/System.Web.Http.Test/Dispatcher/DefaultHttpControllerActivatorTest.cs @@ -153,7 +153,7 @@ public void Create_ThrowsForNullDependencyScope() exception.Message); Assert.NotNull(exception.InnerException); Assert.Matches( - "A dependency resolver of type 'ObjectProxy(_\\d+)?' returned an invalid value of null from its " + + "A dependency resolver of type 'IDependencyResolverProxy' returned an invalid value of null from its " + "BeginScope method. If the container does not have a concept of scope, consider returning a scope " + "that resolves in the root of the container instead.", exception.InnerException.Message); diff --git a/test/System.Web.Http.Test/Routing/DirectRouteProviderContextTests.cs b/test/System.Web.Http.Test/Routing/DirectRouteProviderContextTests.cs index bec090eba..891f2ba2a 100644 --- a/test/System.Web.Http.Test/Routing/DirectRouteProviderContextTests.cs +++ b/test/System.Web.Http.Test/Routing/DirectRouteProviderContextTests.cs @@ -43,7 +43,7 @@ public void CreateBuilderWithResolverAndBuild_Throws_WhenConstraintResolverRetur var ex = Assert.Throws( () => BuildWithResolver(@"hello/{param:constraint}", constraintResolver: constraintResolver.Object)); Assert.Matches( - "The inline constraint resolver of type 'ObjectProxy(_\\d+)?' was unable to resolve the following inline constraint: 'constraint'.", + "The inline constraint resolver of type 'IInlineConstraintResolverProxy' was unable to resolve the following inline constraint: 'constraint'.", ex.Message); } diff --git a/test/System.Web.Http.Test/System.Web.Http.Test.csproj b/test/System.Web.Http.Test/System.Web.Http.Test.csproj index 5e7fce08b..dbda0c5e4 100644 --- a/test/System.Web.Http.Test/System.Web.Http.Test.csproj +++ b/test/System.Web.Http.Test/System.Web.Http.Test.csproj @@ -1,7 +1,7 @@  - - + + {7F2C796F-43B2-4F8F-ABFF-A154EC8AAFA1} @@ -15,12 +15,12 @@ - - ..\..\packages\Castle.Core.4.2.1\lib\net45\Castle.Core.dll + + ..\..\packages\Castle.Core.5.1.1\lib\net462\Castle.Core.dll True - - ..\..\packages\Moq.4.7.142\lib\net45\Moq.dll + + ..\..\packages\Moq.4.18.4\lib\net462\Moq.dll True @@ -40,19 +40,19 @@ - ..\..\packages\xunit.abstractions.2.0.1\lib\net35\xunit.abstractions.dll + ..\..\packages\xunit.abstractions.2.0.3\lib\net35\xunit.abstractions.dll True - - ..\..\packages\xunit.assert.2.3.0\lib\netstandard1.1\xunit.assert.dll + + ..\..\packages\xunit.assert.2.4.2\lib\netstandard1.1\xunit.assert.dll True - - ..\..\packages\xunit.extensibility.core.2.3.0\lib\netstandard1.1\xunit.core.dll + + ..\..\packages\xunit.extensibility.core.2.4.2\lib\net452\xunit.core.dll True - - ..\..\packages\xunit.extensibility.execution.2.3.0\lib\net452\xunit.execution.desktop.dll + + ..\..\packages\xunit.extensibility.execution.2.4.2\lib\net452\xunit.execution.desktop.dll True @@ -405,16 +405,16 @@ - + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - + + + - + \ No newline at end of file diff --git a/test/System.Web.Http.Test/packages.config b/test/System.Web.Http.Test/packages.config index 6e4cf51b5..72e333be0 100644 --- a/test/System.Web.Http.Test/packages.config +++ b/test/System.Web.Http.Test/packages.config @@ -1,14 +1,14 @@  - - - - - - - - - - - + + + + + + + + + + + \ No newline at end of file diff --git a/test/System.Web.Http.Tracing.Test/System.Web.Http.Tracing.Test.csproj b/test/System.Web.Http.Tracing.Test/System.Web.Http.Tracing.Test.csproj index a2461dfe4..ee60b9358 100644 --- a/test/System.Web.Http.Tracing.Test/System.Web.Http.Tracing.Test.csproj +++ b/test/System.Web.Http.Tracing.Test/System.Web.Http.Tracing.Test.csproj @@ -1,7 +1,7 @@  - - + + {F87FD911-4A97-4057-8EAE-1CB96B9A1937} @@ -24,19 +24,19 @@ - ..\..\packages\xunit.abstractions.2.0.1\lib\net35\xunit.abstractions.dll + ..\..\packages\xunit.abstractions.2.0.3\lib\net35\xunit.abstractions.dll True - - ..\..\packages\xunit.assert.2.3.0\lib\netstandard1.1\xunit.assert.dll + + ..\..\packages\xunit.assert.2.4.2\lib\netstandard1.1\xunit.assert.dll True - - ..\..\packages\xunit.extensibility.core.2.3.0\lib\netstandard1.1\xunit.core.dll + + ..\..\packages\xunit.extensibility.core.2.4.2\lib\net452\xunit.core.dll True - - ..\..\packages\xunit.extensibility.execution.2.3.0\lib\net452\xunit.execution.desktop.dll + + ..\..\packages\xunit.extensibility.execution.2.4.2\lib\net452\xunit.execution.desktop.dll True @@ -69,18 +69,18 @@ - + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - + + + - + - + Date: Mon, 13 Feb 2023 12:39:52 -0800 Subject: [PATCH 36/54] Test Formatting assemblies w/ `net6.0` (#384) - expand our text matrix to include a modern (and LTS) TFM - change how Formatting test assemblies are found - `netcoreapp` is no longer the only relevant folder prefix - use the latest .NET 6 SDK - install the 2.1.x runtime in the pipeline - don't require .NET in VS - will use binplaced `msbuild` instead - have `git` ignore the new .msbuild/ folder - react to new `Exception.Message`s in `netcoreapp3.1` - handle different formatting of argument info in `ArgumentException.Message`s - handle slightly greater `decimal` precision in a `JsonReaderException.Message` - react to new `Exception.Message`s and other changes in `net6.0` - handle different `Message` in `InvalidOperationException`s about invalid request URIs - react to other changes in `net6.0` - handle inability to mock a `Stream` if a writer passes a `ReadOnlySpan` in `net6.0` - see moq/moq4#829, moq/moq4#979, and dotnet/runtime#45152 about the issue - skip tests failing due to `HttpResponseMessage` changes - see #386 and dotnet/runtime@b48900f3b37e6d68b5d84a3e48f0c5beb602a128 (which introduced this) - fix coming **Real Soon Now:tm:** :grin: - nits: - simplify define use now that `NETCOREAPP3_1_OR_GREATER` and so on are available - clean up .gitignore - clean up a few comments and tighten scripting up --- .gitignore | 28 ++++++------- Runtime.msbuild | 10 ++--- azure-pipelines.yml | 6 +++ build.cmd | 38 +++++++++-------- eng/GetXCopyMSBuild.ps1 | 42 +++++++++++++++++++ global.json | 2 +- .../Internal/TranscodingStream.cs | 2 +- .../ExceptionAssertions.cs | 19 ++++++--- .../Microsoft.TestCommon.csproj | 2 +- ...em.Net.Http.Formatting.NetCore.Test.csproj | 2 +- ...et.Http.Formatting.NetStandard.Test.csproj | 2 +- .../Formatting/BsonMediaTypeFormatterTests.cs | 7 +++- .../Formatting/JsonMediaTypeFormatterTests.cs | 24 +++++++++++ .../Handlers/ProgressMessageHandlerTest.cs | 2 + .../HttpClientExtensionsTest.cs | 30 +++++++------ .../HttpMessageContentTests.cs | 4 ++ .../Internal/TranscodingStreamTests.cs | 4 +- .../System.Net.Http.Formatting.Test.csproj | 2 +- 18 files changed, 163 insertions(+), 63 deletions(-) create mode 100644 eng/GetXCopyMSBuild.ps1 diff --git a/.gitignore b/.gitignore index 6cd7bfb72..9f67f0ee8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,22 +1,20 @@ -[Bb]in -[Oo]bj -[Tt]est[Rr]esults -*.suo -*.user +.msbuild/ +.vs/ +bin/ +obj/ +packages/ + *.[Cc]ache -*[Rr]esharper* -packages -NuGet.exe -_[Ss]cripts *.binlog -*.exe *.dll -*.nupkg *.dot[Cc]over -*.vsp -*.psess +*.exe +*.nupkg *.orig +*.psess *.sln.ide -.vs/ -project.lock.json +*.suo +*.user +*.vsp +*[Rr]esharper* *launchSettings.json diff --git a/Runtime.msbuild b/Runtime.msbuild index ac847731a..e02860a28 100644 --- a/Runtime.msbuild +++ b/Runtime.msbuild @@ -115,12 +115,12 @@ XmlPath=$(TestResultsDirectory)%(_TestDLLsXunit.FileName)-XunitResults.xml - <_VSTestDLLs Include="bin\$(Configuration)\test\*\netcoreapp*\*.Test.dll" - Condition=" '$(BuildPortable)' == 'true' "/> - <_XunitProject Include="tools\WebStack.testing.targets" - Condition=" '$(BuildPortable)' == 'true' "> + <_VSTestDLLs Include="bin\$(Configuration)\test\NetCore\**\*.Test.dll; + bin\$(Configuration)\test\NetStandard\**\*.Test.dll" + Exclude="bin\$(Configuration)\test\Net*\net4*\*.Test.dll" /> + <_XunitProject Include="tools\WebStack.testing.targets" Condition=" '$(BuildPortable)' == 'true' "> TestAssembly=%(_VSTestDLLs.FullPath); - XmlPath=$(TestResultsDirectory)%(_VSTestDLLs.FileName)-NetCoreApp-XunitResults.xml; + XmlPath=$(TestResultsDirectory)%(_VSTestDLLs.FileName)-$([System.String]::Copy('%(_VSTestDLLs.RecursiveDir)').Trim('\\'))-XunitResults.xml; UseVSTest=true diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 820089f1c..2da1d8ad2 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -60,10 +60,16 @@ jobs: - checkout: self clean: true displayName: Checkout + - task: UseDotNet@2 displayName: Get .NET SDK inputs: useGlobalJson: true + - task: UseDotNet@2 + displayName: Get .NET 2.1 runtime + inputs: + packageType: runtime + version: '2.1.x' - script: .\build.cmd EnableSkipStrongNames displayName: Enable SkipStrongNames diff --git a/build.cmd b/build.cmd index 798507f17..500eb973a 100644 --- a/build.cmd +++ b/build.cmd @@ -2,13 +2,12 @@ pushd %~dp0 setlocal -if exist bin goto build +if exist bin goto Build mkdir bin :Build -REM Find the most recent 32bit MSBuild.exe on the system. Require v16.0 (installed with VS2019) or later. -REM Use `vswhere` for the search because it can find all VS installations. +REM Require VS2019 (v16.0) on the system. Use `vswhere` for the search because it can find all VS installations. set vswhere="%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" if not exist %vswhere% ( set vswhere="%ProgramFiles%\Microsoft Visual Studio\Installer\vswhere.exe" @@ -24,28 +23,33 @@ if not exist %vswhere% ( goto BuildFail ) -REM We're fine w/ any .NET SDK newer than 2.1.500 but also need a 2.1.x runtime. Microsoft.Net.Core.Component.SDK.2.1 -REM actually checks for only the runtime these days. set InstallDir= for /f "usebackq tokens=*" %%i in (`%vswhere% -version 16 -latest -prerelease -products * ^ - -requires Microsoft.Component.MSBuild ^ - -requires Microsoft.NetCore.Component.SDK ^ - -requires Microsoft.Net.Core.Component.SDK.2.1 ^ + -requires Microsoft.Net.Component.4.5.TargetingPack ^ + -requires Microsoft.Net.Component.4.5.2.TargetingPack ^ + -requires Microsoft.Net.Component.4.6.2.TargetingPack ^ -property installationPath`) do ( set InstallDir="%%i" ) if not DEFINED InstallDir ( - echo "Could not find a VS2019 installation with the necessary components (MSBuild, .NET Core 2.1 Runtime, .NET SDK). Please install VS2019 or the missing components." -) - -if exist %InstallDir%\MSBuild\Current\Bin\MSBuild.exe ( - set MSBuild=%InstallDir%\MSBuild\Current\Bin\MSBuild.exe -) else ( - echo Could not find MSBuild.exe. Please install the VS2019 BuildTools component or a workload that includes it. + echo "Could not find a VS2019 installation with the necessary components (targeting packs for v4.5, v4.5.2, and v4.6.2)." + echo Please install VS2019 or the missing components. goto BuildFail ) +REM Find or install MSBuild. Need v17.4 due to our .NET SDK choice. +set "MSBuildVersion=17.4.1" +set "Command=[System.Threading.Thread]::CurrentThread.CurrentCulture = ''" +set "Command=%Command%; [System.Threading.Thread]::CurrentThread.CurrentUICulture = ''" +set "Command=%Command%; try { & '%~dp0eng\GetXCopyMSBuild.ps1' %MSBuildVersion%; exit $LASTEXITCODE }" +set "Command=%Command% catch { write-host $_; exit 1 }" +PowerShell -NoProfile -NoLogo -ExecutionPolicy Bypass -Command "%Command%" +if %ERRORLEVEL% neq 0 goto BuildFail + +REM Add MSBuild to the path. +set "PATH=%CD%\.msbuild\%MSBuildVersion%\tools\MSBuild\Current\Bin\;%PATH%" + REM Configure NuGet operations to work w/in this repo i.e. do not pollute system packages folder. REM Note this causes two copies of packages restored using packages.config to land in this folder e.g. REM StyleCpy.5.0.0/ and stylecop/5.0.0/. @@ -56,13 +60,13 @@ if DEFINED CI (set Desktop=false) else if DEFINED TEAMCITY_VERSION (set Desktop= if "%1" == "" goto BuildDefaults -%MSBuild% Runtime.msbuild /m /nr:false /p:Platform="Any CPU" /p:Desktop=%Desktop% /v:M ^ +MSBuild Runtime.msbuild /m /nr:false /p:Platform="Any CPU" /p:Desktop=%Desktop% /v:M ^ /fl /fileLoggerParameters:LogFile=bin\msbuild.log;Verbosity=Normal /consoleLoggerParameters:Summary /t:%* if %ERRORLEVEL% neq 0 goto BuildFail goto BuildSuccess :BuildDefaults -%MSBuild% Runtime.msbuild /m /nr:false /p:Platform="Any CPU" /p:Desktop=%Desktop% /v:M ^ +MSBuild Runtime.msbuild /m /nr:false /p:Platform="Any CPU" /p:Desktop=%Desktop% /v:M ^ /fl /fileLoggerParameters:LogFile=bin\msbuild.log;Verbosity=Normal /consoleLoggerParameters:Summary if %ERRORLEVEL% neq 0 goto BuildFail goto BuildSuccess diff --git a/eng/GetXCopyMSBuild.ps1 b/eng/GetXCopyMSBuild.ps1 new file mode 100644 index 000000000..6ab853c30 --- /dev/null +++ b/eng/GetXCopyMSBuild.ps1 @@ -0,0 +1,42 @@ +# Lifted from https://github.com/dotnet/arcade/blob/main/eng/common/tools.ps1 + +[CmdletBinding(DefaultParameterSetName='Groups')] +param( + [string]$Version = '17.4.1' +) + +Set-StrictMode -Version 2 +$ErrorActionPreference = 'Stop' + +function Create-Directory ([string[]] $path) { + New-Item -Path $path -Force -ItemType 'Directory' | Out-Null +} + +function Unzip([string]$zipfile, [string]$outpath) { + Add-Type -AssemblyName System.IO.Compression.FileSystem + [System.IO.Compression.ZipFile]::ExtractToDirectory($zipfile, $outpath) +} + +function InitializeXCopyMSBuild([string]$packageVersion, [bool]$install, [string]$ToolsDir) { + $packageName = 'RoslynTools.MSBuild' + $packageDir = Join-Path $ToolsDir $packageVersion + $packagePath = Join-Path $packageDir "$packageName.$packageVersion.nupkg" + + if (!(Test-Path $packageDir)) { + if (!$install) { + return $null + } + + Create-Directory $packageDir + + Write-Host "Downloading $packageName $packageVersion" + $ProgressPreference = 'SilentlyContinue' # Don't display the console progress UI - it's a huge perf hit + Invoke-WebRequest "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/flat2/$packageName/$packageVersion/$packageName.$packageVersion.nupkg" -OutFile $packagePath + + Unzip $packagePath $packageDir + } + + return Join-Path $packageDir 'tools' +} + +InitializeXCopyMSBuild -packageVersion $Version -install $true -ToolsDir (join-path $PWD .msbuild) diff --git a/global.json b/global.json index 053fd617a..0f75e8a6f 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "2.1.818", + "version": "6.0.405", "rollForward": "major" } } diff --git a/src/System.Net.Http.Formatting/Internal/TranscodingStream.cs b/src/System.Net.Http.Formatting/Internal/TranscodingStream.cs index 9d392d469..f279b73ad 100644 --- a/src/System.Net.Http.Formatting/Internal/TranscodingStream.cs +++ b/src/System.Net.Http.Formatting/Internal/TranscodingStream.cs @@ -119,7 +119,7 @@ protected override void Dispose(bool disposing) } } -#if NETCOREAPP3_1 || NET5_0_OR_GREATER || NETSTANDARD2_1 +#if NETCOREAPP3_1_OR_GREATER || NETSTANDARD2_1 public override ValueTask DisposeAsync() { if (_innerStream is null) diff --git a/test/Microsoft.TestCommon/ExceptionAssertions.cs b/test/Microsoft.TestCommon/ExceptionAssertions.cs index 5cca7e7c8..0b43f6627 100644 --- a/test/Microsoft.TestCommon/ExceptionAssertions.cs +++ b/test/Microsoft.TestCommon/ExceptionAssertions.cs @@ -297,7 +297,7 @@ public static async Task ThrowsArgumentNullAsync(FuncThrown when an exception was not thrown, or when an exception of the incorrect type is thrown public static ArgumentException ThrowsArgumentNullOrEmpty(Action testCode, string paramName) { - return Throws(testCode, "Value cannot be null or empty.\r\nParameter name: " + paramName, allowDerivedExceptions: false); + return Throws(testCode, "Value cannot be null or empty." + GetParameterMessage(paramName), allowDerivedExceptions: false); } /// @@ -327,7 +327,7 @@ public static ArgumentOutOfRangeException ThrowsArgumentOutOfRange(Action testCo { if (exceptionMessage != null) { - exceptionMessage = exceptionMessage + "\r\nParameter name: " + paramName; + exceptionMessage = exceptionMessage + GetParameterMessage(paramName); if (actualValue != null) { exceptionMessage += String.Format(CultureReplacer.DefaultCulture, "\r\nActual value was {0}.", actualValue); @@ -360,7 +360,7 @@ public static async Task ThrowsArgumentOutOfRangeAs { if (exceptionMessage != null) { - exceptionMessage = exceptionMessage + "\r\nParameter name: " + paramName; + exceptionMessage = exceptionMessage + GetParameterMessage(paramName); if (actualValue != null) { exceptionMessage += String.Format(CultureReplacer.DefaultCulture, "\r\nActual value was {0}.", actualValue); @@ -500,8 +500,8 @@ public static HttpException ThrowsHttpException(Action testCode, string exceptio public static ArgumentException ThrowsInvalidEnumArgument(Action testCode, string paramName, int invalidValue, Type enumType, bool allowDerivedExceptions = false) { string message = String.Format(CultureReplacer.DefaultCulture, - "The value of argument '{0}' ({1}) is invalid for Enum type '{2}'.{3}Parameter name: {0}", - paramName, invalidValue, enumType.Name, Environment.NewLine); + "The value of argument '{0}' ({1}) is invalid for Enum type '{2}'.{3}", + paramName, invalidValue, enumType.Name, GetParameterMessage(paramName)); #if NETFX_CORE // InvalidEnumArgumentException not available in netstandard1.3. return Throws(testCode, message, allowDerivedExceptions); @@ -581,6 +581,15 @@ public static async Task ThrowsAsync( return ex; } + private static string GetParameterMessage(string parameterName) + { +#if NETCOREAPP3_1_OR_GREATER + return " (Parameter '" + parameterName + "')"; +#else + return Environment.NewLine + "Parameter name: " + parameterName; +#endif + } + // We've re-implemented all the xUnit.net Throws code so that we can get this // updated implementation of RecordException which silently unwraps any instances // of AggregateException. In addition to unwrapping exceptions, this method ensures diff --git a/test/Microsoft.TestCommon/Microsoft.TestCommon.csproj b/test/Microsoft.TestCommon/Microsoft.TestCommon.csproj index 65c984aff..593a10e13 100644 --- a/test/Microsoft.TestCommon/Microsoft.TestCommon.csproj +++ b/test/Microsoft.TestCommon/Microsoft.TestCommon.csproj @@ -1,7 +1,7 @@  - net462;netcoreapp2.1 + net462;netcoreapp2.1;net6.0 $(Configurations);CodeAnalysis $(DefineConstants);NETFX_CORE diff --git a/test/System.Net.Http.Formatting.NetCore.Test/System.Net.Http.Formatting.NetCore.Test.csproj b/test/System.Net.Http.Formatting.NetCore.Test/System.Net.Http.Formatting.NetCore.Test.csproj index 68179da3e..1a2fc91cd 100644 --- a/test/System.Net.Http.Formatting.NetCore.Test/System.Net.Http.Formatting.NetCore.Test.csproj +++ b/test/System.Net.Http.Formatting.NetCore.Test/System.Net.Http.Formatting.NetCore.Test.csproj @@ -1,7 +1,7 @@  - netcoreapp2.1;net462 + net462;netcoreapp2.1;net6.0 System.Net.Http ..\..\bin\$(Configuration)\Test\NetCore\ $(Configurations);CodeAnalysis diff --git a/test/System.Net.Http.Formatting.NetStandard.Test/System.Net.Http.Formatting.NetStandard.Test.csproj b/test/System.Net.Http.Formatting.NetStandard.Test/System.Net.Http.Formatting.NetStandard.Test.csproj index bdcc1288d..dc96f8c4c 100644 --- a/test/System.Net.Http.Formatting.NetStandard.Test/System.Net.Http.Formatting.NetStandard.Test.csproj +++ b/test/System.Net.Http.Formatting.NetStandard.Test/System.Net.Http.Formatting.NetStandard.Test.csproj @@ -1,7 +1,7 @@  - netcoreapp2.1;net462 + net462;netcoreapp2.1;net6.0 System.Net.Http ..\..\bin\$(Configuration)\Test\NetStandard\ $(Configurations);CodeAnalysis diff --git a/test/System.Net.Http.Formatting.Test/Formatting/BsonMediaTypeFormatterTests.cs b/test/System.Net.Http.Formatting.Test/Formatting/BsonMediaTypeFormatterTests.cs index 3082b265d..8b49dba47 100644 --- a/test/System.Net.Http.Formatting.Test/Formatting/BsonMediaTypeFormatterTests.cs +++ b/test/System.Net.Http.Formatting.Test/Formatting/BsonMediaTypeFormatterTests.cs @@ -330,7 +330,12 @@ public async Task FormatterThrowsOnReadWithInvalidContent() // Act & Assert await Assert.ThrowsAsync( () => formatter.ReadFromStreamAsync(variationType, stream, content, null), - "Could not convert to decimal: 7.92281625142643E+28. Path 'Value'."); +#if NETCOREAPP3_1_OR_GREATER + "Could not convert to decimal: 7.922816251426434E+28. Path 'Value'." +#else + "Could not convert to decimal: 7.92281625142643E+28. Path 'Value'." +#endif + ); } [Theory] diff --git a/test/System.Net.Http.Formatting.Test/Formatting/JsonMediaTypeFormatterTests.cs b/test/System.Net.Http.Formatting.Test/Formatting/JsonMediaTypeFormatterTests.cs index 76a497182..9b52fdf8e 100644 --- a/test/System.Net.Http.Formatting.Test/Formatting/JsonMediaTypeFormatterTests.cs +++ b/test/System.Net.Http.Formatting.Test/Formatting/JsonMediaTypeFormatterTests.cs @@ -11,6 +11,7 @@ using System.Text; using System.Threading.Tasks; using Microsoft.TestCommon; +using Moq; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -576,6 +577,29 @@ public override Task WriteToStreamAsync_UsesCorrectCharacterEncoding(string cont formatter, content, formattedContent, mediaType, encoding, isDefaultEncoding); } +#if NET6_0_OR_GREATER + // Cannot Mock a Stream and let JsonWriter write to it. Writer will use ReadOnlySpan in this case and such + // parameters are not currently mockable. See moq/moq4#829, moq/moq4#979, and dotnet/runtime#45152. + // Override here avoids the Mock and should confirm this Stream is not closed. Also adds an + // additional check of the written text. + [Fact] + public override async Task WriteToStreamAsync_WhenObjectIsNull_WritesDataButDoesNotCloseStream() + { + // Arrange + JsonMediaTypeFormatter formatter = CreateFormatter(); + Stream stream = new MemoryStream(); + HttpContent content = new StringContent(String.Empty); + + // Act + await formatter.WriteToStreamAsync(typeof(SampleType), null, stream, content, null); + + // Assert (stream will throw if it has been closed) + stream.Position = 0; + using var reader = new StreamReader(stream); + Assert.Equal("null", reader.ReadToEnd()); + } +#endif + public class TestJsonMediaTypeFormatter : JsonMediaTypeFormatter { public TestJsonMediaTypeFormatter() diff --git a/test/System.Net.Http.Formatting.Test/Handlers/ProgressMessageHandlerTest.cs b/test/System.Net.Http.Formatting.Test/Handlers/ProgressMessageHandlerTest.cs index 36f50cde6..0947270c3 100644 --- a/test/System.Net.Http.Formatting.Test/Handlers/ProgressMessageHandlerTest.cs +++ b/test/System.Net.Http.Formatting.Test/Handlers/ProgressMessageHandlerTest.cs @@ -56,8 +56,10 @@ public async Task SendAsync_DoesNotInsertSendProgressWithoutEntityOrHandlerPrese } [Theory] +#if !NET6_0_OR_GREATER // https://github.com/aspnet/AspNetWebStack/issues/386 [InlineData(false, false)] [InlineData(false, true)] +#endif [InlineData(true, false)] [InlineData(true, true)] public async Task SendAsync_InsertsReceiveProgressWhenResponseEntityPresent(bool insertResponseEntity, bool addReceiveProgressHandler) diff --git a/test/System.Net.Http.Formatting.Test/HttpClientExtensionsTest.cs b/test/System.Net.Http.Formatting.Test/HttpClientExtensionsTest.cs index a12ab0383..5007ff4ac 100644 --- a/test/System.Net.Http.Formatting.Test/HttpClientExtensionsTest.cs +++ b/test/System.Net.Http.Formatting.Test/HttpClientExtensionsTest.cs @@ -14,6 +14,12 @@ namespace System.Net.Http { public class HttpClientExtensionsTest { + private const string InvalidUriMessage = +#if NET6_0_OR_GREATER + "An invalid request URI was provided. Either the request URI must be an absolute URI or BaseAddress must be set."; +#else + "An invalid request URI was provided. The request URI must either be an absolute URI or BaseAddress must be set."; +#endif private readonly MediaTypeFormatter _formatter = new MockMediaTypeFormatter { CallBase = true }; private readonly HttpClient _client; private readonly MediaTypeHeaderValue _mediaTypeHeader = MediaTypeHeaderValue.Parse("foo/bar; charset=utf-16"); @@ -40,7 +46,7 @@ public void PostAsJsonAsync_String_WhenClientIsNull_ThrowsException() public void PostAsJsonAsync_String_WhenUriIsNull_ThrowsException() { Assert.Throws(() => _client.PostAsJsonAsync((string)null, new object()), - "An invalid request URI was provided. The request URI must either be an absolute URI or BaseAddress must be set."); + InvalidUriMessage); } [Fact] @@ -64,7 +70,7 @@ public void PostAsXmlAsync_String_WhenClientIsNull_ThrowsException() public void PostAsXmlAsync_String_WhenUriIsNull_ThrowsException() { Assert.Throws(() => _client.PostAsXmlAsync((string)null, new object()), - "An invalid request URI was provided. The request URI must either be an absolute URI or BaseAddress must be set."); + InvalidUriMessage); } [Fact] @@ -88,7 +94,7 @@ public void PostAsync_String_WhenClientIsNull_ThrowsException() public void PostAsync_String_WhenRequestUriIsNull_ThrowsException() { Assert.Throws(() => _client.PostAsync((string)null, new object(), new JsonMediaTypeFormatter(), "text/json"), - "An invalid request URI was provided. The request URI must either be an absolute URI or BaseAddress must be set."); + InvalidUriMessage); } [Fact] @@ -169,7 +175,7 @@ public void PutAsJsonAsync_String_WhenClientIsNull_ThrowsException() public void PutAsJsonAsync_String_WhenUriIsNull_ThrowsException() { Assert.Throws(() => _client.PutAsJsonAsync((string)null, new object()), - "An invalid request URI was provided. The request URI must either be an absolute URI or BaseAddress must be set."); + InvalidUriMessage); } [Fact] @@ -193,7 +199,7 @@ public void PutAsXmlAsync_String_WhenClientIsNull_ThrowsException() public void PutAsXmlAsync_String_WhenUriIsNull_ThrowsException() { Assert.Throws(() => _client.PutAsXmlAsync((string)null, new object()), - "An invalid request URI was provided. The request URI must either be an absolute URI or BaseAddress must be set."); + InvalidUriMessage); } [Fact] @@ -217,7 +223,7 @@ public void PutAsync_String_WhenClientIsNull_ThrowsException() public void PutAsync_String_WhenRequestUriIsNull_ThrowsException() { Assert.Throws(() => _client.PutAsync((string)null, new object(), new JsonMediaTypeFormatter(), "text/json"), - "An invalid request URI was provided. The request URI must either be an absolute URI or BaseAddress must be set."); + InvalidUriMessage); } [Fact] @@ -298,7 +304,7 @@ public void PostAsJsonAsync_Uri_WhenClientIsNull_ThrowsException() public void PostAsJsonAsync_Uri_WhenUriIsNull_ThrowsException() { Assert.Throws(() => _client.PostAsJsonAsync((Uri)null, new object()), - "An invalid request URI was provided. The request URI must either be an absolute URI or BaseAddress must be set."); + InvalidUriMessage); } [Fact] @@ -322,7 +328,7 @@ public void PostAsXmlAsync_Uri_WhenClientIsNull_ThrowsException() public void PostAsXmlAsync_Uri_WhenUriIsNull_ThrowsException() { Assert.Throws(() => _client.PostAsXmlAsync((Uri)null, new object()), - "An invalid request URI was provided. The request URI must either be an absolute URI or BaseAddress must be set."); + InvalidUriMessage); } [Fact] @@ -346,7 +352,7 @@ public void PostAsync_Uri_WhenClientIsNull_ThrowsException() public void PostAsync_Uri_WhenRequestUriIsNull_ThrowsException() { Assert.Throws(() => _client.PostAsync((Uri)null, new object(), new JsonMediaTypeFormatter(), "text/json"), - "An invalid request URI was provided. The request URI must either be an absolute URI or BaseAddress must be set."); + InvalidUriMessage); } [Fact] @@ -427,7 +433,7 @@ public void PutAsJsonAsync_Uri_WhenClientIsNull_ThrowsException() public void PutAsJsonAsync_Uri_WhenUriIsNull_ThrowsException() { Assert.Throws(() => _client.PutAsJsonAsync((Uri)null, new object()), - "An invalid request URI was provided. The request URI must either be an absolute URI or BaseAddress must be set."); + InvalidUriMessage); } [Fact] @@ -451,7 +457,7 @@ public void PutAsXmlAsync_Uri_WhenClientIsNull_ThrowsException() public void PutAsXmlAsync_Uri_WhenUriIsNull_ThrowsException() { Assert.Throws(() => _client.PutAsXmlAsync((Uri)null, new object()), - "An invalid request URI was provided. The request URI must either be an absolute URI or BaseAddress must be set."); + InvalidUriMessage); } [Fact] @@ -475,7 +481,7 @@ public void PutAsync_Uri_WhenClientIsNull_ThrowsException() public void PutAsync_Uri_WhenRequestUriIsNull_ThrowsException() { Assert.Throws(() => _client.PutAsync((Uri)null, new object(), new JsonMediaTypeFormatter(), "text/json"), - "An invalid request URI was provided. The request URI must either be an absolute URI or BaseAddress must be set."); + InvalidUriMessage); } [Fact] diff --git a/test/System.Net.Http.Formatting.Test/HttpMessageContentTests.cs b/test/System.Net.Http.Formatting.Test/HttpMessageContentTests.cs index a8b41b562..f5a60b5e0 100644 --- a/test/System.Net.Http.Formatting.Test/HttpMessageContentTests.cs +++ b/test/System.Net.Http.Formatting.Test/HttpMessageContentTests.cs @@ -164,6 +164,7 @@ public async Task SerializeRequestMultipleTimes() } } +#if !NET6_0_OR_GREATER // https://github.com/aspnet/AspNetWebStack/issues/386 [Fact] public async Task SerializeResponse() { @@ -185,6 +186,7 @@ public async Task SerializeResponseMultipleTimes() await ValidateResponse(instance, false); } } +#endif [Fact] public async Task SerializeRequestWithEntity() @@ -241,6 +243,7 @@ public async Task SerializeRequestAsync() } } +#if !NET6_0_OR_GREATER // https://github.com/aspnet/AspNetWebStack/issues/386 [Fact] public async Task SerializeResponseAsync() { @@ -251,6 +254,7 @@ public async Task SerializeResponseAsync() await ValidateResponse(instance, false); } } +#endif [Fact] public async Task SerializeRequestWithPortAndQueryAsync() diff --git a/test/System.Net.Http.Formatting.Test/Internal/TranscodingStreamTests.cs b/test/System.Net.Http.Formatting.Test/Internal/TranscodingStreamTests.cs index 7d6e0a506..4e50d4381 100644 --- a/test/System.Net.Http.Formatting.Test/Internal/TranscodingStreamTests.cs +++ b/test/System.Net.Http.Formatting.Test/Internal/TranscodingStreamTests.cs @@ -174,7 +174,7 @@ public void Dispose_WithLeaveOpenFalse_DisposesInnerStream() // Async -#if NETCOREAPP3_1 || NET5_0_OR_GREATER || NETSTANDARD2_1 +#if NETCOREAPP3_1_OR_GREATER || NETSTANDARD2_1 innerStream = new MemoryStream(); transcodingStream = new TranscodingStream(innerStream, Encoding.UTF8, Encoding.UTF8, leaveOpen: false); transcodingStream.DisposeAsync().GetAwaiter().GetResult(); @@ -196,7 +196,7 @@ public void Dispose_WithLeaveOpenTrue_DoesNotDisposeInnerStream() // Async -#if NETCOREAPP3_1 || NET5_0_OR_GREATER || NETSTANDARD2_1 +#if NETCOREAPP3_1_OR_GREATER || NETSTANDARD2_1 innerStream = new MemoryStream(); transcodingStream = new TranscodingStream(innerStream, Encoding.UTF8, Encoding.UTF8, leaveOpen: true); transcodingStream.DisposeAsync().GetAwaiter().GetResult(); diff --git a/test/System.Net.Http.Formatting.Test/System.Net.Http.Formatting.Test.csproj b/test/System.Net.Http.Formatting.Test/System.Net.Http.Formatting.Test.csproj index ab9d953a1..efadbbb6a 100644 --- a/test/System.Net.Http.Formatting.Test/System.Net.Http.Formatting.Test.csproj +++ b/test/System.Net.Http.Formatting.Test/System.Net.Http.Formatting.Test.csproj @@ -20,7 +20,7 @@ ..\..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll False - False + True From 979e6ac66302034c5907de2eee52c67bb87c3db5 Mon Sep 17 00:00:00 2001 From: Doug Bunting <6431421+dougbu@users.noreply.github.com> Date: Fri, 17 Feb 2023 12:14:39 -0800 Subject: [PATCH 37/54] Add `Content` to all `HttpResponseMessage`s (#387) - fix #386 - reenable `net6.0` tests disabled in #384 for this issue - also, check `Stream.CanSeek` less when calculating `HttpMessageContent.ContentLength` value - use inner `HttpContent.Headers.ContentLength` if available - this changes behaviour slightly for both requests and responses - observable as `HttpMessageContent.Headers.ContentLength!=null` for empty messages - for responses, avoids `ContentLength==null` versus `ContentLength==0` inconsistencies (depending on platform) - `ContentLength==null` may still occur in some corner cases (which existed before) - e.g. when inner `HttpContent` doesn't know its length and `ReadAsStreamAsync()` hasn't completed - main change means `HttpResponseMessage`s we expose to user code are consistent across platforms - note: user code won't see `EmptyContent` in `HttpResponseMessage`s we create --- .../HttpContentMessageExtensions.cs | 6 +++++- src/System.Net.Http.Formatting/HttpMessageContent.cs | 9 ++++++--- .../HttpRequestMessageExtensions.cs | 3 +++ .../Formatting/JsonMediaTypeFormatterTests.cs | 2 +- .../Handlers/ProgressMessageHandlerTest.cs | 5 ++--- .../Handlers/ProgressStreamTest.cs | 2 +- .../HttpMessageContentTests.cs | 12 ++++-------- test/System.Net.Http.Formatting.Test/ParserData.cs | 4 +++- .../Controllers/VoidResultConverterTest.cs | 3 ++- .../WebHostExceptionHandlerTests.cs | 3 ++- 10 files changed, 29 insertions(+), 20 deletions(-) diff --git a/src/System.Net.Http.Formatting/HttpContentMessageExtensions.cs b/src/System.Net.Http.Formatting/HttpContentMessageExtensions.cs index 99ebe4b92..ca883460b 100644 --- a/src/System.Net.Http.Formatting/HttpContentMessageExtensions.cs +++ b/src/System.Net.Http.Formatting/HttpContentMessageExtensions.cs @@ -451,7 +451,7 @@ private static HttpContent CreateHeaderFields(HttpHeaders source, HttpHeaders de Contract.Assert(destination != null, "destination headers cannot be null"); Contract.Assert(contentStream != null, "contentStream must be non null"); HttpContentHeaders contentHeaders = null; - HttpContent content = null; + HttpContent content; // Set the header fields foreach (KeyValuePair> header in source) @@ -481,6 +481,10 @@ private static HttpContent CreateHeaderFields(HttpHeaders source, HttpHeaders de content = new StreamContent(contentStream); contentHeaders.CopyTo(content.Headers); } + else + { + content = new StreamContent(Stream.Null); + } return content; } diff --git a/src/System.Net.Http.Formatting/HttpMessageContent.cs b/src/System.Net.Http.Formatting/HttpMessageContent.cs index d34ca72b9..839888a2e 100644 --- a/src/System.Net.Http.Formatting/HttpMessageContent.cs +++ b/src/System.Net.Http.Formatting/HttpMessageContent.cs @@ -205,6 +205,7 @@ protected override async Task SerializeToStreamAsync(Stream stream, TransportCon protected override bool TryComputeLength(out long length) { // We have four states we could be in: + // 0. We have content and it knows its ContentLength. // 1. We have content, but the task is still running or finished without success // 2. We have content, the task has finished successfully, and the stream came back as a null or non-seekable // 3. We have content, the task has finished successfully, and the stream is seekable, so we know its length @@ -214,11 +215,13 @@ protected override bool TryComputeLength(out long length) // For #3, we return true & the size of our headers + the content length // For #4, we return true & the size of our headers - bool hasContent = _streamTask.Value != null; length = 0; - // Cases #1, #2, #3 - if (hasContent) + if (Content?.Headers.ContentLength is not null) + { + length = (long)Content.Headers.ContentLength; // Case #0 + } + else if (_streamTask.Value is not null) { Stream readStream; if (!_streamTask.Value.TryGetResult(out readStream) // Case #1 diff --git a/src/System.Net.Http.Formatting/HttpRequestMessageExtensions.cs b/src/System.Net.Http.Formatting/HttpRequestMessageExtensions.cs index a503f148b..b2e568eaa 100644 --- a/src/System.Net.Http.Formatting/HttpRequestMessageExtensions.cs +++ b/src/System.Net.Http.Formatting/HttpRequestMessageExtensions.cs @@ -3,6 +3,7 @@ using System.ComponentModel; using System.Diagnostics.CodeAnalysis; +using System.IO; using System.Web.Http; namespace System.Net.Http @@ -29,6 +30,7 @@ public static HttpResponseMessage CreateResponse(this HttpRequestMessage request return new HttpResponseMessage { + Content = new StreamContent(Stream.Null), StatusCode = statusCode, RequestMessage = request }; @@ -49,6 +51,7 @@ public static HttpResponseMessage CreateResponse(this HttpRequestMessage request return new HttpResponseMessage { + Content = new StreamContent(Stream.Null), RequestMessage = request }; } diff --git a/test/System.Net.Http.Formatting.Test/Formatting/JsonMediaTypeFormatterTests.cs b/test/System.Net.Http.Formatting.Test/Formatting/JsonMediaTypeFormatterTests.cs index 9b52fdf8e..5a12c1132 100644 --- a/test/System.Net.Http.Formatting.Test/Formatting/JsonMediaTypeFormatterTests.cs +++ b/test/System.Net.Http.Formatting.Test/Formatting/JsonMediaTypeFormatterTests.cs @@ -588,7 +588,7 @@ public override async Task WriteToStreamAsync_WhenObjectIsNull_WritesDataButDoes // Arrange JsonMediaTypeFormatter formatter = CreateFormatter(); Stream stream = new MemoryStream(); - HttpContent content = new StringContent(String.Empty); + HttpContent content = new StreamContent(Stream.Null); // Act await formatter.WriteToStreamAsync(typeof(SampleType), null, stream, content, null); diff --git a/test/System.Net.Http.Formatting.Test/Handlers/ProgressMessageHandlerTest.cs b/test/System.Net.Http.Formatting.Test/Handlers/ProgressMessageHandlerTest.cs index 0947270c3..2984dbd4a 100644 --- a/test/System.Net.Http.Formatting.Test/Handlers/ProgressMessageHandlerTest.cs +++ b/test/System.Net.Http.Formatting.Test/Handlers/ProgressMessageHandlerTest.cs @@ -56,10 +56,8 @@ public async Task SendAsync_DoesNotInsertSendProgressWithoutEntityOrHandlerPrese } [Theory] -#if !NET6_0_OR_GREATER // https://github.com/aspnet/AspNetWebStack/issues/386 [InlineData(false, false)] [InlineData(false, true)] -#endif [InlineData(true, false)] [InlineData(true, true)] public async Task SendAsync_InsertsReceiveProgressWhenResponseEntityPresent(bool insertResponseEntity, bool addReceiveProgressHandler) @@ -86,7 +84,8 @@ public async Task SendAsync_InsertsReceiveProgressWhenResponseEntityPresent(bool } else { - Assert.Null(response.Content); + Assert.NotNull(response.Content); + Assert.Equal(0L, response.Content.Headers.ContentLength); } } } diff --git a/test/System.Net.Http.Formatting.Test/Handlers/ProgressStreamTest.cs b/test/System.Net.Http.Formatting.Test/Handlers/ProgressStreamTest.cs index a6de511b8..0c0b06110 100644 --- a/test/System.Net.Http.Formatting.Test/Handlers/ProgressStreamTest.cs +++ b/test/System.Net.Http.Formatting.Test/Handlers/ProgressStreamTest.cs @@ -274,7 +274,7 @@ internal static ProgressStream CreateProgressStream( Stream iStream = innerStream ?? new Mock().Object; ProgressMessageHandler pHandler = progressMessageHandler ?? new ProgressMessageHandler(); HttpRequestMessage req = request ?? new HttpRequestMessage(); - HttpResponseMessage rsp = response ?? new HttpResponseMessage(); + HttpResponseMessage rsp = response ?? new HttpResponseMessage() { Content = new StreamContent(Stream.Null) }; return new ProgressStream(iStream, pHandler, req, rsp); } diff --git a/test/System.Net.Http.Formatting.Test/HttpMessageContentTests.cs b/test/System.Net.Http.Formatting.Test/HttpMessageContentTests.cs index f5a60b5e0..2ef0d3113 100644 --- a/test/System.Net.Http.Formatting.Test/HttpMessageContentTests.cs +++ b/test/System.Net.Http.Formatting.Test/HttpMessageContentTests.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.IO; using System.Net.Http.Headers; using System.Threading.Tasks; using Microsoft.TestCommon; @@ -39,10 +40,8 @@ private static HttpResponseMessage CreateResponse(bool containsEntity) httpResponse.ReasonPhrase = ParserData.HttpReasonPhrase; httpResponse.Version = new Version("1.2"); AddMessageHeaders(httpResponse.Headers); - if (containsEntity) - { - httpResponse.Content = new StringContent(ParserData.HttpMessageEntity); - } + httpResponse.Content = + containsEntity ? new StringContent(ParserData.HttpMessageEntity) : new StreamContent(Stream.Null); return httpResponse; } @@ -76,6 +75,7 @@ private static async Task ValidateRequest(HttpContent content, bool containsEnti private static async Task ValidateResponse(HttpContent content, bool containsEntity) { Assert.Equal(ParserData.HttpResponseMediaType, content.Headers.ContentType); + long? length = content.Headers.ContentLength; Assert.NotNull(length); @@ -164,7 +164,6 @@ public async Task SerializeRequestMultipleTimes() } } -#if !NET6_0_OR_GREATER // https://github.com/aspnet/AspNetWebStack/issues/386 [Fact] public async Task SerializeResponse() { @@ -186,7 +185,6 @@ public async Task SerializeResponseMultipleTimes() await ValidateResponse(instance, false); } } -#endif [Fact] public async Task SerializeRequestWithEntity() @@ -243,7 +241,6 @@ public async Task SerializeRequestAsync() } } -#if !NET6_0_OR_GREATER // https://github.com/aspnet/AspNetWebStack/issues/386 [Fact] public async Task SerializeResponseAsync() { @@ -254,7 +251,6 @@ public async Task SerializeResponseAsync() await ValidateResponse(instance, false); } } -#endif [Fact] public async Task SerializeRequestWithPortAndQueryAsync() diff --git a/test/System.Net.Http.Formatting.Test/ParserData.cs b/test/System.Net.Http.Formatting.Test/ParserData.cs index b0bc1fd19..10c0b3617 100644 --- a/test/System.Net.Http.Formatting.Test/ParserData.cs +++ b/test/System.Net.Http.Formatting.Test/ParserData.cs @@ -198,7 +198,7 @@ public static TheoryDataSet InvalidStatusCodes ((int)HttpStatus).ToString() + " " + HttpReasonPhrase + - "\r\nN1: V1a, V1b, V1c, V1d, V1e\r\nN2: V2\r\n\r\n"; + "\r\nN1: V1a, V1b, V1c, V1d, V1e\r\nN2: V2\r\nContent-Length: 0\r\n\r\n"; public static readonly string HttpRequestWithEntity = HttpMethod + @@ -206,6 +206,7 @@ public static TheoryDataSet InvalidStatusCodes HttpHostName + "\r\nN1: V1a, V1b, V1c, V1d, V1e\r\nN2: V2\r\nContent-Type: " + TextContentType + + "\r\nContent-Length: 100" + "\r\n\r\n" + HttpMessageEntity; @@ -216,6 +217,7 @@ public static TheoryDataSet InvalidStatusCodes HttpReasonPhrase + "\r\nN1: V1a, V1b, V1c, V1d, V1e\r\nN2: V2\r\nContent-Type: " + TextContentType + + "\r\nContent-Length: 100" + "\r\n\r\n" + HttpMessageEntity; } diff --git a/test/System.Web.Http.Test/Controllers/VoidResultConverterTest.cs b/test/System.Web.Http.Test/Controllers/VoidResultConverterTest.cs index c05e5f29a..7622e931f 100644 --- a/test/System.Web.Http.Test/Controllers/VoidResultConverterTest.cs +++ b/test/System.Web.Http.Test/Controllers/VoidResultConverterTest.cs @@ -31,7 +31,8 @@ public void Convert_ReturnsResponseMessageWithRequestAssignedAndNoContentToRefle var result = _converter.Convert(_context, null); Assert.Equal(HttpStatusCode.NoContent, result.StatusCode); - Assert.Null(result.Content); + Assert.NotNull(result.Content); + Assert.Equal(0L, result.Content.Headers.ContentLength); Assert.Same(_request, result.RequestMessage); } } diff --git a/test/System.Web.Http.WebHost.Test/WebHostExceptionHandlerTests.cs b/test/System.Web.Http.WebHost.Test/WebHostExceptionHandlerTests.cs index 42e23eaf2..e6bcf94e3 100644 --- a/test/System.Web.Http.WebHost.Test/WebHostExceptionHandlerTests.cs +++ b/test/System.Web.Http.WebHost.Test/WebHostExceptionHandlerTests.cs @@ -220,7 +220,8 @@ public async Task HandleAsync_IfCatchBlockIsWebHostBufferedContent_WithCreateExc { Assert.NotNull(response); Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode); - Assert.Null(response.Content); + Assert.NotNull(response.Content); + Assert.Equal(0L, response.Content.Headers.ContentLength); Assert.Same(expectedRequest, response.RequestMessage); } } From 30c4ecee2ff30345dadfde7b1e46d0908c39cf59 Mon Sep 17 00:00:00 2001 From: Doug Bunting <6431421+dougbu@users.noreply.github.com> Date: Tue, 21 Feb 2023 12:36:28 -0800 Subject: [PATCH 38/54] Use -Svc pools from here on out (#388) - we _only_ service this repo --- .codeql.yml | 2 +- azure-pipelines.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.codeql.yml b/.codeql.yml index aac075630..53b9e8e43 100644 --- a/.codeql.yml +++ b/.codeql.yml @@ -42,7 +42,7 @@ jobs: - job: codeql displayName: CodeQL pool: - name: NetCore1ESPool-Internal + name: NetCore1ESPool-Svc-Internal demands: ImageOverride -equals windows.vs2019.amd64 timeoutInMinutes: 90 diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 2da1d8ad2..fbd694417 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -28,10 +28,10 @@ jobs: displayName: Build pool: ${{ if eq(variables['System.TeamProject'], 'public') }}: - name: NetCore-Public + name: NetCore-Svc-Public demands: ImageOverride -equals windows.vs2019.amd64.open ${{ else }}: - name: NetCore1ESPool-Internal + name: NetCore1ESPool-Svc-Internal demands: ImageOverride -equals windows.vs2019.amd64 timeoutInMinutes: 30 From eae75d60441a2ac666ce72b478edcb929a187297 Mon Sep 17 00:00:00 2001 From: Doug Bunting <6431421+dougbu@users.noreply.github.com> Date: Thu, 23 Feb 2023 20:06:51 -0800 Subject: [PATCH 39/54] Correct `ValidateStreamForReading(...)` (#390) - fix #389 - check `Stream` before first read attempt - check `CanRead` (not `CanSeek`) before second or later read attempts - add lots of tests of related scenarios - nit: correct a recent `HttpContentMessageExtensions` comment Apply suggestions from code review - specifically, correct an `HttpMessageContent` comment Co-authored-by: Chris Ross --- .../HttpContentMessageExtensions.cs | 3 +- .../HttpMessageContent.cs | 11 +- .../HttpMessageContentTests.cs | 298 ++++++++++++++++-- 3 files changed, 283 insertions(+), 29 deletions(-) diff --git a/src/System.Net.Http.Formatting/HttpContentMessageExtensions.cs b/src/System.Net.Http.Formatting/HttpContentMessageExtensions.cs index ca883460b..fdc518c54 100644 --- a/src/System.Net.Http.Formatting/HttpContentMessageExtensions.cs +++ b/src/System.Net.Http.Formatting/HttpContentMessageExtensions.cs @@ -467,7 +467,8 @@ private static HttpContent CreateHeaderFields(HttpHeaders source, HttpHeaders de } } - // If we have content headers then create an HttpContent for this Response + // If we have content headers then create an HttpContent for this request or response. Otherwise, + // provide a HttpContent instance to overwrite the null or EmptyContent value. if (contentHeaders != null) { // Need to rewind the input stream to be at the position right after the HTTP header diff --git a/src/System.Net.Http.Formatting/HttpMessageContent.cs b/src/System.Net.Http.Formatting/HttpMessageContent.cs index 839888a2e..c182d40c8 100644 --- a/src/System.Net.Http.Formatting/HttpMessageContent.cs +++ b/src/System.Net.Http.Formatting/HttpMessageContent.cs @@ -359,12 +359,21 @@ private byte[] SerializeHeader() private void ValidateStreamForReading(Stream stream) { + // Stream is null case should be an extreme, incredibly unlikely corner case. Every HttpContent from + // the framework (see dotnet/runtime or .NET Framework reference source) provides a non-null Stream + // in the ReadAsStreamAsync task's return value. Likely need a poorly-designed derived HttpContent + // to hit this. Mostly ignoring the fact this message doesn't make much sense for the case. + if (stream is null || !stream.CanRead) + { + throw Error.NotSupported(Properties.Resources.NotSupported_UnreadableStream); + } + // If the content needs to be written to a target stream a 2nd time, then the stream must support // seeking (e.g. a FileStream), otherwise the stream can't be copied a second time to a target // stream (e.g. a NetworkStream). if (_contentConsumed) { - if (stream != null && stream.CanRead) + if (stream.CanSeek) { stream.Position = 0; } diff --git a/test/System.Net.Http.Formatting.Test/HttpMessageContentTests.cs b/test/System.Net.Http.Formatting.Test/HttpMessageContentTests.cs index 2ef0d3113..4206730b1 100644 --- a/test/System.Net.Http.Formatting.Test/HttpMessageContentTests.cs +++ b/test/System.Net.Http.Formatting.Test/HttpMessageContentTests.cs @@ -46,20 +46,34 @@ private static HttpResponseMessage CreateResponse(bool containsEntity) return httpResponse; } - private static async Task ReadContentAsync(HttpContent content) + private static async Task ReadContentAsync(HttpContent content, bool unBuffered = false) { - await content.LoadIntoBufferAsync(); + if (unBuffered) + { + var stream = new MemoryStream(); + await content.CopyToAsync(stream); + stream.Position = 0L; + + // StreamReader will dispose of the Stream. + using var reader = new StreamReader(stream); + + return await reader.ReadToEndAsync(); + } + else + { + await content.LoadIntoBufferAsync(); - return await content.ReadAsStringAsync(); + return await content.ReadAsStringAsync(); + } } - private static async Task ValidateRequest(HttpContent content, bool containsEntity) + private static async Task ValidateRequest(HttpContent content, bool containsEntity, bool unBuffered = false) { Assert.Equal(ParserData.HttpRequestMediaType, content.Headers.ContentType); long? length = content.Headers.ContentLength; Assert.NotNull(length); - string message = await ReadContentAsync(content); + string message = await ReadContentAsync(content, unBuffered); if (containsEntity) { Assert.Equal(ParserData.HttpRequestWithEntity.Length, length); @@ -72,14 +86,14 @@ private static async Task ValidateRequest(HttpContent content, bool containsEnti } } - private static async Task ValidateResponse(HttpContent content, bool containsEntity) + private static async Task ValidateResponse(HttpContent content, bool containsEntity, bool unBuffered = false) { Assert.Equal(ParserData.HttpResponseMediaType, content.Headers.ContentType); long? length = content.Headers.ContentLength; Assert.NotNull(length); - string message = await ReadContentAsync(content); + string message = await ReadContentAsync(content, unBuffered); if (containsEntity) { Assert.Equal(ParserData.HttpResponseWithEntity.Length, length); @@ -153,14 +167,16 @@ public async Task SerializeRequestWithExistingHostHeader() Assert.Equal(ParserData.HttpRequestWithHost, message); } - [Fact] - public async Task SerializeRequestMultipleTimes() + [Theory] + [InlineData(false)] + [InlineData(true)] + public async Task SerializeRequestMultipleTimes(bool unBuffered) { - HttpRequestMessage request = CreateRequest(ParserData.HttpRequestUri, false); - HttpMessageContent instance = new HttpMessageContent(request); + HttpRequestMessage request = CreateRequest(ParserData.HttpRequestUri, containsEntity: false); + HttpMessageContent instance = new(request); for (int cnt = 0; cnt < iterations; cnt++) { - await ValidateRequest(instance, false); + await ValidateRequest(instance, containsEntity: false, unBuffered); } } @@ -175,14 +191,16 @@ public async Task SerializeResponse() } } - [Fact] - public async Task SerializeResponseMultipleTimes() + [Theory] + [InlineData(false)] + [InlineData(true)] + public async Task SerializeResponseMultipleTimes(bool unBuffered) { - HttpResponseMessage response = CreateResponse(false); - HttpMessageContent instance = new HttpMessageContent(response); + HttpResponseMessage response = CreateResponse(containsEntity: false); + HttpMessageContent instance = new(response); for (int cnt = 0; cnt < iterations; cnt++) { - await ValidateResponse(instance, false); + await ValidateResponse(instance, containsEntity: false, unBuffered); } } @@ -197,14 +215,16 @@ public async Task SerializeRequestWithEntity() } } - [Fact] - public async Task SerializeRequestWithEntityMultipleTimes() + [Theory] + [InlineData(false)] + [InlineData(true)] + public async Task SerializeRequestWithEntityMultipleTimes(bool unBuffered) { - HttpRequestMessage request = CreateRequest(ParserData.HttpRequestUri, true); - HttpMessageContent instance = new HttpMessageContent(request); + HttpRequestMessage request = CreateRequest(ParserData.HttpRequestUri, containsEntity: true); + HttpMessageContent instance = new(request); for (int cnt = 0; cnt < iterations; cnt++) { - await ValidateRequest(instance, true); + await ValidateRequest(instance, containsEntity: true, unBuffered); } } @@ -219,14 +239,16 @@ public async Task SerializeResponseWithEntity() } } - [Fact] - public async Task SerializeResponseWithEntityMultipleTimes() + [Theory] + [InlineData(false)] + [InlineData(true)] + public async Task SerializeResponseWithEntityMultipleTimes(bool unBuffered) { - HttpResponseMessage response = CreateResponse(true); - HttpMessageContent instance = new HttpMessageContent(response); + HttpResponseMessage response = CreateResponse(containsEntity: true); + HttpMessageContent instance = new(response); for (int cnt = 0; cnt < iterations; cnt++) { - await ValidateResponse(instance, true); + await ValidateResponse(instance, containsEntity: true, unBuffered); } } @@ -303,5 +325,227 @@ public void DisposeInnerHttpResponseMessage() instance.Dispose(); Assert.ThrowsObjectDisposed(() => { response.StatusCode = HttpStatusCode.OK; }, typeof(HttpResponseMessage).FullName); } + + [Fact] + public void Request_ContentLengthNull_IfReadOnlyStream() + { + var request = CreateRequest(ParserData.HttpRequestUri, containsEntity: false); + request.Content = new StreamContent(new ReadOnlyStream()); + var instance = new HttpMessageContent(request); + + var length = instance.Headers.ContentLength; + + Assert.Null(length); + } + + [Fact] + public void Response_ContentLengthNull_IfReadOnlyStream() + { + var response = CreateResponse(containsEntity: false); + response.Content = new StreamContent(new ReadOnlyStream()); + var instance = new HttpMessageContent(response); + + var length = instance.Headers.ContentLength; + + Assert.Null(length); + } + + // Also confirms content can be serialized multiple times if either buffered or involves a seekable Stream. + [Theory] + [InlineData(false, true)] + [InlineData(true, false)] + public async Task Request_NoContentLength_IfNotRequested(bool readOnlyStream, bool unBuffered) + { + var request = CreateRequest(ParserData.HttpRequestUri, containsEntity: false); + if (readOnlyStream) + { + request.Content = new StreamContent(new ReadOnlyStream()); + } + var instance = new HttpMessageContent(request); + + for (int cnt = 0; cnt < iterations; cnt++) + { + var contentString = await ReadContentAsync(instance, unBuffered); + + Assert.Equal(ParserData.HttpRequest.Replace("Content-Length: 0\r\n", ""), contentString); + } + } + + // Also confirms content can be serialized multiple times if either buffered or involves a seekable Stream. + [Theory] + [InlineData(false, true)] + [InlineData(true, false)] + public async Task Response_NoContentLength_IfNotRequested(bool readOnlyStream, bool unBuffered) + { + var response = CreateResponse(containsEntity: false); + if (readOnlyStream) + { + response.Content = new StreamContent(new ReadOnlyStream()); + } + var instance = new HttpMessageContent(response); + + for (int cnt = 0; cnt < iterations; cnt++) + { + var contentString = await ReadContentAsync(instance, unBuffered); + + Assert.Equal(ParserData.HttpResponse.Replace("Content-Length: 0\r\n", ""), contentString); + } + } + + // Covers the false, false case of Request_NoContentLength_IfNotRequested(...). + [Fact] + public async Task Request_HasContentLength_IfBuffered_EvenIfNotRequested() + { + var request = CreateRequest(ParserData.HttpRequestUri, containsEntity: false); + var instance = new HttpMessageContent(request); + for (int cnt = 0; cnt < iterations; cnt++) + { + var contentString = await ReadContentAsync(instance, unBuffered: false); + + Assert.Equal(ParserData.HttpRequest, contentString); + } + } + + // Covers the false, false case of Response_NoContentLength_IfNotRequested(...). + [Fact] + public async Task Response_HasContentLength_IfBuffered_EvenIfNotRequested() + { + var response = CreateResponse(containsEntity: false); + var instance = new HttpMessageContent(response); + for (int cnt = 0; cnt < iterations; cnt++) + { + var contentString = await ReadContentAsync(instance, unBuffered: false); + + Assert.Equal(ParserData.HttpResponse, contentString); + } + } + + // Covers the true, true case of Request_NoContentLength_IfNotRequested(...). + [Fact] + public async Task Request_CannotSerializeMultipleTimes_IfNotBufferedAndNotSeekable() + { + var request = CreateRequest(ParserData.HttpRequestUri, containsEntity: false); + request.Content = new StreamContent(new ReadOnlyStream()); + var instance = new HttpMessageContent(request); + + // Act #1 + var contentString = await ReadContentAsync(instance, unBuffered: true); + + // Assert #1 + Assert.Equal(ParserData.HttpRequest.Replace("Content-Length: 0\r\n", ""), contentString); + + // Act #2 + await Assert.ThrowsAsync( + () => ReadContentAsync(instance, unBuffered: true), + "The 'HttpContent' of the 'HttpRequestMessage' has already been read."); + } + + // Covers the true, true case of Response_NoContentLength_IfNotRequested(...). + [Fact] + public async Task Response_CannotSerializeMultipleTimes_IfNotBufferedAndNotSeekable() + { + var response = CreateResponse(containsEntity: false); + response.Content = new StreamContent(new ReadOnlyStream()); + var instance = new HttpMessageContent(response); + + // Act #1 + var contentString = await ReadContentAsync(instance, unBuffered: true); + + // Assert #1 + Assert.Equal(ParserData.HttpResponse.Replace("Content-Length: 0\r\n", ""), contentString); + + // Act #2 + await Assert.ThrowsAsync( + () => ReadContentAsync(instance, unBuffered: true), + "The 'HttpContent' of the 'HttpResponseMessage' has already been read."); + } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public async Task Request_CannotSerialize_IfWriteOnlyStream(bool unBuffered) + { + var request = CreateRequest(ParserData.HttpRequestUri, containsEntity: false); + request.Content = new StreamContent(new WriteOnlyStream()); + var instance = new HttpMessageContent(request); + + await Assert.ThrowsAsync( + () => ReadContentAsync(instance, unBuffered), + "Stream does not support reading."); + } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public async Task Response_CannotSerialize_IfWriteOnlyStream(bool unBuffered) + { + var response = CreateResponse(containsEntity: false); + response.Content = new StreamContent(new WriteOnlyStream()); + var instance = new HttpMessageContent(response); + + await Assert.ThrowsAsync( + () => ReadContentAsync(instance, unBuffered), + "Stream does not support reading."); + } + + // Unlike Stream.Null, this stream does not support seeking. Bit more like (say) a network stream or + // the EmptyReadStream introduced in .NET 5. Note: EmptyReadStream should never be visible to our code + // because HttpContentMessageExtensions and HttpRequestMessageExtensions overwrite + // HttpResponseMessage.Content (or HttpRequestMessage.Content in one case) when creating an instance. + private class ReadOnlyStream : Stream + { + public override bool CanRead => true; + public override bool CanSeek => false; + public override bool CanWrite => false; + public override long Length => throw new NotImplementedException(); + public override long Position + { + get => throw new NotImplementedException(); + set => throw new NotImplementedException(); + } + + public override void Flush() + { + // Do nothing. + } + + public override int Read(byte[] buffer, int offset, int count) => 0; + + public override long Seek(long offset, SeekOrigin origin) => throw new NotImplementedException(); + + public override void SetLength(long value) => throw new NotImplementedException(); + + public override void Write(byte[] buffer, int offset, int count) => throw new NotImplementedException(); + } + + // Unlike Stream.Null, this stream does not support seeking. Bit more like (say) a network stream. + private class WriteOnlyStream : Stream + { + public override bool CanRead => false; + public override bool CanSeek => false; + public override bool CanWrite => true; + public override long Length => throw new NotImplementedException(); + public override long Position + { + get => throw new NotImplementedException(); + set => throw new NotImplementedException(); + } + + public override void Flush() + { + // Do nothing. + } + + public override int Read(byte[] buffer, int offset, int count) => throw new NotImplementedException(); + + public override long Seek(long offset, SeekOrigin origin) => throw new NotImplementedException(); + + public override void SetLength(long value) => throw new NotImplementedException(); + + public override void Write(byte[] buffer, int offset, int count) + { + // Ignore all parameters and do nothing. + } + } } } From d56a97f59325f63632a48a5a142e4e2f0d96398f Mon Sep 17 00:00:00 2001 From: Doug Bunting <6431421+dougbu@users.noreply.github.com> Date: Tue, 28 Feb 2023 11:52:52 -0800 Subject: [PATCH 40/54] Rename Formatting projects and more (#392) * Rename `netstandard` Formatting projects - Formatting.NetCore and Formatting.NetStandard names no longer make sense * Adjust `netstandard` Formatting output paths - align w/ new project names * Use `NETSTANDARD1_3` and `Testing_NetStandard1_3` - `NETFX_CORE` name no longer makes much sense - remove both `NETFX_CORE` C# defined constant and `msbuild` property - manually-defined constant completely unnecessary in src/ code * Remove RuntimePortable.sln - solution name no longer makes much sense and division adds little or no value - add .NET Standard projects to Runtime.sln - add solution filters for .NET Framework and .NET Standard projects - remove `$(BuildPortable)` property and `@(SolutionsToBuild)` item group --- .codeql.yml | 2 +- Runtime.NetFramework.slnf | 57 ++++++ Runtime.NetStandard.slnf | 12 ++ Runtime.msbuild | 37 ++-- Runtime.sln | 41 +++- RuntimePortable.sln | 76 -------- azure-pipelines.yml | 2 +- src/Common/CommonWebApiResources.Designer.cs | 2 +- src/Common/Error.cs | 2 +- src/Directory.Build.props | 2 +- .../ICloneable.cs | 0 .../MediaTypeHeaderValueExtensions.cs | 0 .../System.Net.Http.Formatting.ns1_3.csproj} | 4 +- .../System.Net.Http.Formatting.ns2_0.csproj} | 2 +- .../Formatting/BaseJsonMediaTypeFormatter.cs | 2 +- .../Formatting/BsonMediaTypeFormatter.cs | 4 +- .../Formatting/JsonContractResolver.cs | 2 +- .../Formatting/JsonMediaTypeFormatter.cs | 10 +- .../Formatting/StringComparisonHelper.cs | 2 +- .../Formatting/XmlMediaTypeFormatter.cs | 2 +- .../FormattingUtilities.cs | 2 +- .../Handlers/ProgressStream.cs | 4 +- .../Internal/ByteRangeStream.cs | 4 +- .../Internal/DelegatingStream.cs | 4 +- .../Internal/HttpValueCollection.cs | 4 +- .../Internal/NonClosingDelegatingStream.cs | 2 +- .../Internal/TypeExtensions.cs | 12 +- .../InvalidByteRangeException.cs | 2 +- .../MimeBodyPart.cs | 2 +- .../Properties/AssemblyInfo.cs | 6 +- .../Properties/Resources.Designer.cs | 176 +++++++++--------- .../PushStreamContent.cs | 2 +- test/Directory.Build.props | 4 +- .../Directory.Build.props | 4 +- .../ExceptionAssertions.cs | 4 +- .../Microsoft.TestCommon.csproj | 14 +- .../Formatting/BsonMediaTypeFormatterTests.cs | 2 +- ...DataContractJsonMediaTypeFormatterTests.cs | 2 +- .../Formatting/JsonNetSerializationTest.cs | 4 +- .../Formatting/StringComparisonHelperTest.cs | 2 +- .../Formatting/XmlMediaTypeFormatterTests.cs | 2 +- .../Handlers/ProgressStreamTest.cs | 4 +- .../HttpContentMultipartExtensionsTests.cs | 4 +- .../Internal/ByteRangeStreamTest.cs | 2 +- .../Internal/DelegatingStreamTest.cs | 4 +- .../Internal/TranscodingStreamTests.cs | 2 +- .../PushStreamContentTest.cs | 4 +- ...tem.Net.Http.Formatting.ns1_3.Test.csproj} | 8 +- ...tem.Net.Http.Formatting.ns2_0.Test.csproj} | 4 +- tools/SkipStrongNames.xml | 4 +- 50 files changed, 285 insertions(+), 270 deletions(-) create mode 100644 Runtime.NetFramework.slnf create mode 100644 Runtime.NetStandard.slnf delete mode 100644 RuntimePortable.sln rename src/{System.Net.Http.Formatting.NetCore => System.Net.Http.Formatting.ns1_3}/ICloneable.cs (100%) rename src/{System.Net.Http.Formatting.NetCore => System.Net.Http.Formatting.ns1_3}/MediaTypeHeaderValueExtensions.cs (100%) rename src/{System.Net.Http.Formatting.NetCore/System.Net.Http.Formatting.NetCore.csproj => System.Net.Http.Formatting.ns1_3/System.Net.Http.Formatting.ns1_3.csproj} (96%) rename src/{System.Net.Http.Formatting.NetStandard/System.Net.Http.Formatting.NetStandard.csproj => System.Net.Http.Formatting.ns2_0/System.Net.Http.Formatting.ns2_0.csproj} (98%) rename test/{System.Net.Http.Formatting.NetCore.Test/System.Net.Http.Formatting.NetCore.Test.csproj => System.Net.Http.Formatting.ns1_3.Test/System.Net.Http.Formatting.ns1_3.Test.csproj} (89%) rename test/{System.Net.Http.Formatting.NetStandard.Test/System.Net.Http.Formatting.NetStandard.Test.csproj => System.Net.Http.Formatting.ns2_0.Test/System.Net.Http.Formatting.ns2_0.Test.csproj} (93%) diff --git a/.codeql.yml b/.codeql.yml index 53b9e8e43..65948ac75 100644 --- a/.codeql.yml +++ b/.codeql.yml @@ -57,7 +57,7 @@ jobs: - script: .\build.cmd EnableSkipStrongNames displayName: Windows Build - EnableSkipStrongNames - - script: .\build.cmd Build /p:BuildPortable=true + - script: .\build.cmd Build displayName: Windows Build - task: CodeQL3000Finalize@0 diff --git a/Runtime.NetFramework.slnf b/Runtime.NetFramework.slnf new file mode 100644 index 000000000..7b79711ff --- /dev/null +++ b/Runtime.NetFramework.slnf @@ -0,0 +1,57 @@ +{ + "solution": { + "path": "Runtime.sln", + "projects": [ + "src\\Microsoft.AspNet.Facebook\\Microsoft.AspNet.Facebook.csproj", + "src\\Microsoft.Web.Helpers\\Microsoft.Web.Helpers.csproj", + "src\\Microsoft.Web.Mvc\\Microsoft.Web.Mvc.csproj", + "src\\Microsoft.Web.WebPages.OAuth\\Microsoft.Web.WebPages.OAuth.csproj", + "src\\System.Net.Http.Formatting\\System.Net.Http.Formatting.csproj", + "src\\System.Web.Cors\\System.Web.Cors.csproj", + "src\\System.Web.Helpers\\System.Web.Helpers.csproj", + "src\\System.Web.Http.Cors\\System.Web.Http.Cors.csproj", + "src\\System.Web.Http.Owin\\System.Web.Http.Owin.csproj", + "src\\System.Web.Http.SelfHost\\System.Web.Http.SelfHost.csproj", + "src\\System.Web.Http.SignalR\\System.Web.Http.SignalR.csproj", + "src\\System.Web.Http.Tracing\\System.Web.Http.Tracing.csproj", + "src\\System.Web.Http.WebHost\\System.Web.Http.WebHost.csproj", + "src\\System.Web.Http\\System.Web.Http.csproj", + "src\\System.Web.Mvc\\System.Web.Mvc.csproj", + "src\\System.Web.Razor\\System.Web.Razor.csproj", + "src\\System.Web.WebPages.Administration\\System.Web.WebPages.Administration.csproj", + "src\\System.Web.WebPages.Deployment\\System.Web.WebPages.Deployment.csproj", + "src\\System.Web.WebPages.Razor\\System.Web.WebPages.Razor.csproj", + "src\\System.Web.WebPages\\System.Web.WebPages.csproj", + "src\\WebApiHelpPage\\VB\\WebApiHelpPageVB.vbproj", + "src\\WebApiHelpPage\\WebApiHelpPage.csproj", + "src\\WebMatrix.Data\\WebMatrix.Data.csproj", + "src\\WebMatrix.WebData\\WebMatrix.WebData.csproj", + "test\\Microsoft.AspNet.Facebook.Test\\Microsoft.AspNet.Facebook.Test.csproj", + "test\\Microsoft.TestCommon\\Microsoft.TestCommon.csproj", + "test\\Microsoft.Web.Helpers.Test\\Microsoft.Web.Helpers.Test.csproj", + "test\\Microsoft.Web.Mvc.Test\\Microsoft.Web.Mvc.Test.csproj", + "test\\Microsoft.Web.WebPages.OAuth.Test\\Microsoft.Web.WebPages.OAuth.Test.csproj", + "test\\System.Net.Http.Formatting.Test\\System.Net.Http.Formatting.Test.csproj", + "test\\System.Web.Cors.Test\\System.Web.Cors.Test.csproj", + "test\\System.Web.Helpers.Test\\System.Web.Helpers.Test.csproj", + "test\\System.Web.Http.Cors.Test\\System.Web.Http.Cors.Test.csproj", + "test\\System.Web.Http.Integration.Test\\System.Web.Http.Integration.Test.csproj", + "test\\System.Web.Http.Owin.Test\\System.Web.Http.Owin.Test.csproj", + "test\\System.Web.Http.SelfHost.Test\\System.Web.Http.SelfHost.Test.csproj", + "test\\System.Web.Http.SignalR.Test\\System.Web.Http.SignalR.Test.csproj", + "test\\System.Web.Http.Test\\System.Web.Http.Test.csproj", + "test\\System.Web.Http.Tracing.Test\\System.Web.Http.Tracing.Test.csproj", + "test\\System.Web.Http.WebHost.Test\\System.Web.Http.WebHost.Test.csproj", + "test\\System.Web.Mvc.Test\\System.Web.Mvc.Test.csproj", + "test\\System.Web.Razor.Test\\System.Web.Razor.Test.csproj", + "test\\System.Web.WebPages.Administration.Test\\System.Web.WebPages.Administration.Test.csproj", + "test\\System.Web.WebPages.Deployment.Test\\System.Web.WebPages.Deployment.Test.csproj", + "test\\System.Web.WebPages.Razor.Test\\System.Web.WebPages.Razor.Test.csproj", + "test\\System.Web.WebPages.Test\\System.Web.WebPages.Test.csproj", + "test\\WebApiHelpPage.Test\\WebApiHelpPage.Test.csproj", + "test\\WebApiHelpPage.VB.Test\\WebApiHelpPage.VB.Test.csproj", + "test\\WebMatrix.Data.Test\\WebMatrix.Data.Test.csproj", + "test\\WebMatrix.WebData.Test\\WebMatrix.WebData.Test.csproj" + ] + } +} \ No newline at end of file diff --git a/Runtime.NetStandard.slnf b/Runtime.NetStandard.slnf new file mode 100644 index 000000000..b8270ab3e --- /dev/null +++ b/Runtime.NetStandard.slnf @@ -0,0 +1,12 @@ +{ + "solution": { + "path": "Runtime.sln", + "projects": [ + "src\\System.Net.Http.Formatting.ns1_3\\System.Net.Http.Formatting.ns1_3.csproj", + "src\\System.Net.Http.Formatting.ns2_0\\System.Net.Http.Formatting.ns2_0.csproj", + "test\\Microsoft.TestCommon\\Microsoft.TestCommon.csproj", + "test\\System.Net.Http.Formatting.ns1_3.Test\\System.Net.Http.Formatting.ns1_3.Test.csproj", + "test\\System.Net.Http.Formatting.ns2_0.Test\\System.Net.Http.Formatting.ns2_0.Test.csproj" + ] + } +} \ No newline at end of file diff --git a/Runtime.msbuild b/Runtime.msbuild index e02860a28..c77f8bc72 100644 --- a/Runtime.msbuild +++ b/Runtime.msbuild @@ -8,7 +8,6 @@ Release true true - true true false false @@ -19,16 +18,6 @@ .nuget\NuGet.exe - - - $(BuildInParallel) - - - $(BuildInParallel) - true - - - @@ -49,9 +38,8 @@ @@ -66,10 +54,9 @@ - <_ToRestore Include="@(SolutionsToBuild)" /> + <_ToRestore Include="Runtime.sln" /> <_ToRestore Include="test\Microsoft.TestCommon\Microsoft.TestCommon.csproj" - AdditionalProperties="NetFX_Core=true" - Condition=" '$(BuildPortable)' == 'true' " /> + AdditionalProperties="Testing_NetStandard1_3=true" /> @@ -107,18 +93,17 @@ - <_TestDLLsXunit Include="bin\$(Configuration)\test\*.Test.dll" /> - <_TestDLLsXunit Include="bin\$(Configuration)\test\*\net4*\*.Test.dll" - Condition=" '$(BuildPortable)' == 'true' " /> + <_TestDLLsXunit Include="bin\$(Configuration)\test\*.Test.dll; + bin\$(Configuration)\test\*\net4*\*.Test.dll" /> <_XunitProject Include="tools\WebStack.testing.targets"> TestAssembly=%(_TestDLLsXunit.FullPath); XmlPath=$(TestResultsDirectory)%(_TestDLLsXunit.FileName)-XunitResults.xml - <_VSTestDLLs Include="bin\$(Configuration)\test\NetCore\**\*.Test.dll; - bin\$(Configuration)\test\NetStandard\**\*.Test.dll" - Exclude="bin\$(Configuration)\test\Net*\net4*\*.Test.dll" /> - <_XunitProject Include="tools\WebStack.testing.targets" Condition=" '$(BuildPortable)' == 'true' "> + <_VSTestDLLs Include="bin\$(Configuration)\test\ns1_3\**\*.Test.dll; + bin\$(Configuration)\test\ns2_0\**\*.Test.dll" + Exclude="bin\$(Configuration)\test\*\net4*\*.Test.dll" /> + <_XunitProject Include="tools\WebStack.testing.targets"> TestAssembly=%(_VSTestDLLs.FullPath); XmlPath=$(TestResultsDirectory)%(_VSTestDLLs.FileName)-$([System.String]::Copy('%(_VSTestDLLs.RecursiveDir)').Trim('\\'))-XunitResults.xml; UseVSTest=true diff --git a/Runtime.sln b/Runtime.sln index bd43f01fe..56de063a7 100644 --- a/Runtime.sln +++ b/Runtime.sln @@ -57,7 +57,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Web.Http.Test", "tes EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Net.Http.Formatting", "src\System.Net.Http.Formatting\System.Net.Http.Formatting.csproj", "{668E9021-CE84-49D9-98FB-DF125A9FCDB0}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.TestCommon", "test\Microsoft.TestCommon\Microsoft.TestCommon.csproj", "{FCCC4CB7-BAF7-4A57-9F89-E5766FE536C0}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.TestCommon", "test\Microsoft.TestCommon\Microsoft.TestCommon.csproj", "{FCCC4CB7-BAF7-4A57-9F89-E5766FE536C0}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Net.Http.Formatting.Test", "test\System.Net.Http.Formatting.Test\System.Net.Http.Formatting.Test.csproj", "{7AF77741-9158-4D5F-8782-8F21FADF025F}" EndProject @@ -95,8 +95,9 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Web.Http.Owin", "src EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Web.Http.Owin.Test", "test\System.Web.Http.Owin.Test\System.Web.Http.Owin.Test.csproj", "{C19267DD-3984-430C-AE18-4034F85DE4E5}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{CB34D534-9A09-4EE4-B350-C1C23AFBF5EE}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution items", "Solution items", "{CB34D534-9A09-4EE4-B350-C1C23AFBF5EE}" ProjectSection(SolutionItems) = preProject + global.json = global.json NuGet.Config = NuGet.Config .nuget\packages.config = .nuget\packages.config EndProjectSection @@ -113,6 +114,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.Facebook", EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.Facebook.Test", "test\Microsoft.AspNet.Facebook.Test\Microsoft.AspNet.Facebook.Test.csproj", "{C3BEF382-C7C4-454D-B017-1EAC03E9A82C}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Net.Http.Formatting.ns1_3", "src\System.Net.Http.Formatting.ns1_3\System.Net.Http.Formatting.ns1_3.csproj", "{5ABD9968-F3A3-4967-B768-A6142F69759E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Net.Http.Formatting.ns2_0", "src\System.Net.Http.Formatting.ns2_0\System.Net.Http.Formatting.ns2_0.csproj", "{9AAFB58C-B8C1-4D7F-80E6-7B95C94A829B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Net.Http.Formatting.ns1_3.Test", "test\System.Net.Http.Formatting.ns1_3.Test\System.Net.Http.Formatting.ns1_3.Test.csproj", "{A1A20049-04C2-4676-93CF-92449C4BBAA9}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Net.Http.Formatting.ns2_0.Test", "test\System.Net.Http.Formatting.ns2_0.Test\System.Net.Http.Formatting.ns2_0.Test.csproj", "{6C320AD9-F380-4F8B-85F9-0689F88766EC}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution CodeAnalysis|Any CPU = CodeAnalysis|Any CPU @@ -420,6 +429,30 @@ Global {C3BEF382-C7C4-454D-B017-1EAC03E9A82C}.Debug|Any CPU.Build.0 = Debug|Any CPU {C3BEF382-C7C4-454D-B017-1EAC03E9A82C}.Release|Any CPU.ActiveCfg = Release|Any CPU {C3BEF382-C7C4-454D-B017-1EAC03E9A82C}.Release|Any CPU.Build.0 = Release|Any CPU + {5ABD9968-F3A3-4967-B768-A6142F69759E}.CodeAnalysis|Any CPU.ActiveCfg = CodeAnalysis|Any CPU + {5ABD9968-F3A3-4967-B768-A6142F69759E}.CodeAnalysis|Any CPU.Build.0 = CodeAnalysis|Any CPU + {5ABD9968-F3A3-4967-B768-A6142F69759E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5ABD9968-F3A3-4967-B768-A6142F69759E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5ABD9968-F3A3-4967-B768-A6142F69759E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5ABD9968-F3A3-4967-B768-A6142F69759E}.Release|Any CPU.Build.0 = Release|Any CPU + {9AAFB58C-B8C1-4D7F-80E6-7B95C94A829B}.CodeAnalysis|Any CPU.ActiveCfg = CodeAnalysis|Any CPU + {9AAFB58C-B8C1-4D7F-80E6-7B95C94A829B}.CodeAnalysis|Any CPU.Build.0 = CodeAnalysis|Any CPU + {9AAFB58C-B8C1-4D7F-80E6-7B95C94A829B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9AAFB58C-B8C1-4D7F-80E6-7B95C94A829B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9AAFB58C-B8C1-4D7F-80E6-7B95C94A829B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9AAFB58C-B8C1-4D7F-80E6-7B95C94A829B}.Release|Any CPU.Build.0 = Release|Any CPU + {A1A20049-04C2-4676-93CF-92449C4BBAA9}.CodeAnalysis|Any CPU.ActiveCfg = CodeAnalysis|Any CPU + {A1A20049-04C2-4676-93CF-92449C4BBAA9}.CodeAnalysis|Any CPU.Build.0 = CodeAnalysis|Any CPU + {A1A20049-04C2-4676-93CF-92449C4BBAA9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A1A20049-04C2-4676-93CF-92449C4BBAA9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A1A20049-04C2-4676-93CF-92449C4BBAA9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A1A20049-04C2-4676-93CF-92449C4BBAA9}.Release|Any CPU.Build.0 = Release|Any CPU + {6C320AD9-F380-4F8B-85F9-0689F88766EC}.CodeAnalysis|Any CPU.ActiveCfg = CodeAnalysis|Any CPU + {6C320AD9-F380-4F8B-85F9-0689F88766EC}.CodeAnalysis|Any CPU.Build.0 = CodeAnalysis|Any CPU + {6C320AD9-F380-4F8B-85F9-0689F88766EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6C320AD9-F380-4F8B-85F9-0689F88766EC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6C320AD9-F380-4F8B-85F9-0689F88766EC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6C320AD9-F380-4F8B-85F9-0689F88766EC}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -475,6 +508,10 @@ Global {1E89A3E9-0A7F-418F-B4BE-6E38A6315373} = {C40883CD-366D-4534-8B58-3EA0D13136DF} {821A136C-7C6F-44C6-A9E6-C39B5BFB1483} = {A9836F9E-6DB3-4D9F-ADCA-CF42D8C8BA93} {C3BEF382-C7C4-454D-B017-1EAC03E9A82C} = {C40883CD-366D-4534-8B58-3EA0D13136DF} + {5ABD9968-F3A3-4967-B768-A6142F69759E} = {A9836F9E-6DB3-4D9F-ADCA-CF42D8C8BA93} + {9AAFB58C-B8C1-4D7F-80E6-7B95C94A829B} = {A9836F9E-6DB3-4D9F-ADCA-CF42D8C8BA93} + {A1A20049-04C2-4676-93CF-92449C4BBAA9} = {C40883CD-366D-4534-8B58-3EA0D13136DF} + {6C320AD9-F380-4F8B-85F9-0689F88766EC} = {C40883CD-366D-4534-8B58-3EA0D13136DF} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {A855CFDC-9BEE-43A9-A3EA-4C4624A747DB} diff --git a/RuntimePortable.sln b/RuntimePortable.sln deleted file mode 100644 index 6838937f7..000000000 --- a/RuntimePortable.sln +++ /dev/null @@ -1,76 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27116.1 -MinimumVisualStudioVersion = 15.0 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{A9836F9E-6DB3-4D9F-ADCA-CF42D8C8BA93}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{C40883CD-366D-4534-8B58-3EA0D13136DF}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.TestCommon", "test\Microsoft.TestCommon\Microsoft.TestCommon.csproj", "{FCCC4CB7-BAF7-4A57-9F89-E5766FE536C0}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Net.Http.Formatting.NetCore", "src\System.Net.Http.Formatting.NetCore\System.Net.Http.Formatting.NetCore.csproj", "{C7060639-719B-4BD2-8A37-2F146B5A0668}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Net.Http.Formatting.NetCore.Test", "test\System.Net.Http.Formatting.NetCore.Test\System.Net.Http.Formatting.NetCore.Test.csproj", "{8DA61DAC-FF7E-4CA1-93A0-6148DB66FD08}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Net.Http.Formatting.NetStandard", "src\System.Net.Http.Formatting.NetStandard\System.Net.Http.Formatting.NetStandard.csproj", "{636CA76A-C85C-42E2-B4AA-88046279B3CA}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Net.Http.Formatting.NetStandard.Test", "test\System.Net.Http.Formatting.NetStandard.Test\System.Net.Http.Formatting.NetStandard.Test.csproj", "{DECB05DF-B33A-44A0-B5DE-B14A8CE0740F}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{A72045D4-B048-4697-9535-C3A6EDCA85B9}" - ProjectSection(SolutionItems) = preProject - global.json = global.json - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - CodeAnalysis|Any CPU = CodeAnalysis|Any CPU - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {FCCC4CB7-BAF7-4A57-9F89-E5766FE536C0}.CodeAnalysis|Any CPU.ActiveCfg = CodeAnalysis|Any CPU - {FCCC4CB7-BAF7-4A57-9F89-E5766FE536C0}.CodeAnalysis|Any CPU.Build.0 = CodeAnalysis|Any CPU - {FCCC4CB7-BAF7-4A57-9F89-E5766FE536C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FCCC4CB7-BAF7-4A57-9F89-E5766FE536C0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FCCC4CB7-BAF7-4A57-9F89-E5766FE536C0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FCCC4CB7-BAF7-4A57-9F89-E5766FE536C0}.Release|Any CPU.Build.0 = Release|Any CPU - {C7060639-719B-4BD2-8A37-2F146B5A0668}.CodeAnalysis|Any CPU.ActiveCfg = CodeAnalysis|Any CPU - {C7060639-719B-4BD2-8A37-2F146B5A0668}.CodeAnalysis|Any CPU.Build.0 = CodeAnalysis|Any CPU - {C7060639-719B-4BD2-8A37-2F146B5A0668}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C7060639-719B-4BD2-8A37-2F146B5A0668}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C7060639-719B-4BD2-8A37-2F146B5A0668}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C7060639-719B-4BD2-8A37-2F146B5A0668}.Release|Any CPU.Build.0 = Release|Any CPU - {8DA61DAC-FF7E-4CA1-93A0-6148DB66FD08}.CodeAnalysis|Any CPU.ActiveCfg = CodeAnalysis|Any CPU - {8DA61DAC-FF7E-4CA1-93A0-6148DB66FD08}.CodeAnalysis|Any CPU.Build.0 = CodeAnalysis|Any CPU - {8DA61DAC-FF7E-4CA1-93A0-6148DB66FD08}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8DA61DAC-FF7E-4CA1-93A0-6148DB66FD08}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8DA61DAC-FF7E-4CA1-93A0-6148DB66FD08}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8DA61DAC-FF7E-4CA1-93A0-6148DB66FD08}.Release|Any CPU.Build.0 = Release|Any CPU - {636CA76A-C85C-42E2-B4AA-88046279B3CA}.CodeAnalysis|Any CPU.ActiveCfg = CodeAnalysis|Any CPU - {636CA76A-C85C-42E2-B4AA-88046279B3CA}.CodeAnalysis|Any CPU.Build.0 = CodeAnalysis|Any CPU - {636CA76A-C85C-42E2-B4AA-88046279B3CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {636CA76A-C85C-42E2-B4AA-88046279B3CA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {636CA76A-C85C-42E2-B4AA-88046279B3CA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {636CA76A-C85C-42E2-B4AA-88046279B3CA}.Release|Any CPU.Build.0 = Release|Any CPU - {DECB05DF-B33A-44A0-B5DE-B14A8CE0740F}.CodeAnalysis|Any CPU.ActiveCfg = CodeAnalysis|Any CPU - {DECB05DF-B33A-44A0-B5DE-B14A8CE0740F}.CodeAnalysis|Any CPU.Build.0 = CodeAnalysis|Any CPU - {DECB05DF-B33A-44A0-B5DE-B14A8CE0740F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DECB05DF-B33A-44A0-B5DE-B14A8CE0740F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DECB05DF-B33A-44A0-B5DE-B14A8CE0740F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DECB05DF-B33A-44A0-B5DE-B14A8CE0740F}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {FCCC4CB7-BAF7-4A57-9F89-E5766FE536C0} = {C40883CD-366D-4534-8B58-3EA0D13136DF} - {C7060639-719B-4BD2-8A37-2F146B5A0668} = {A9836F9E-6DB3-4D9F-ADCA-CF42D8C8BA93} - {8DA61DAC-FF7E-4CA1-93A0-6148DB66FD08} = {C40883CD-366D-4534-8B58-3EA0D13136DF} - {636CA76A-C85C-42E2-B4AA-88046279B3CA} = {A9836F9E-6DB3-4D9F-ADCA-CF42D8C8BA93} - {DECB05DF-B33A-44A0-B5DE-B14A8CE0740F} = {C40883CD-366D-4534-8B58-3EA0D13136DF} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {2A542E86-4A12-4997-B307-DEA9C7EE6539} - EndGlobalSection -EndGlobal diff --git a/azure-pipelines.yml b/azure-pipelines.yml index fbd694417..b4e242d3a 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -73,7 +73,7 @@ jobs: - script: .\build.cmd EnableSkipStrongNames displayName: Enable SkipStrongNames - - script: .\build.cmd $(_BuildTarget) /p:BuildPortable=true ^ + - script: .\build.cmd $(_BuildTarget) ^ /binaryLogger:artifacts/msbuild.binlog /p:Configuration=$(_Configuration) /p:StyleCopEnabled=$(_StyleCopEnabled) ^ /fileLoggerParameters:LogFile=artifacts/msbuild.log;Summary;Verbosity=minimal displayName: Build diff --git a/src/Common/CommonWebApiResources.Designer.cs b/src/Common/CommonWebApiResources.Designer.cs index 251eed2b4..6e1e476d6 100644 --- a/src/Common/CommonWebApiResources.Designer.cs +++ b/src/Common/CommonWebApiResources.Designer.cs @@ -40,7 +40,7 @@ internal CommonWebApiResources() { internal static global::System.Resources.ResourceManager ResourceManager { get { if (object.ReferenceEquals(resourceMan, null)) { -#if NETFX_CORE +#if NETSTANDARD1_3 var assembly = typeof(CommonWebApiResources).GetTypeInfo().Assembly; #else var assembly = typeof(CommonWebApiResources).Assembly; diff --git a/src/Common/Error.cs b/src/Common/Error.cs index f25b3d9b2..85449c142 100644 --- a/src/Common/Error.cs +++ b/src/Common/Error.cs @@ -262,7 +262,7 @@ internal static NotSupportedException NotSupported(string messageFormat, params return new NotSupportedException(Error.Format(messageFormat, messageArgs)); } -#if NETFX_CORE // InvalidEnumArgumentException not available in netstandard1.3. +#if NETSTANDARD1_3 // InvalidEnumArgumentException not available in netstandard1.3. internal class InvalidEnumArgumentException : ArgumentException { public InvalidEnumArgumentException() : this(null) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index c5c258a90..6785fd164 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -4,6 +4,6 @@ true false - v4.5 + v4.5 diff --git a/src/System.Net.Http.Formatting.NetCore/ICloneable.cs b/src/System.Net.Http.Formatting.ns1_3/ICloneable.cs similarity index 100% rename from src/System.Net.Http.Formatting.NetCore/ICloneable.cs rename to src/System.Net.Http.Formatting.ns1_3/ICloneable.cs diff --git a/src/System.Net.Http.Formatting.NetCore/MediaTypeHeaderValueExtensions.cs b/src/System.Net.Http.Formatting.ns1_3/MediaTypeHeaderValueExtensions.cs similarity index 100% rename from src/System.Net.Http.Formatting.NetCore/MediaTypeHeaderValueExtensions.cs rename to src/System.Net.Http.Formatting.ns1_3/MediaTypeHeaderValueExtensions.cs diff --git a/src/System.Net.Http.Formatting.NetCore/System.Net.Http.Formatting.NetCore.csproj b/src/System.Net.Http.Formatting.ns1_3/System.Net.Http.Formatting.ns1_3.csproj similarity index 96% rename from src/System.Net.Http.Formatting.NetCore/System.Net.Http.Formatting.NetCore.csproj rename to src/System.Net.Http.Formatting.ns1_3/System.Net.Http.Formatting.ns1_3.csproj index 615fd2326..70326ce1b 100644 --- a/src/System.Net.Http.Formatting.NetCore/System.Net.Http.Formatting.NetCore.csproj +++ b/src/System.Net.Http.Formatting.ns1_3/System.Net.Http.Formatting.ns1_3.csproj @@ -4,10 +4,10 @@ netstandard1.3 System.Net.Http System.Net.Http.Formatting - $(OutputPath)NetCore\ + $(OutputPath)ns1_3\ $(OutputPath)$(AssemblyName).xml false - $(DefineConstants);ASPNETMVC;NETFX_CORE + $(DefineConstants);ASPNETMVC 1591 false $(Configurations);CodeAnalysis diff --git a/src/System.Net.Http.Formatting.NetStandard/System.Net.Http.Formatting.NetStandard.csproj b/src/System.Net.Http.Formatting.ns2_0/System.Net.Http.Formatting.ns2_0.csproj similarity index 98% rename from src/System.Net.Http.Formatting.NetStandard/System.Net.Http.Formatting.NetStandard.csproj rename to src/System.Net.Http.Formatting.ns2_0/System.Net.Http.Formatting.ns2_0.csproj index ba3a97a38..b44945028 100644 --- a/src/System.Net.Http.Formatting.NetStandard/System.Net.Http.Formatting.NetStandard.csproj +++ b/src/System.Net.Http.Formatting.ns2_0/System.Net.Http.Formatting.ns2_0.csproj @@ -4,7 +4,7 @@ netstandard2.0 System.Net.Http System.Net.Http.Formatting - $(OutputPath)NetStandard\ + $(OutputPath)ns2_0\ $(OutputPath)$(AssemblyName).xml false $(DefineConstants);ASPNETMVC diff --git a/src/System.Net.Http.Formatting/Formatting/BaseJsonMediaTypeFormatter.cs b/src/System.Net.Http.Formatting/Formatting/BaseJsonMediaTypeFormatter.cs index 300716228..c25bdba46 100644 --- a/src/System.Net.Http.Formatting/Formatting/BaseJsonMediaTypeFormatter.cs +++ b/src/System.Net.Http.Formatting/Formatting/BaseJsonMediaTypeFormatter.cs @@ -19,7 +19,7 @@ namespace System.Net.Http.Formatting /// public abstract class BaseJsonMediaTypeFormatter : MediaTypeFormatter { - // Though MaxDepth is not supported in portable library, we still override JsonReader's MaxDepth + // Though MaxDepth is not supported in netstandard1.3, we still override JsonReader's MaxDepth private int _maxDepth = FormattingUtilities.DefaultMaxDepth; private readonly IContractResolver _defaultContractResolver; diff --git a/src/System.Net.Http.Formatting/Formatting/BsonMediaTypeFormatter.cs b/src/System.Net.Http.Formatting/Formatting/BsonMediaTypeFormatter.cs index b6d0a8351..c6eba6e45 100644 --- a/src/System.Net.Http.Formatting/Formatting/BsonMediaTypeFormatter.cs +++ b/src/System.Net.Http.Formatting/Formatting/BsonMediaTypeFormatter.cs @@ -73,7 +73,7 @@ public sealed override int MaxDepth } } -#if !NETFX_CORE // DBNull not supported in portable library; no need to override there +#if !NETSTANDARD1_3 // DBNull not supported in netstandard1.3; no need to override there /// public override Task ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger) { @@ -241,7 +241,7 @@ public override void WriteToStream(Type type, object value, Stream writeStream, return; } -#if !NETFX_CORE // DBNull not supported in portable library +#if !NETSTANDARD1_3 // DBNull not supported in netstandard1.3 if (value == DBNull.Value) { // ReadFromStreamAsync() override above converts null to DBNull.Value if given Type is DBNull; normally diff --git a/src/System.Net.Http.Formatting/Formatting/JsonContractResolver.cs b/src/System.Net.Http.Formatting/Formatting/JsonContractResolver.cs index dad07b236..2dd063842 100644 --- a/src/System.Net.Http.Formatting/Formatting/JsonContractResolver.cs +++ b/src/System.Net.Http.Formatting/Formatting/JsonContractResolver.cs @@ -30,7 +30,7 @@ public JsonContractResolver(MediaTypeFormatter formatter) _formatter = formatter; -#if !NETFX_CORE +#if !NETSTANDARD1_3 // Need this setting to have [Serializable] types serialized correctly IgnoreSerializableAttribute = false; #endif diff --git a/src/System.Net.Http.Formatting/Formatting/JsonMediaTypeFormatter.cs b/src/System.Net.Http.Formatting/Formatting/JsonMediaTypeFormatter.cs index 41344e9c8..775a78a32 100644 --- a/src/System.Net.Http.Formatting/Formatting/JsonMediaTypeFormatter.cs +++ b/src/System.Net.Http.Formatting/Formatting/JsonMediaTypeFormatter.cs @@ -215,13 +215,13 @@ public override object ReadFromStream(Type type, Stream readStream, Encoding eff DataContractJsonSerializer dataContractSerializer = GetDataContractSerializer(type); // JsonReaderWriterFactory is internal, CreateTextReader only supports auto-detecting the encoding - // and auto-detection fails in some cases for the NETFX_CORE project. In addition, DCS encodings are + // and auto-detection fails in some cases for the netstandard1.3 project. In addition, DCS encodings are // limited to UTF8, UTF16BE, and UTF16LE. Convert to UTF8 as we read. Stream innerStream = string.Equals(effectiveEncoding.WebName, Utf8Encoding.WebName, StringComparison.OrdinalIgnoreCase) ? new NonClosingDelegatingStream(readStream) : new TranscodingStream(readStream, effectiveEncoding, Utf8Encoding, leaveOpen: true); -#if NETFX_CORE +#if NETSTANDARD1_3 using (innerStream) { // Unfortunately, we're ignoring _readerQuotas. @@ -298,7 +298,7 @@ public override void WriteToStream(Type type, object value, Stream writeStream, else { // JsonReaderWriterFactory is internal and DataContractJsonSerializer only writes UTF8 for the - // NETFX_CORE project. In addition, DCS encodings are limited to UTF8, UTF16BE, and UTF16LE. + // netstandard1.3 project. In addition, DCS encodings are limited to UTF8, UTF16BE, and UTF16LE. // Convert to UTF8 as we write. using var innerStream = new TranscodingStream(writeStream, effectiveEncoding, Utf8Encoding, leaveOpen: true); WriteObject(innerStream, type, value); @@ -315,7 +315,7 @@ private void WriteObject(Stream stream, Type type, object value) DataContractJsonSerializer dataContractSerializer = GetDataContractSerializer(type); // Do not dispose of the stream. WriteToStream handles that where it's needed. -#if NETFX_CORE +#if NETSTANDARD1_3 dataContractSerializer.WriteObject(stream, value); #else using XmlWriter writer = JsonReaderWriterFactory.CreateJsonWriter(stream, Utf8Encoding, ownsStream: false); @@ -333,7 +333,7 @@ private DataContractJsonSerializer CreateDataContractSerializer(Type type, bool try { -#if !NETFX_CORE // XsdDataContractExporter is not supported in portable libraries +#if !NETSTANDARD1_3 // XsdDataContractExporter is not supported in netstandard1.3 // Verify that type is a valid data contract by forcing the serializer to try to create a data contract FormattingUtilities.XsdDataContractExporter.GetRootElementName(type); #endif diff --git a/src/System.Net.Http.Formatting/Formatting/StringComparisonHelper.cs b/src/System.Net.Http.Formatting/Formatting/StringComparisonHelper.cs index 8dade6d2d..8f45ee70c 100644 --- a/src/System.Net.Http.Formatting/Formatting/StringComparisonHelper.cs +++ b/src/System.Net.Http.Formatting/Formatting/StringComparisonHelper.cs @@ -23,7 +23,7 @@ public static bool IsDefined(StringComparison value) { return value == StringComparison.CurrentCulture || value == StringComparison.CurrentCultureIgnoreCase || -#if !NETFX_CORE +#if !NETSTANDARD1_3 value == StringComparison.InvariantCulture || value == StringComparison.InvariantCultureIgnoreCase || #endif diff --git a/src/System.Net.Http.Formatting/Formatting/XmlMediaTypeFormatter.cs b/src/System.Net.Http.Formatting/Formatting/XmlMediaTypeFormatter.cs index 9e858e5cb..77a68d69b 100644 --- a/src/System.Net.Http.Formatting/Formatting/XmlMediaTypeFormatter.cs +++ b/src/System.Net.Http.Formatting/Formatting/XmlMediaTypeFormatter.cs @@ -522,7 +522,7 @@ private object CreateDefaultSerializer(Type type, bool throwOnError) } else { -#if !NETFX_CORE // XsdDataContractExporter is not supported in portable libraries +#if !NETSTANDARD1_3 // XsdDataContractExporter is not supported in netstandard1.3 // REVIEW: Is there something comparable in WinRT? // Verify that type is a valid data contract by forcing the serializer to try to create a data contract FormattingUtilities.XsdDataContractExporter.GetRootElementName(type); diff --git a/src/System.Net.Http.Formatting/FormattingUtilities.cs b/src/System.Net.Http.Formatting/FormattingUtilities.cs index 897bcd21f..2d296a18c 100644 --- a/src/System.Net.Http.Formatting/FormattingUtilities.cs +++ b/src/System.Net.Http.Formatting/FormattingUtilities.cs @@ -114,7 +114,7 @@ internal static class FormattingUtilities /// public static readonly Type QueryableInterfaceGenericType = typeof(IQueryable<>); -#if !NETFX_CORE // XsdDataContractExporter is not supported in portable libraries +#if !NETSTANDARD1_3 // XsdDataContractExporter is not supported in netstandard1.3 /// /// An instance of . /// diff --git a/src/System.Net.Http.Formatting/Handlers/ProgressStream.cs b/src/System.Net.Http.Formatting/Handlers/ProgressStream.cs index 4ee57acf3..eff766608 100644 --- a/src/System.Net.Http.Formatting/Handlers/ProgressStream.cs +++ b/src/System.Net.Http.Formatting/Handlers/ProgressStream.cs @@ -68,7 +68,7 @@ public override async Task ReadAsync(byte[] buffer, int offset, int count, return readCount; } -#if !NETFX_CORE // BeginX and EndX are not supported on streams in portable libraries +#if !NETSTANDARD1_3 // BeginX and EndX are not supported on Streams in netstandard1.3 public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { return InnerStream.BeginRead(buffer, offset, count, callback, state); @@ -100,7 +100,7 @@ public override async Task WriteAsync(byte[] buffer, int offset, int count, Canc ReportBytesSent(count, userState: null); } -#if !NETFX_CORE // BeginX and EndX are not supported on streams in portable libraries +#if !NETSTANDARD1_3 // BeginX and EndX are not supported on Streams in netstandard1.3 public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { return new ProgressWriteAsyncResult(InnerStream, this, buffer, offset, count, callback, state); diff --git a/src/System.Net.Http.Formatting/Internal/ByteRangeStream.cs b/src/System.Net.Http.Formatting/Internal/ByteRangeStream.cs index bf3d4371f..a4fce9a3f 100644 --- a/src/System.Net.Http.Formatting/Internal/ByteRangeStream.cs +++ b/src/System.Net.Http.Formatting/Internal/ByteRangeStream.cs @@ -111,7 +111,7 @@ public override long Position } } -#if !NETFX_CORE // BeginX and EndX are not supported on streams in portable libraries +#if !NETSTANDARD1_3 // BeginX and EndX are not supported on Streams in netstandard1.3 public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { return base.BeginRead(buffer, offset, PrepareStreamForRangeRead(count), callback, state); @@ -174,7 +174,7 @@ public override void Write(byte[] buffer, int offset, int count) throw Error.NotSupported(Properties.Resources.ByteRangeStreamReadOnly); } -#if !NETFX_CORE // BeginX and EndX are not supported on streams in portable libraries +#if !NETSTANDARD1_3 // BeginX and EndX are not supported on Streams in netstandard1.3 public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { throw Error.NotSupported(Properties.Resources.ByteRangeStreamReadOnly); diff --git a/src/System.Net.Http.Formatting/Internal/DelegatingStream.cs b/src/System.Net.Http.Formatting/Internal/DelegatingStream.cs index ee0c51bde..0e713fdfd 100644 --- a/src/System.Net.Http.Formatting/Internal/DelegatingStream.cs +++ b/src/System.Net.Http.Formatting/Internal/DelegatingStream.cs @@ -97,7 +97,7 @@ public override Task ReadAsync(byte[] buffer, int offset, int count, Cancel return _innerStream.ReadAsync(buffer, offset, count, cancellationToken); } -#if !NETFX_CORE // BeginX and EndX not supported on Streams in portable libraries +#if !NETSTANDARD1_3 // BeginX and EndX not supported on Streams in netstandard1.3 public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { return _innerStream.BeginRead(buffer, offset, count, callback, state); @@ -139,7 +139,7 @@ public override Task WriteAsync(byte[] buffer, int offset, int count, Cancellati return _innerStream.WriteAsync(buffer, offset, count, cancellationToken); } -#if !NETFX_CORE // BeginX and EndX not supported on Streams in portable libraries +#if !NETSTANDARD1_3 // BeginX and EndX not supported on Streams in netstandard1.3 public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { return _innerStream.BeginWrite(buffer, offset, count, callback, state); diff --git a/src/System.Net.Http.Formatting/Internal/HttpValueCollection.cs b/src/System.Net.Http.Formatting/Internal/HttpValueCollection.cs index 72f28d4cd..082b33319 100644 --- a/src/System.Net.Http.Formatting/Internal/HttpValueCollection.cs +++ b/src/System.Net.Http.Formatting/Internal/HttpValueCollection.cs @@ -15,12 +15,12 @@ namespace System.Net.Http.Formatting.Internal /// /// NameValueCollection to represent form data and to generate form data output. /// -#if !NETFX_CORE // NameValueCollection is not serializable in netstandard1.3. +#if !NETSTANDARD1_3 // NameValueCollection is not serializable in netstandard1.3. [Serializable] #endif internal class HttpValueCollection : NameValueCollection { -#if !NETFX_CORE // NameValueCollection is not serializable in netstandard1.3. +#if !NETSTANDARD1_3 // NameValueCollection is not serializable in netstandard1.3. protected HttpValueCollection(SerializationInfo info, StreamingContext context) : base(info, context) { diff --git a/src/System.Net.Http.Formatting/Internal/NonClosingDelegatingStream.cs b/src/System.Net.Http.Formatting/Internal/NonClosingDelegatingStream.cs index 625bc8536..1d7599654 100644 --- a/src/System.Net.Http.Formatting/Internal/NonClosingDelegatingStream.cs +++ b/src/System.Net.Http.Formatting/Internal/NonClosingDelegatingStream.cs @@ -20,7 +20,7 @@ public NonClosingDelegatingStream(Stream innerStream) { } -#if NETFX_CORE +#if NETSTANDARD1_3 protected override void Dispose(bool disposing) { } diff --git a/src/System.Net.Http.Formatting/Internal/TypeExtensions.cs b/src/System.Net.Http.Formatting/Internal/TypeExtensions.cs index 0f22bfcea..aab7ca05c 100644 --- a/src/System.Net.Http.Formatting/Internal/TypeExtensions.cs +++ b/src/System.Net.Http.Formatting/Internal/TypeExtensions.cs @@ -8,7 +8,7 @@ namespace System.Net.Http { internal static class TypeExtensions { -#if NETFX_CORE +#if NETSTANDARD1_3 private static bool EqualTo(this Type[] t1, Type[] t2) { if (t1.Length != t2.Length) @@ -42,7 +42,7 @@ public static Type ExtractGenericInterface(this Type queryType, Type interfaceTy return (matchesInterface(queryType)) ? queryType : queryType.GetInterfaces().FirstOrDefault(matchesInterface); } -#if NETFX_CORE +#if NETSTANDARD1_3 public static Type[] GetGenericArguments(this Type type) { return type.GetTypeInfo().GenericTypeArguments; @@ -54,7 +54,7 @@ public static Type[] GetInterfaces(this Type type) } #endif -#if NETFX_CORE +#if NETSTANDARD1_3 public static bool IsAssignableFrom(this Type type, Type c) { return type.GetTypeInfo().IsAssignableFrom(c.GetTypeInfo()); @@ -63,7 +63,7 @@ public static bool IsAssignableFrom(this Type type, Type c) public static bool IsGenericType(this Type type) { -#if NETFX_CORE +#if NETSTANDARD1_3 return type.GetTypeInfo().IsGenericType; #else return type.IsGenericType; @@ -72,7 +72,7 @@ public static bool IsGenericType(this Type type) public static bool IsInterface(this Type type) { -#if NETFX_CORE +#if NETSTANDARD1_3 return type.GetTypeInfo().IsInterface; #else return type.IsInterface; @@ -81,7 +81,7 @@ public static bool IsInterface(this Type type) public static bool IsValueType(this Type type) { -#if NETFX_CORE +#if NETSTANDARD1_3 return type.GetTypeInfo().IsValueType; #else return type.IsValueType; diff --git a/src/System.Net.Http.Formatting/InvalidByteRangeException.cs b/src/System.Net.Http.Formatting/InvalidByteRangeException.cs index 7e7e677bf..ef6175208 100644 --- a/src/System.Net.Http.Formatting/InvalidByteRangeException.cs +++ b/src/System.Net.Http.Formatting/InvalidByteRangeException.cs @@ -35,7 +35,7 @@ public InvalidByteRangeException(ContentRangeHeaderValue contentRange, string me Initialize(contentRange); } -#if !NETFX_CORE // Exception is not serializable in netstandard1.3. +#if !NETSTANDARD1_3 // Exception is not serializable in netstandard1.3. public InvalidByteRangeException(ContentRangeHeaderValue contentRange, SerializationInfo info, StreamingContext context) : base(info, context) { diff --git a/src/System.Net.Http.Formatting/MimeBodyPart.cs b/src/System.Net.Http.Formatting/MimeBodyPart.cs index fcd4a7f94..cd07e8bba 100644 --- a/src/System.Net.Http.Formatting/MimeBodyPart.cs +++ b/src/System.Net.Http.Formatting/MimeBodyPart.cs @@ -190,7 +190,7 @@ private void CleanupOutputStream() } else { -#if NETFX_CORE +#if NETSTANDARD1_3 _outputStream.Dispose(); #else _outputStream.Close(); diff --git a/src/System.Net.Http.Formatting/Properties/AssemblyInfo.cs b/src/System.Net.Http.Formatting/Properties/AssemblyInfo.cs index 331be44ef..15d3a9add 100644 --- a/src/System.Net.Http.Formatting/Properties/AssemblyInfo.cs +++ b/src/System.Net.Http.Formatting/Properties/AssemblyInfo.cs @@ -14,10 +14,10 @@ [assembly: Guid("7fa1ae84-36e2-46b6-812c-c985a8e65e9a")] #if NETSTANDARD2_0 -[assembly: InternalsVisibleTo("System.Net.Http.Formatting.NetStandard.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")] -#elif NETFX_CORE +[assembly: InternalsVisibleTo("System.Net.Http.Formatting.ns2_0.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")] +#elif NETSTANDARD1_3 [assembly: InternalsVisibleTo("Microsoft.TestCommon, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")] -[assembly: InternalsVisibleTo("System.Net.Http.Formatting.NetCore.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")] +[assembly: InternalsVisibleTo("System.Net.Http.Formatting.ns1_3.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")] #else [assembly: InternalsVisibleTo("System.Net.Http.Formatting.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")] [assembly: InternalsVisibleTo("System.Net.Http.Formatting.Test.Integration, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")] diff --git a/src/System.Net.Http.Formatting/Properties/Resources.Designer.cs b/src/System.Net.Http.Formatting/Properties/Resources.Designer.cs index 194d4eff1..7a0bd97ba 100644 --- a/src/System.Net.Http.Formatting/Properties/Resources.Designer.cs +++ b/src/System.Net.Http.Formatting/Properties/Resources.Designer.cs @@ -11,8 +11,8 @@ namespace System.Net.Http.Properties { using System; using System.Reflection; - - + + /// /// A strongly-typed resource class, for looking up localized strings, etc. /// @@ -24,15 +24,15 @@ namespace System.Net.Http.Properties { [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { - + private static global::System.Resources.ResourceManager resourceMan; - + private static global::System.Globalization.CultureInfo resourceCulture; - + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal Resources() { } - + /// /// Returns the cached ResourceManager instance used by this class. /// @@ -40,7 +40,7 @@ internal Resources() { internal static global::System.Resources.ResourceManager ResourceManager { get { if (object.ReferenceEquals(resourceMan, null)) { -#if NETFX_CORE +#if NETSTANDARD1_3 var assembly = typeof(Resources).GetTypeInfo().Assembly; #else var assembly = typeof(Resources).Assembly; @@ -51,7 +51,7 @@ internal Resources() { return resourceMan; } } - + /// /// Overrides the current thread's CurrentUICulture property for all /// resource lookups using this strongly typed resource class. @@ -65,7 +65,7 @@ internal Resources() { resourceCulture = value; } } - + /// /// Looks up a localized string similar to Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection.. /// @@ -74,7 +74,7 @@ internal static string Argument_InvalidOffLen { return ResourceManager.GetString("Argument_InvalidOffLen", resourceCulture); } } - + /// /// Looks up a localized string similar to Async Callback threw an exception.. /// @@ -83,7 +83,7 @@ internal static string AsyncResult_CallbackThrewException { return ResourceManager.GetString("AsyncResult_CallbackThrewException", resourceCulture); } } - + /// /// Looks up a localized string similar to The IAsyncResult implementation '{0}' tried to complete a single operation multiple times. This could be caused by an incorrect application IAsyncResult implementation or other extensibility code, such as an IAsyncResult that returns incorrect CompletedSynchronously values or invokes the AsyncCallback multiple times.. /// @@ -92,7 +92,7 @@ internal static string AsyncResult_MultipleCompletes { return ResourceManager.GetString("AsyncResult_MultipleCompletes", resourceCulture); } } - + /// /// Looks up a localized string similar to End cannot be called twice on an AsyncResult.. /// @@ -101,7 +101,7 @@ internal static string AsyncResult_MultipleEnds { return ResourceManager.GetString("AsyncResult_MultipleEnds", resourceCulture); } } - + /// /// Looks up a localized string similar to An incorrect IAsyncResult was provided to an 'End' method. The IAsyncResult object passed to 'End' must be the one returned from the matching 'Begin' or passed to the callback provided to 'Begin'.. /// @@ -110,7 +110,7 @@ internal static string AsyncResult_ResultMismatch { return ResourceManager.GetString("AsyncResult_ResultMismatch", resourceCulture); } } - + /// /// Looks up a localized string similar to Found zero byte ranges. There must be at least one byte range provided.. /// @@ -119,7 +119,7 @@ internal static string ByteRangeStreamContentNoRanges { return ResourceManager.GetString("ByteRangeStreamContentNoRanges", resourceCulture); } } - + /// /// Looks up a localized string similar to The range unit '{0}' is not valid. The range must have a unit of '{1}'.. /// @@ -128,7 +128,7 @@ internal static string ByteRangeStreamContentNotBytesRange { return ResourceManager.GetString("ByteRangeStreamContentNotBytesRange", resourceCulture); } } - + /// /// Looks up a localized string similar to The stream over which '{0}' provides a range view must have a length greater than or equal to 1.. /// @@ -137,7 +137,7 @@ internal static string ByteRangeStreamEmpty { return ResourceManager.GetString("ByteRangeStreamEmpty", resourceCulture); } } - + /// /// Looks up a localized string similar to The 'From' value of the range must be less than or equal to {0}.. /// @@ -146,7 +146,7 @@ internal static string ByteRangeStreamInvalidFrom { return ResourceManager.GetString("ByteRangeStreamInvalidFrom", resourceCulture); } } - + /// /// Looks up a localized string similar to An attempt was made to move the position before the beginning of the stream.. /// @@ -155,7 +155,7 @@ internal static string ByteRangeStreamInvalidOffset { return ResourceManager.GetString("ByteRangeStreamInvalidOffset", resourceCulture); } } - + /// /// Looks up a localized string similar to None of the requested ranges ({0}) overlap with the current extent of the selected resource.. /// @@ -164,7 +164,7 @@ internal static string ByteRangeStreamNoneOverlap { return ResourceManager.GetString("ByteRangeStreamNoneOverlap", resourceCulture); } } - + /// /// Looks up a localized string similar to The requested range ({0}) does not overlap with the current extent of the selected resource.. /// @@ -173,7 +173,7 @@ internal static string ByteRangeStreamNoOverlap { return ResourceManager.GetString("ByteRangeStreamNoOverlap", resourceCulture); } } - + /// /// Looks up a localized string similar to The stream over which '{0}' provides a range view must be seekable.. /// @@ -182,7 +182,7 @@ internal static string ByteRangeStreamNotSeekable { return ResourceManager.GetString("ByteRangeStreamNotSeekable", resourceCulture); } } - + /// /// Looks up a localized string similar to This is a read-only stream.. /// @@ -191,7 +191,7 @@ internal static string ByteRangeStreamReadOnly { return ResourceManager.GetString("ByteRangeStreamReadOnly", resourceCulture); } } - + /// /// Looks up a localized string similar to A null '{0}' is not valid.. /// @@ -200,7 +200,7 @@ internal static string CannotHaveNullInList { return ResourceManager.GetString("CannotHaveNullInList", resourceCulture); } } - + /// /// Looks up a localized string similar to The '{0}' of '{1}' cannot be used as a supported media type because it is a media range.. /// @@ -209,7 +209,7 @@ internal static string CannotUseMediaRangeForSupportedMediaType { return ResourceManager.GetString("CannotUseMediaRangeForSupportedMediaType", resourceCulture); } } - + /// /// Looks up a localized string similar to The '{0}' type cannot accept a null value for the value type '{1}'.. /// @@ -218,7 +218,7 @@ internal static string CannotUseNullValueType { return ResourceManager.GetString("CannotUseNullValueType", resourceCulture); } } - + /// /// Looks up a localized string similar to The specified value is not a valid cookie name.. /// @@ -227,7 +227,7 @@ internal static string CookieInvalidName { return ResourceManager.GetString("CookieInvalidName", resourceCulture); } } - + /// /// Looks up a localized string similar to Cookie cannot be null.. /// @@ -236,7 +236,7 @@ internal static string CookieNull { return ResourceManager.GetString("CookieNull", resourceCulture); } } - + /// /// Looks up a localized string similar to The '{0}' list is invalid because it contains one or more null items.. /// @@ -245,7 +245,7 @@ internal static string DelegatingHandlerArrayContainsNullItem { return ResourceManager.GetString("DelegatingHandlerArrayContainsNullItem", resourceCulture); } } - + /// /// Looks up a localized string similar to The '{0}' list is invalid because the property '{1}' of '{2}' is not null.. /// @@ -254,7 +254,7 @@ internal static string DelegatingHandlerArrayHasNonNullInnerHandler { return ResourceManager.GetString("DelegatingHandlerArrayHasNonNullInnerHandler", resourceCulture); } } - + /// /// Looks up a localized string similar to Error reading HTML form URL-encoded data stream.. /// @@ -263,7 +263,7 @@ internal static string ErrorReadingFormUrlEncodedStream { return ResourceManager.GetString("ErrorReadingFormUrlEncodedStream", resourceCulture); } } - + /// /// Looks up a localized string similar to Mismatched types at node '{0}'.. /// @@ -272,7 +272,7 @@ internal static string FormUrlEncodedMismatchingTypes { return ResourceManager.GetString("FormUrlEncodedMismatchingTypes", resourceCulture); } } - + /// /// Looks up a localized string similar to Error parsing HTML form URL-encoded data, byte {0}.. /// @@ -281,7 +281,7 @@ internal static string FormUrlEncodedParseError { return ResourceManager.GetString("FormUrlEncodedParseError", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid HTTP status code: '{0}'. The status code must be between {1} and {2}.. /// @@ -290,7 +290,7 @@ internal static string HttpInvalidStatusCode { return ResourceManager.GetString("HttpInvalidStatusCode", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid HTTP version: '{0}'. The version must start with the characters '{1}'.. /// @@ -299,7 +299,7 @@ internal static string HttpInvalidVersion { return ResourceManager.GetString("HttpInvalidVersion", resourceCulture); } } - + /// /// Looks up a localized string similar to The '{0}' of the '{1}' has already been read.. /// @@ -308,7 +308,7 @@ internal static string HttpMessageContentAlreadyRead { return ResourceManager.GetString("HttpMessageContentAlreadyRead", resourceCulture); } } - + /// /// Looks up a localized string similar to The '{0}' must be seekable in order to create an '{1}' instance containing an entity body. . /// @@ -317,7 +317,7 @@ internal static string HttpMessageContentStreamMustBeSeekable { return ResourceManager.GetString("HttpMessageContentStreamMustBeSeekable", resourceCulture); } } - + /// /// Looks up a localized string similar to Error reading HTTP message.. /// @@ -326,7 +326,7 @@ internal static string HttpMessageErrorReading { return ResourceManager.GetString("HttpMessageErrorReading", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid '{0}' instance provided. It does not have a content type header with a value of '{1}'.. /// @@ -335,7 +335,7 @@ internal static string HttpMessageInvalidMediaType { return ResourceManager.GetString("HttpMessageInvalidMediaType", resourceCulture); } } - + /// /// Looks up a localized string similar to HTTP Request URI cannot be an empty string.. /// @@ -344,7 +344,7 @@ internal static string HttpMessageParserEmptyUri { return ResourceManager.GetString("HttpMessageParserEmptyUri", resourceCulture); } } - + /// /// Looks up a localized string similar to Error parsing HTTP message header byte {0} of message {1}.. /// @@ -353,7 +353,7 @@ internal static string HttpMessageParserError { return ResourceManager.GetString("HttpMessageParserError", resourceCulture); } } - + /// /// Looks up a localized string similar to An invalid number of '{0}' header fields were present in the HTTP Request. It must contain exactly one '{0}' header field but found {1}.. /// @@ -362,7 +362,7 @@ internal static string HttpMessageParserInvalidHostCount { return ResourceManager.GetString("HttpMessageParserInvalidHostCount", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid URI scheme: '{0}'. The URI scheme must be a valid '{1}' scheme.. /// @@ -371,7 +371,7 @@ internal static string HttpMessageParserInvalidUriScheme { return ResourceManager.GetString("HttpMessageParserInvalidUriScheme", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid array at node '{0}'.. /// @@ -380,7 +380,7 @@ internal static string InvalidArrayInsert { return ResourceManager.GetString("InvalidArrayInsert", resourceCulture); } } - + /// /// Looks up a localized string similar to Traditional style array without '[]' is not supported with nested object at location {0}.. /// @@ -389,7 +389,7 @@ internal static string JQuery13CompatModeNotSupportNestedJson { return ResourceManager.GetString("JQuery13CompatModeNotSupportNestedJson", resourceCulture); } } - + /// /// Looks up a localized string similar to The '{0}' method returned null. It must return a JSON serializer instance.. /// @@ -398,7 +398,7 @@ internal static string JsonSerializerFactoryReturnedNull { return ResourceManager.GetString("JsonSerializerFactoryReturnedNull", resourceCulture); } } - + /// /// Looks up a localized string similar to The '{0}' method threw an exception when attempting to create a JSON serializer.. /// @@ -407,7 +407,7 @@ internal static string JsonSerializerFactoryThrew { return ResourceManager.GetString("JsonSerializerFactoryThrew", resourceCulture); } } - + /// /// Looks up a localized string similar to The maximum read depth ({0}) has been exceeded because the form url-encoded data being read has more levels of nesting than is allowed.. /// @@ -416,7 +416,7 @@ internal static string MaxDepthExceeded { return ResourceManager.GetString("MaxDepthExceeded", resourceCulture); } } - + /// /// Looks up a localized string similar to The number of keys in a NameValueCollection has exceeded the limit of '{0}'. You can adjust it by modifying the MaxHttpCollectionKeys property on the '{1}' class.. /// @@ -425,7 +425,7 @@ internal static string MaxHttpCollectionKeyLimitReached { return ResourceManager.GetString("MaxHttpCollectionKeyLimitReached", resourceCulture); } } - + /// /// Looks up a localized string similar to Error parsing BSON data; unable to read content as a {0}.. /// @@ -434,7 +434,7 @@ internal static string MediaTypeFormatter_BsonParseError_MissingData { return ResourceManager.GetString("MediaTypeFormatter_BsonParseError_MissingData", resourceCulture); } } - + /// /// Looks up a localized string similar to Error parsing BSON data; unexpected dictionary content: {0} entries, first key '{1}'.. /// @@ -443,7 +443,7 @@ internal static string MediaTypeFormatter_BsonParseError_UnexpectedData { return ResourceManager.GetString("MediaTypeFormatter_BsonParseError_UnexpectedData", resourceCulture); } } - + /// /// Looks up a localized string similar to The '{0}' method returned null. It must return a JSON reader instance.. /// @@ -452,7 +452,7 @@ internal static string MediaTypeFormatter_JsonReaderFactoryReturnedNull { return ResourceManager.GetString("MediaTypeFormatter_JsonReaderFactoryReturnedNull", resourceCulture); } } - + /// /// Looks up a localized string similar to The '{0}' method returned null. It must return a JSON writer instance.. /// @@ -461,7 +461,7 @@ internal static string MediaTypeFormatter_JsonWriterFactoryReturnedNull { return ResourceManager.GetString("MediaTypeFormatter_JsonWriterFactoryReturnedNull", resourceCulture); } } - + /// /// Looks up a localized string similar to The media type formatter of type '{0}' does not support reading because it does not implement the ReadFromStreamAsync method.. /// @@ -470,7 +470,7 @@ internal static string MediaTypeFormatterCannotRead { return ResourceManager.GetString("MediaTypeFormatterCannotRead", resourceCulture); } } - + /// /// Looks up a localized string similar to The media type formatter of type '{0}' does not support reading because it does not implement the ReadFromStream method.. /// @@ -479,7 +479,7 @@ internal static string MediaTypeFormatterCannotReadSync { return ResourceManager.GetString("MediaTypeFormatterCannotReadSync", resourceCulture); } } - + /// /// Looks up a localized string similar to The media type formatter of type '{0}' does not support writing because it does not implement the WriteToStreamAsync method.. /// @@ -488,7 +488,7 @@ internal static string MediaTypeFormatterCannotWrite { return ResourceManager.GetString("MediaTypeFormatterCannotWrite", resourceCulture); } } - + /// /// Looks up a localized string similar to The media type formatter of type '{0}' does not support writing because it does not implement the WriteToStream method.. /// @@ -497,7 +497,7 @@ internal static string MediaTypeFormatterCannotWriteSync { return ResourceManager.GetString("MediaTypeFormatterCannotWriteSync", resourceCulture); } } - + /// /// Looks up a localized string similar to No encoding found for media type formatter '{0}'. There must be at least one supported encoding registered in order for the media type formatter to read or write content.. /// @@ -506,7 +506,7 @@ internal static string MediaTypeFormatterNoEncoding { return ResourceManager.GetString("MediaTypeFormatterNoEncoding", resourceCulture); } } - + /// /// Looks up a localized string similar to MIME multipart boundary cannot end with an empty space.. /// @@ -515,7 +515,7 @@ internal static string MimeMultipartParserBadBoundary { return ResourceManager.GetString("MimeMultipartParserBadBoundary", resourceCulture); } } - + /// /// Looks up a localized string similar to Did not find required '{0}' header field in MIME multipart body part.. /// @@ -524,7 +524,7 @@ internal static string MultipartFormDataStreamProviderNoContentDisposition { return ResourceManager.GetString("MultipartFormDataStreamProviderNoContentDisposition", resourceCulture); } } - + /// /// Looks up a localized string similar to Could not determine a valid local file name for the multipart body part.. /// @@ -533,7 +533,7 @@ internal static string MultipartStreamProviderInvalidLocalFileName { return ResourceManager.GetString("MultipartStreamProviderInvalidLocalFileName", resourceCulture); } } - + /// /// Looks up a localized string similar to Nested bracket is not valid for '{0}' data at position {1}.. /// @@ -542,7 +542,7 @@ internal static string NestedBracketNotValid { return ResourceManager.GetString("NestedBracketNotValid", resourceCulture); } } - + /// /// Looks up a localized string similar to A non-null request URI must be provided to determine if a '{0}' matches a given request or response message.. /// @@ -551,7 +551,7 @@ internal static string NonNullUriRequiredForMediaTypeMapping { return ResourceManager.GetString("NonNullUriRequiredForMediaTypeMapping", resourceCulture); } } - + /// /// Looks up a localized string similar to No MediaTypeFormatter is available to read an object of type '{0}' from content with media type '{1}'.. /// @@ -560,7 +560,7 @@ internal static string NoReadSerializerAvailable { return ResourceManager.GetString("NoReadSerializerAvailable", resourceCulture); } } - + /// /// Looks up a localized string similar to Stream does not support reading.. /// @@ -569,7 +569,7 @@ internal static string NotSupported_UnreadableStream { return ResourceManager.GetString("NotSupported_UnreadableStream", resourceCulture); } } - + /// /// Looks up a localized string similar to Stream does not support seeking.. /// @@ -578,7 +578,7 @@ internal static string NotSupported_UnseekableStream { return ResourceManager.GetString("NotSupported_UnseekableStream", resourceCulture); } } - + /// /// Looks up a localized string similar to Stream does not support writing.. /// @@ -587,7 +587,7 @@ internal static string NotSupported_UnwritableStream { return ResourceManager.GetString("NotSupported_UnwritableStream", resourceCulture); } } - + /// /// Looks up a localized string similar to An object of type '{0}' cannot be used with a type parameter of '{1}'.. /// @@ -596,7 +596,7 @@ internal static string ObjectAndTypeDisagree { return ResourceManager.GetString("ObjectAndTypeDisagree", resourceCulture); } } - + /// /// Looks up a localized string similar to The configured formatter '{0}' cannot write an object of type '{1}'.. /// @@ -605,7 +605,7 @@ internal static string ObjectContent_FormatterCannotWriteType { return ResourceManager.GetString("ObjectContent_FormatterCannotWriteType", resourceCulture); } } - + /// /// Looks up a localized string similar to Cannot access a closed stream.. /// @@ -614,7 +614,7 @@ internal static string ObjectDisposed_StreamClosed { return ResourceManager.GetString("ObjectDisposed_StreamClosed", resourceCulture); } } - + /// /// Looks up a localized string similar to Query string name cannot be null.. /// @@ -623,7 +623,7 @@ internal static string QueryStringNameShouldNotNull { return ResourceManager.GetString("QueryStringNameShouldNotNull", resourceCulture); } } - + /// /// Looks up a localized string similar to Unexpected end of HTTP message stream. HTTP message is not complete.. /// @@ -632,7 +632,7 @@ internal static string ReadAsHttpMessageUnexpectedTermination { return ResourceManager.GetString("ReadAsHttpMessageUnexpectedTermination", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid '{0}' instance provided. It does not have a '{1}' content-type header with a '{2}' parameter.. /// @@ -641,7 +641,7 @@ internal static string ReadAsMimeMultipartArgumentNoBoundary { return ResourceManager.GetString("ReadAsMimeMultipartArgumentNoBoundary", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid '{0}' instance provided. It does not have a content-type header value. '{0}' instances must have a content-type header starting with '{1}'.. /// @@ -650,7 +650,7 @@ internal static string ReadAsMimeMultipartArgumentNoContentType { return ResourceManager.GetString("ReadAsMimeMultipartArgumentNoContentType", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid '{0}' instance provided. It does not have a content type header starting with '{1}'.. /// @@ -659,7 +659,7 @@ internal static string ReadAsMimeMultipartArgumentNoMultipart { return ResourceManager.GetString("ReadAsMimeMultipartArgumentNoMultipart", resourceCulture); } } - + /// /// Looks up a localized string similar to Error reading MIME multipart body part.. /// @@ -668,7 +668,7 @@ internal static string ReadAsMimeMultipartErrorReading { return ResourceManager.GetString("ReadAsMimeMultipartErrorReading", resourceCulture); } } - + /// /// Looks up a localized string similar to Error writing MIME multipart body part to output stream.. /// @@ -677,7 +677,7 @@ internal static string ReadAsMimeMultipartErrorWriting { return ResourceManager.GetString("ReadAsMimeMultipartErrorWriting", resourceCulture); } } - + /// /// Looks up a localized string similar to Error parsing MIME multipart body part header byte {0} of data segment {1}.. /// @@ -686,7 +686,7 @@ internal static string ReadAsMimeMultipartHeaderParseError { return ResourceManager.GetString("ReadAsMimeMultipartHeaderParseError", resourceCulture); } } - + /// /// Looks up a localized string similar to Error parsing MIME multipart message byte {0} of data segment {1}.. /// @@ -695,7 +695,7 @@ internal static string ReadAsMimeMultipartParseError { return ResourceManager.GetString("ReadAsMimeMultipartParseError", resourceCulture); } } - + /// /// Looks up a localized string similar to The stream provider of type '{0}' threw an exception.. /// @@ -704,7 +704,7 @@ internal static string ReadAsMimeMultipartStreamProviderException { return ResourceManager.GetString("ReadAsMimeMultipartStreamProviderException", resourceCulture); } } - + /// /// Looks up a localized string similar to The stream provider of type '{0}' returned null. It must return a writable '{1}' instance.. /// @@ -713,7 +713,7 @@ internal static string ReadAsMimeMultipartStreamProviderNull { return ResourceManager.GetString("ReadAsMimeMultipartStreamProviderNull", resourceCulture); } } - + /// /// Looks up a localized string similar to The stream provider of type '{0}' returned a read-only stream. It must return a writable '{1}' instance.. /// @@ -722,7 +722,7 @@ internal static string ReadAsMimeMultipartStreamProviderReadOnly { return ResourceManager.GetString("ReadAsMimeMultipartStreamProviderReadOnly", resourceCulture); } } - + /// /// Looks up a localized string similar to Unexpected end of MIME multipart stream. MIME multipart message is not complete.. /// @@ -731,7 +731,7 @@ internal static string ReadAsMimeMultipartUnexpectedTermination { return ResourceManager.GetString("ReadAsMimeMultipartUnexpectedTermination", resourceCulture); } } - + /// /// Looks up a localized string similar to The '{0}' method in '{1}' returned null. It must return a RemoteStreamResult instance containing a writable stream and a valid URL.. /// @@ -740,7 +740,7 @@ internal static string RemoteStreamInfoCannotBeNull { return ResourceManager.GetString("RemoteStreamInfoCannotBeNull", resourceCulture); } } - + /// /// Looks up a localized string similar to The '{0}' serializer cannot serialize the type '{1}'.. /// @@ -749,7 +749,7 @@ internal static string SerializerCannotSerializeType { return ResourceManager.GetString("SerializerCannotSerializeType", resourceCulture); } } - + /// /// Looks up a localized string similar to There is an unmatched opened bracket for the '{0}' at position {1}.. /// @@ -758,7 +758,7 @@ internal static string UnMatchedBracketNotValid { return ResourceManager.GetString("UnMatchedBracketNotValid", resourceCulture); } } - + /// /// Looks up a localized string similar to Indentation is not supported by '{0}'.. /// @@ -767,7 +767,7 @@ internal static string UnsupportedIndent { return ResourceManager.GetString("UnsupportedIndent", resourceCulture); } } - + /// /// Looks up a localized string similar to The object of type '{0}' returned by {1} must be an instance of either XmlObjectSerializer or XmlSerializer.. /// @@ -776,7 +776,7 @@ internal static string XmlMediaTypeFormatter_InvalidSerializerType { return ResourceManager.GetString("XmlMediaTypeFormatter_InvalidSerializerType", resourceCulture); } } - + /// /// Looks up a localized string similar to The object returned by {0} must not be a null value.. /// diff --git a/src/System.Net.Http.Formatting/PushStreamContent.cs b/src/System.Net.Http.Formatting/PushStreamContent.cs index 6896e6c39..8b4a72b3c 100644 --- a/src/System.Net.Http.Formatting/PushStreamContent.cs +++ b/src/System.Net.Http.Formatting/PushStreamContent.cs @@ -153,7 +153,7 @@ public CompleteTaskOnCloseStream(Stream innerStream, TaskCompletionSource _serializeToStreamTask = serializeToStreamTask; } -#if NETFX_CORE +#if NETSTANDARD1_3 [SuppressMessage( "Microsoft.Usage", "CA2215:Dispose methods should call base class dispose", diff --git a/test/Directory.Build.props b/test/Directory.Build.props index 23c8b064c..c55ba298d 100644 --- a/test/Directory.Build.props +++ b/test/Directory.Build.props @@ -6,7 +6,7 @@ true v4.6.2 + '$(MSBuildProjectName)' != 'System.Net.Http.Formatting.ns1_3.Test' AND + '$(MSBuildProjectName)' != 'System.Net.Http.Formatting.ns2_0.Test' ">v4.6.2 diff --git a/test/Microsoft.TestCommon/Directory.Build.props b/test/Microsoft.TestCommon/Directory.Build.props index dc9c3befb..1c94e6e8e 100644 --- a/test/Microsoft.TestCommon/Directory.Build.props +++ b/test/Microsoft.TestCommon/Directory.Build.props @@ -2,8 +2,8 @@ - - obj\NetCore\ + + obj\ns1_3\ $(DefaultItemExcludes);obj\** diff --git a/test/Microsoft.TestCommon/ExceptionAssertions.cs b/test/Microsoft.TestCommon/ExceptionAssertions.cs index 0b43f6627..9c0de771a 100644 --- a/test/Microsoft.TestCommon/ExceptionAssertions.cs +++ b/test/Microsoft.TestCommon/ExceptionAssertions.cs @@ -6,7 +6,7 @@ using System.Reflection; using System.Threading.Tasks; using System.Web; -#if NETFX_CORE +#if Testing_NetStandard1_3 using System.Web.Http; #endif @@ -503,7 +503,7 @@ public static ArgumentException ThrowsInvalidEnumArgument(Action testCode, strin "The value of argument '{0}' ({1}) is invalid for Enum type '{2}'.{3}", paramName, invalidValue, enumType.Name, GetParameterMessage(paramName)); -#if NETFX_CORE // InvalidEnumArgumentException not available in netstandard1.3. +#if Testing_NetStandard1_3 // InvalidEnumArgumentException not available in netstandard1.3. return Throws(testCode, message, allowDerivedExceptions); #else return Throws(testCode, message, allowDerivedExceptions); diff --git a/test/Microsoft.TestCommon/Microsoft.TestCommon.csproj b/test/Microsoft.TestCommon/Microsoft.TestCommon.csproj index 593a10e13..d22704250 100644 --- a/test/Microsoft.TestCommon/Microsoft.TestCommon.csproj +++ b/test/Microsoft.TestCommon/Microsoft.TestCommon.csproj @@ -4,21 +4,21 @@ net462;netcoreapp2.1;net6.0 $(Configurations);CodeAnalysis $(DefineConstants);NETFX_CORE + Condition=" '$(Testing_NetStandard1_3)' == 'true' ">$(DefineConstants);Testing_NetStandard1_3 false ..\..\bin\$(Configuration)\Test\ $(OutputPath)NetCore\ + Condition=" '$(Testing_NetStandard1_3)' == 'true' ">$(OutputPath)ns1_3\ - + + Condition=" '$(TargetFrameworkIdentifier)' == '.NETFramework' AND '$(Testing_NetStandard1_3)' == 'true' " /> + Condition=" '$(TargetFrameworkIdentifier)' == '.NETFramework' AND '$(Testing_NetStandard1_3)' != 'true' " /> @@ -33,7 +33,7 @@ Condition=" '$(TargetFrameworkIdentifier)' != '.NETFramework' " /> - + diff --git a/test/System.Net.Http.Formatting.Test/Formatting/BsonMediaTypeFormatterTests.cs b/test/System.Net.Http.Formatting.Test/Formatting/BsonMediaTypeFormatterTests.cs index 8b49dba47..17711aacd 100644 --- a/test/System.Net.Http.Formatting.Test/Formatting/BsonMediaTypeFormatterTests.cs +++ b/test/System.Net.Http.Formatting.Test/Formatting/BsonMediaTypeFormatterTests.cs @@ -392,7 +392,7 @@ public async Task ReadFromStreamAsync_RoundTripsWriteToStreamAsync_PerhapsJObjec } } -#if !NETFX_CORE // DBNull not supported in portable library +#if !Testing_NetStandard1_3 // DBNull not supported in netstandard1.3 // Test alternate null value [Theory] [TestDataSet(typeof(JsonMediaTypeFormatterTests), "DBNullAsObjectTestDataCollection", TestDataVariations.AllSingleInstances)] diff --git a/test/System.Net.Http.Formatting.Test/Formatting/DataContractJsonMediaTypeFormatterTests.cs b/test/System.Net.Http.Formatting.Test/Formatting/DataContractJsonMediaTypeFormatterTests.cs index 55ad646b4..f29126ba1 100644 --- a/test/System.Net.Http.Formatting.Test/Formatting/DataContractJsonMediaTypeFormatterTests.cs +++ b/test/System.Net.Http.Formatting.Test/Formatting/DataContractJsonMediaTypeFormatterTests.cs @@ -87,7 +87,7 @@ public void CanReadType_ReturnsExpectedValues(Type variationType, object testDat Assert.False(isSerializable != canSupport && isSerializable, String.Format("2nd CanReadType returned wrong value for '{0}'.", variationType)); } -#if !NETFX_CORE // XsdDataContractExporterMethods unconditionally return true without XsdDataContractExporter to use. +#if !Testing_NetStandard1_3 // XsdDataContractExporterMethods unconditionally return true without XsdDataContractExporter to use. [Fact] public void CanReadType_ReturnsFalse_ForInvalidDataContracts() { diff --git a/test/System.Net.Http.Formatting.Test/Formatting/JsonNetSerializationTest.cs b/test/System.Net.Http.Formatting.Test/Formatting/JsonNetSerializationTest.cs index bd0edfd20..da5c9d7da 100644 --- a/test/System.Net.Http.Formatting.Test/Formatting/JsonNetSerializationTest.cs +++ b/test/System.Net.Http.Formatting.Test/Formatting/JsonNetSerializationTest.cs @@ -92,7 +92,7 @@ public static TheoryDataSet SerializedJson // Classes { new DataContractType() { s = "foo", i = 49, NotAMember = "Error" }, "{\"s\":\"foo\",\"i\":49}" }, { new POCOType() { s = "foo", t = "Error"}, "{\"s\":\"foo\"}" }, -#if !NETFX_CORE // Only publics are serialized in portable library +#if !Testing_NetStandard1_3 // Only publics are serialized in netstandard1.3 { new SerializableType("protected") { publicField = "public", protectedInternalField = "protected internal", internalField = "internal", PublicProperty = "private", nonSerializedField = "Error" }, "{\"publicField\":\"public\",\"internalField\":\"internal\",\"protectedInternalField\":\"protected internal\",\"protectedField\":\"protected\",\"privateField\":\"private\"}" }, #else { new SerializableType("protected") { publicField = "public", protectedInternalField = "protected internal", internalField = "internal", PublicProperty = "private", nonSerializedField = "Error" }, "{\"publicField\":\"public\",\"PublicProperty\":\"private\"}" }, @@ -491,7 +491,7 @@ public string PublicProperty public bool Equals(SerializableType other) { -#if !NETFX_CORE // Only publics are serialized in portable library. privateField is serialized through PublicProperty +#if !Testing_NetStandard1_3 // Only publics are serialized in netstandard1.3. privateField is serialized through PublicProperty return this.publicField == other.publicField && this.internalField == other.internalField && this.protectedInternalField == other.protectedInternalField && diff --git a/test/System.Net.Http.Formatting.Test/Formatting/StringComparisonHelperTest.cs b/test/System.Net.Http.Formatting.Test/Formatting/StringComparisonHelperTest.cs index f18764086..104a4c48a 100644 --- a/test/System.Net.Http.Formatting.Test/Formatting/StringComparisonHelperTest.cs +++ b/test/System.Net.Http.Formatting.Test/Formatting/StringComparisonHelperTest.cs @@ -12,7 +12,7 @@ public StringComparisonHelperTest() { } -#if NETFX_CORE // InvariantCulture and InvariantCultureIgnoreCase case are not supported in portable library projects +#if Testing_NetStandard1_3 // InvariantCulture and InvariantCultureIgnoreCase case are not supported in netstandard1.3 project protected override bool ValueExistsForFramework(StringComparison value) { return !(value == StringComparison.InvariantCulture || value == StringComparison.InvariantCultureIgnoreCase); diff --git a/test/System.Net.Http.Formatting.Test/Formatting/XmlMediaTypeFormatterTests.cs b/test/System.Net.Http.Formatting.Test/Formatting/XmlMediaTypeFormatterTests.cs index d10e927d3..6ee72838e 100644 --- a/test/System.Net.Http.Formatting.Test/Formatting/XmlMediaTypeFormatterTests.cs +++ b/test/System.Net.Http.Formatting.Test/Formatting/XmlMediaTypeFormatterTests.cs @@ -673,7 +673,7 @@ public Task InvalidXmlCharacters_CannotBeSerialized_IfCheckCharactersIsTrue() "'\x16', hexadecimal value 0x16, is an invalid character."); } -#if !NETFX_CORE // Different behavior in portable libraries due to no DataContract validation +#if !Testing_NetStandard1_3 // Different behavior in netstandard1.3 due to no DataContract validation [Fact] public void CanReadType_ReturnsFalse_ForInvalidDataContracts() { diff --git a/test/System.Net.Http.Formatting.Test/Handlers/ProgressStreamTest.cs b/test/System.Net.Http.Formatting.Test/Handlers/ProgressStreamTest.cs index 0c0b06110..0355dcdab 100644 --- a/test/System.Net.Http.Formatting.Test/Handlers/ProgressStreamTest.cs +++ b/test/System.Net.Http.Formatting.Test/Handlers/ProgressStreamTest.cs @@ -66,7 +66,7 @@ public async Task ReadByte_ReportsBytesRead() Assert.Equal(100, mockProgressEventHandler.EventArgs.ProgressPercentage); } -#if !NETFX_CORE // BeginX and EndX not supported on Streams in portable libraries +#if !Testing_NetStandard1_3 // BeginX and EndX not supported on Streams in netstandard1.3 [Fact] public async Task BeginEndRead_ReportsBytesRead() { @@ -186,7 +186,7 @@ public void WriteByte_ReportsBytesWritten() Assert.Equal(100, mockProgressEventHandler.EventArgs.ProgressPercentage); } -#if !NETFX_CORE // BeginX and EndX not supported on Streams in portable libraries +#if !Testing_NetStandard1_3 // BeginX and EndX not supported on Streams in netstandard1.3 [Fact] public void BeginEndWrite_ReportsBytesWritten() { diff --git a/test/System.Net.Http.Formatting.Test/HttpContentMultipartExtensionsTests.cs b/test/System.Net.Http.Formatting.Test/HttpContentMultipartExtensionsTests.cs index 1fc9c1ea8..b9769fa63 100644 --- a/test/System.Net.Http.Formatting.Test/HttpContentMultipartExtensionsTests.cs +++ b/test/System.Net.Http.Formatting.Test/HttpContentMultipartExtensionsTests.cs @@ -444,7 +444,7 @@ public override Task ReadAsync(byte[] buffer, int offset, int count, Cancel throw new IOException(ExceptionAsyncStreamMessage); } -#if !NETFX_CORE // BeginX and EndX not supported on Streams in portable libraries +#if !Testing_NetStandard1_3 // BeginX and EndX not supported on Streams in netstandard1.3 public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { throw new IOException(ExceptionAsyncStreamMessage); @@ -464,7 +464,7 @@ public override Task WriteAsync(byte[] buffer, int offset, int count, Cancellati throw new IOException(ExceptionAsyncStreamMessage); } -#if !NETFX_CORE // BeginX and EndX not supported on Streams in portable libraries +#if !Testing_NetStandard1_3 // BeginX and EndX not supported on Streams in netstandard1.3 public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { throw new IOException(ExceptionAsyncStreamMessage); diff --git a/test/System.Net.Http.Formatting.Test/Internal/ByteRangeStreamTest.cs b/test/System.Net.Http.Formatting.Test/Internal/ByteRangeStreamTest.cs index 391f31b09..6e8251778 100644 --- a/test/System.Net.Http.Formatting.Test/Internal/ByteRangeStreamTest.cs +++ b/test/System.Net.Http.Formatting.Test/Internal/ByteRangeStreamTest.cs @@ -303,7 +303,7 @@ public async Task Position_PositionsNextRead() } } -#if !NETFX_CORE // BeginX and EndX are not supported on streams in portable libraries +#if !Testing_NetStandard1_3 // BeginX and EndX are not supported on Streams in netstandard1.3 [Theory] [PropertyData("ReadBoundsDataWithLimit")] public void BeginRead_ReadsEffectiveLengthBytes(int from, int to, int innerLength, int effectiveLength) diff --git a/test/System.Net.Http.Formatting.Test/Internal/DelegatingStreamTest.cs b/test/System.Net.Http.Formatting.Test/Internal/DelegatingStreamTest.cs index 8f24a05d3..1ed7db60a 100644 --- a/test/System.Net.Http.Formatting.Test/Internal/DelegatingStreamTest.cs +++ b/test/System.Net.Http.Formatting.Test/Internal/DelegatingStreamTest.cs @@ -193,7 +193,7 @@ public void DelegatingStream_Read() mockInnerStream.Verify(s => s.Read(buffer, offset, count), Times.Once()); } -#if !NETFX_CORE // BeginX and EndX not supported on Streams in portable libraries +#if !Testing_NetStandard1_3 // BeginX and EndX not supported on Streams in netstandard1.3 [Fact] public void DelegatingStream_BeginRead() { @@ -305,7 +305,7 @@ public void DelegatingStream_Write() mockInnerStream.Verify(s => s.Write(buffer, offset, count), Times.Once()); } -#if !NETFX_CORE // BeginX and EndX not supported on Streams in portable libraries +#if !Testing_NetStandard1_3 // BeginX and EndX not supported on Streams in netstandard1.3 [Fact] public void DelegatingStream_BeginWrite() { diff --git a/test/System.Net.Http.Formatting.Test/Internal/TranscodingStreamTests.cs b/test/System.Net.Http.Formatting.Test/Internal/TranscodingStreamTests.cs index 4e50d4381..c92b43915 100644 --- a/test/System.Net.Http.Formatting.Test/Internal/TranscodingStreamTests.cs +++ b/test/System.Net.Http.Formatting.Test/Internal/TranscodingStreamTests.cs @@ -31,7 +31,7 @@ public static IEnumerable ReadWriteTestBufferLengths } } -#if NETFX_CORE || Testing_NetStandard2_0 // .NET Framework implementation loses track of cancellation token. +#if Testing_NetStandard1_3 || Testing_NetStandard2_0 // .NET Framework implementation loses track of cancellation token. [Fact] public void AsyncMethods_ReturnCanceledTaskIfCancellationTokenTripped() { diff --git a/test/System.Net.Http.Formatting.Test/PushStreamContentTest.cs b/test/System.Net.Http.Formatting.Test/PushStreamContentTest.cs index a3414019d..9274aaa01 100644 --- a/test/System.Net.Http.Formatting.Test/PushStreamContentTest.cs +++ b/test/System.Net.Http.Formatting.Test/PushStreamContentTest.cs @@ -79,7 +79,7 @@ public async Task SerializeToStreamAsync_CompletesTaskOnActionException() Assert.True(outputStream.CanRead); } -#if NETFX_CORE +#if Testing_NetStandard1_3 [Fact] public async Task CompleteTaskOnCloseStream_Dispose_CompletesTaskButDoNotDisposeInnerStream() { @@ -222,7 +222,7 @@ public void Action(Stream stream, HttpContent content, TransportContext context) if (_close) { -#if NETFX_CORE +#if Testing_NetStandard1_3 stream.Dispose(); #else stream.Close(); diff --git a/test/System.Net.Http.Formatting.NetCore.Test/System.Net.Http.Formatting.NetCore.Test.csproj b/test/System.Net.Http.Formatting.ns1_3.Test/System.Net.Http.Formatting.ns1_3.Test.csproj similarity index 89% rename from test/System.Net.Http.Formatting.NetCore.Test/System.Net.Http.Formatting.NetCore.Test.csproj rename to test/System.Net.Http.Formatting.ns1_3.Test/System.Net.Http.Formatting.ns1_3.Test.csproj index 1a2fc91cd..cfd42c053 100644 --- a/test/System.Net.Http.Formatting.NetCore.Test/System.Net.Http.Formatting.NetCore.Test.csproj +++ b/test/System.Net.Http.Formatting.ns1_3.Test/System.Net.Http.Formatting.ns1_3.Test.csproj @@ -3,10 +3,10 @@ net462;netcoreapp2.1;net6.0 System.Net.Http - ..\..\bin\$(Configuration)\Test\NetCore\ + ..\..\bin\$(Configuration)\Test\ns1_3\ $(Configurations);CodeAnalysis false - $(DefineConstants);NETFX_CORE + $(DefineConstants);Testing_NetStandard1_3 true true @@ -37,8 +37,8 @@ %(RecursiveDir)\%(Filename).cs - - + + diff --git a/test/System.Net.Http.Formatting.NetStandard.Test/System.Net.Http.Formatting.NetStandard.Test.csproj b/test/System.Net.Http.Formatting.ns2_0.Test/System.Net.Http.Formatting.ns2_0.Test.csproj similarity index 93% rename from test/System.Net.Http.Formatting.NetStandard.Test/System.Net.Http.Formatting.NetStandard.Test.csproj rename to test/System.Net.Http.Formatting.ns2_0.Test/System.Net.Http.Formatting.ns2_0.Test.csproj index dc96f8c4c..8c7958b39 100644 --- a/test/System.Net.Http.Formatting.NetStandard.Test/System.Net.Http.Formatting.NetStandard.Test.csproj +++ b/test/System.Net.Http.Formatting.ns2_0.Test/System.Net.Http.Formatting.ns2_0.Test.csproj @@ -3,7 +3,7 @@ net462;netcoreapp2.1;net6.0 System.Net.Http - ..\..\bin\$(Configuration)\Test\NetStandard\ + ..\..\bin\$(Configuration)\Test\ns2_0\ $(Configurations);CodeAnalysis false $(DefineConstants);Testing_NetStandard2_0 @@ -33,7 +33,7 @@ %(RecursiveDir)\%(Filename).cs - + diff --git a/tools/SkipStrongNames.xml b/tools/SkipStrongNames.xml index 7844b81cb..b189c3596 100644 --- a/tools/SkipStrongNames.xml +++ b/tools/SkipStrongNames.xml @@ -41,8 +41,8 @@ - - + + From cb7628ff7018e6dee7e7e6e05dd524df4d41820b Mon Sep 17 00:00:00 2001 From: Doug Bunting <6431421+dougbu@users.noreply.github.com> Date: Wed, 1 Mar 2023 16:53:44 -0800 Subject: [PATCH 41/54] Support `DBNull` in `netstandard1.3` assembly (#394) * Support `DBNull` in `netstandard1.3` assembly - available from the System.Data.Common package - extend `DBNull` testing to include `net6.0` - s/NETCOREAPP/NETCOREAPP2_1/ where possible - fix comments in `HttpValueCollectionTest` - comments about `DBNull` there were incorrect * !fixup! Add `$(System.JobId)` to artifact names - `publish` / `PublishPipelineArtifact@1` task doesn't overwrite an existing build artifact - bit different from `PublishBuildArtifacts@1` - follow guidance at --- azure-pipelines.yml | 4 ++-- .../System.Net.Http.Formatting.ns1_3.csproj | 1 + .../Formatting/BsonMediaTypeFormatter.cs | 8 ++------ .../Formatting/BsonMediaTypeFormatterTests.cs | 4 +--- .../Formatting/DataContractJsonMediaTypeFormatterTests.cs | 2 +- .../Formatting/JsonMediaTypeFormatterTests.cs | 2 +- .../Formatting/XmlMediaTypeFormatterTests.cs | 4 ++-- .../Internal/HttpValueCollectionTest.cs | 6 +++--- 8 files changed, 13 insertions(+), 18 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index b4e242d3a..b8b92278a 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -79,7 +79,7 @@ jobs: displayName: Build - publish: ./bin/$(_Configuration)/Test/TestResults/ - artifact: $(_Configuration) Test Results + artifact: $(_Configuration) Test Results $(System.JobId) condition: and(always(), ne(variables._BuildTarget, 'Build')) continueOnError: true displayName: Upload test results @@ -95,6 +95,6 @@ jobs: testRunTitle: $(_Configuration) - publish: ./artifacts/ - artifact: $(_Configuration) Logs + artifact: $(_Configuration) Logs $(System.JobId) condition: always() displayName: Upload logs diff --git a/src/System.Net.Http.Formatting.ns1_3/System.Net.Http.Formatting.ns1_3.csproj b/src/System.Net.Http.Formatting.ns1_3/System.Net.Http.Formatting.ns1_3.csproj index 70326ce1b..7e388ca5b 100644 --- a/src/System.Net.Http.Formatting.ns1_3/System.Net.Http.Formatting.ns1_3.csproj +++ b/src/System.Net.Http.Formatting.ns1_3/System.Net.Http.Formatting.ns1_3.csproj @@ -17,6 +17,7 @@ + diff --git a/src/System.Net.Http.Formatting/Formatting/BsonMediaTypeFormatter.cs b/src/System.Net.Http.Formatting/Formatting/BsonMediaTypeFormatter.cs index c6eba6e45..fe6fdef23 100644 --- a/src/System.Net.Http.Formatting/Formatting/BsonMediaTypeFormatter.cs +++ b/src/System.Net.Http.Formatting/Formatting/BsonMediaTypeFormatter.cs @@ -73,7 +73,6 @@ public sealed override int MaxDepth } } -#if !NETSTANDARD1_3 // DBNull not supported in netstandard1.3; no need to override there /// public override Task ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger) { @@ -101,7 +100,6 @@ public override Task ReadFromStreamAsync(Type type, Stream readStream, H return base.ReadFromStreamAsync(type, readStream, content, formatterLogger); } } -#endif /// public override object ReadFromStream(Type type, Stream readStream, Encoding effectiveEncoding, @@ -234,14 +232,13 @@ public override void WriteToStream(Type type, object value, Stream writeStream, if (value == null) { - // Cannot serialize null at the top level. Json.Net throws Newtonsoft.Json.JsonWriterException : Error - // writing Null value. BSON must start with an Object or Array. Path ''. Fortunately + // Cannot serialize null at the top level. Json.Net throws Newtonsoft.Json.JsonWriterException : Error + // writing Null value. BSON must start with an Object or Array. Path ''. Fortunately // BaseJsonMediaTypeFormatter.ReadFromStream(Type, Stream, HttpContent, IFormatterLogger) treats zero- // length content as null or the default value of a struct. return; } -#if !NETSTANDARD1_3 // DBNull not supported in netstandard1.3 if (value == DBNull.Value) { // ReadFromStreamAsync() override above converts null to DBNull.Value if given Type is DBNull; normally @@ -252,7 +249,6 @@ public override void WriteToStream(Type type, object value, Stream writeStream, // rather than null, and not meet the receiver's expectations. return; } -#endif // See comments in ReadFromStream() above about this special case and the need to include byte[] in it. // Using runtime type here because Json.Net will throw during serialization whenever it cannot handle the diff --git a/test/System.Net.Http.Formatting.Test/Formatting/BsonMediaTypeFormatterTests.cs b/test/System.Net.Http.Formatting.Test/Formatting/BsonMediaTypeFormatterTests.cs index 17711aacd..93cea6ba7 100644 --- a/test/System.Net.Http.Formatting.Test/Formatting/BsonMediaTypeFormatterTests.cs +++ b/test/System.Net.Http.Formatting.Test/Formatting/BsonMediaTypeFormatterTests.cs @@ -392,7 +392,6 @@ public async Task ReadFromStreamAsync_RoundTripsWriteToStreamAsync_PerhapsJObjec } } -#if !Testing_NetStandard1_3 // DBNull not supported in netstandard1.3 // Test alternate null value [Theory] [TestDataSet(typeof(JsonMediaTypeFormatterTests), "DBNullAsObjectTestDataCollection", TestDataVariations.AllSingleInstances)] @@ -408,7 +407,7 @@ public async Task ReadFromStreamAsync_RoundTripsWriteToStreamAsync_DBNullAsNull( Assert.Null(readObj); } -#if !NETCOREAPP // DBNull not serializable on .NET Core 2.1 except at top level (using BsonMediaTypeformatter special case). +#if !NETCOREAPP2_1 // DBNull not serializable on .NET Core 2.1 except at top level (using BsonMediaTypeformatter special case). [Theory] [TestDataSet(typeof(JsonMediaTypeFormatterTests), "DBNullAsObjectTestDataCollection", TestDataVariations.AsDictionary)] public async Task ReadFromStreamAsync_RoundTripsWriteToStreamAsync_DBNullAsNull_Dictionary(Type variationType, object testData) @@ -512,7 +511,6 @@ public async Task ReadFromStreamAsync_RoundTripsWriteToStreamAsync_DBNull() // Only BSON case where DBNull.Value round-trips Assert.Equal(testData, readObj); } -#endif private class TestBsonMediaTypeFormatter : BsonMediaTypeFormatter { diff --git a/test/System.Net.Http.Formatting.Test/Formatting/DataContractJsonMediaTypeFormatterTests.cs b/test/System.Net.Http.Formatting.Test/Formatting/DataContractJsonMediaTypeFormatterTests.cs index f29126ba1..1d3d1999a 100644 --- a/test/System.Net.Http.Formatting.Test/Formatting/DataContractJsonMediaTypeFormatterTests.cs +++ b/test/System.Net.Http.Formatting.Test/Formatting/DataContractJsonMediaTypeFormatterTests.cs @@ -159,7 +159,7 @@ public async Task ReadFromStreamAsync_RoundTripsWriteToStreamAsync_KnownTypes(Ty } } -#if !NETCOREAPP // DBNull not serializable on .NET Core 2.1. +#if !NETCOREAPP2_1 // DBNull not serializable on .NET Core 2.1. // Test alternate null value [Fact] public async Task ReadFromStreamAsync_RoundTripsWriteToStreamAsync_DBNull() diff --git a/test/System.Net.Http.Formatting.Test/Formatting/JsonMediaTypeFormatterTests.cs b/test/System.Net.Http.Formatting.Test/Formatting/JsonMediaTypeFormatterTests.cs index 5a12c1132..26d85ec46 100644 --- a/test/System.Net.Http.Formatting.Test/Formatting/JsonMediaTypeFormatterTests.cs +++ b/test/System.Net.Http.Formatting.Test/Formatting/JsonMediaTypeFormatterTests.cs @@ -367,7 +367,7 @@ public async Task ReadFromStreamAsync_RoundTripsWriteToStreamAsync(Type variatio } } -#if !NETCOREAPP // DBNull not serializable on .NET Core 2.1. +#if !NETCOREAPP2_1 // DBNull not serializable on .NET Core 2.1. // Test alternate null value; always serialized as "null" [Theory] [TestDataSet(typeof(JsonMediaTypeFormatterTests), "DBNullAsObjectTestDataCollection", TestDataVariations.AllSingleInstances)] diff --git a/test/System.Net.Http.Formatting.Test/Formatting/XmlMediaTypeFormatterTests.cs b/test/System.Net.Http.Formatting.Test/Formatting/XmlMediaTypeFormatterTests.cs index 6ee72838e..28b73acfd 100644 --- a/test/System.Net.Http.Formatting.Test/Formatting/XmlMediaTypeFormatterTests.cs +++ b/test/System.Net.Http.Formatting.Test/Formatting/XmlMediaTypeFormatterTests.cs @@ -36,7 +36,7 @@ public class XmlMediaTypeFormatterTests : MediaTypeFormatterTestBase Date: Mon, 6 Mar 2023 17:26:11 -0800 Subject: [PATCH 42/54] Throw `PlatformNotSupportedException` in `netstandard1.3` (#396) - stop trying to use DCS in the JSON and XML formatters - if `UseDataContractSerializer` or `!UseXmlSerializer`: - `CanReadType(...)` and `CanWriteType(...)` always return `false` - `ReadFromStreamAsync(...)` and `WriteToStreamAsync(...)` always `throw` - change default XML formatter configuration to use `XmlSerializer` - adjust and disable tests in reaction - add tests of new `netstandard1.3` behavior - nits: - correct namespace of `SerializerConsistencyTests`; was alone in previous namespace - s/DataContractFormatter/XmlSerializerFormatter/ to reflect actual `XmlMediaTypeFormatter` test actions --- .../Formatting/JsonMediaTypeFormatter.cs | 39 ++-- .../MediaTypeFormatterCollection.cs | 6 +- .../Formatting/XmlMediaTypeFormatter.cs | 22 ++- .../Properties/Resources.Designer.cs | 18 ++ .../Properties/Resources.resx | 6 + ...DataContractJsonMediaTypeFormatterTests.cs | 152 ++++++++++++++-- .../Formatting/JsonMediaTypeFormatterTests.cs | 2 + .../Formatting/MediaTypeFormatterTestBase.cs | 6 +- .../Formatting/SerializerConsistencyTests.cs | 16 +- .../Formatting/XmlMediaTypeFormatterTests.cs | 170 ++++++++++++++++-- .../HttpClientExtensionsTest.cs | 8 + 11 files changed, 392 insertions(+), 53 deletions(-) diff --git a/src/System.Net.Http.Formatting/Formatting/JsonMediaTypeFormatter.cs b/src/System.Net.Http.Formatting/Formatting/JsonMediaTypeFormatter.cs index 775a78a32..a3bb36060 100644 --- a/src/System.Net.Http.Formatting/Formatting/JsonMediaTypeFormatter.cs +++ b/src/System.Net.Http.Formatting/Formatting/JsonMediaTypeFormatter.cs @@ -6,7 +6,9 @@ using System.Diagnostics.Contracts; using System.IO; using System.Net.Http.Headers; +#if !NETSTANDARD1_3 // Unnecessary when targeting netstandard1.3. using System.Net.Http.Internal; +#endif using System.Runtime.Serialization.Json; using System.Text; using System.Threading; @@ -214,20 +216,15 @@ public override object ReadFromStream(Type type, Stream readStream, Encoding eff { DataContractJsonSerializer dataContractSerializer = GetDataContractSerializer(type); - // JsonReaderWriterFactory is internal, CreateTextReader only supports auto-detecting the encoding - // and auto-detection fails in some cases for the netstandard1.3 project. In addition, DCS encodings are - // limited to UTF8, UTF16BE, and UTF16LE. Convert to UTF8 as we read. - Stream innerStream = string.Equals(effectiveEncoding.WebName, Utf8Encoding.WebName, StringComparison.OrdinalIgnoreCase) ? +#if NETSTANDARD1_3 // Unreachable when targeting netstandard1.3. Return just to satisfy the compiler. + return null; +#else + // DCS encodings are limited to UTF8, UTF16BE, and UTF16LE. Convert to UTF8 as we read. + Stream innerStream = + string.Equals(effectiveEncoding.WebName, Utf8Encoding.WebName, StringComparison.OrdinalIgnoreCase) ? new NonClosingDelegatingStream(readStream) : new TranscodingStream(readStream, effectiveEncoding, Utf8Encoding, leaveOpen: true); -#if NETSTANDARD1_3 - using (innerStream) - { - // Unfortunately, we're ignoring _readerQuotas. - return dataContractSerializer.ReadObject(innerStream); - } -#else // XmlDictionaryReader will always dispose of innerStream when we dispose of the reader. using XmlDictionaryReader reader = JsonReaderWriterFactory.CreateJsonReader(innerStream, Utf8Encoding, _readerQuotas, onClose: null); @@ -314,10 +311,8 @@ private void WriteObject(Stream stream, Type type, object value) { DataContractJsonSerializer dataContractSerializer = GetDataContractSerializer(type); +#if !NETSTANDARD1_3 // Unreachable when targeting netstandard1.3. // Do not dispose of the stream. WriteToStream handles that where it's needed. -#if NETSTANDARD1_3 - dataContractSerializer.WriteObject(stream, value); -#else using XmlWriter writer = JsonReaderWriterFactory.CreateJsonWriter(stream, Utf8Encoding, ownsStream: false); dataContractSerializer.WriteObject(writer, value); #endif @@ -328,15 +323,26 @@ private DataContractJsonSerializer CreateDataContractSerializer(Type type, bool { Contract.Assert(type != null); +#if NETSTANDARD1_3 // XsdDataContractExporter is not supported in netstandard1.3 + if (throwOnError) + { + throw new PlatformNotSupportedException(Error.Format( + Properties.Resources.JsonMediaTypeFormatter_DCS_NotSupported, + nameof(UseDataContractJsonSerializer))); + } + else + { + return null; + } +#else + DataContractJsonSerializer serializer = null; Exception exception = null; try { -#if !NETSTANDARD1_3 // XsdDataContractExporter is not supported in netstandard1.3 // Verify that type is a valid data contract by forcing the serializer to try to create a data contract FormattingUtilities.XsdDataContractExporter.GetRootElementName(type); -#endif serializer = CreateDataContractSerializer(type); } @@ -362,6 +368,7 @@ private DataContractJsonSerializer CreateDataContractSerializer(Type type, bool } return serializer; +#endif } /// diff --git a/src/System.Net.Http.Formatting/Formatting/MediaTypeFormatterCollection.cs b/src/System.Net.Http.Formatting/Formatting/MediaTypeFormatterCollection.cs index 4320d1ff6..864eacded 100644 --- a/src/System.Net.Http.Formatting/Formatting/MediaTypeFormatterCollection.cs +++ b/src/System.Net.Http.Formatting/Formatting/MediaTypeFormatterCollection.cs @@ -255,7 +255,11 @@ private static IEnumerable CreateDefaultFormatters() return new MediaTypeFormatter[] { new JsonMediaTypeFormatter(), - new XmlMediaTypeFormatter(), + new XmlMediaTypeFormatter() +#if NETSTANDARD1_3 // XsdDataContractExporter is not supported in netstandard1.3. Cannot use DCS. + { UseXmlSerializer = true } +#endif + , new FormUrlEncodedMediaTypeFormatter() }; } diff --git a/src/System.Net.Http.Formatting/Formatting/XmlMediaTypeFormatter.cs b/src/System.Net.Http.Formatting/Formatting/XmlMediaTypeFormatter.cs index 77a68d69b..76ee18f3d 100644 --- a/src/System.Net.Http.Formatting/Formatting/XmlMediaTypeFormatter.cs +++ b/src/System.Net.Http.Formatting/Formatting/XmlMediaTypeFormatter.cs @@ -511,6 +511,23 @@ public object InvokeGetSerializer(Type type, object value, HttpContent content) private object CreateDefaultSerializer(Type type, bool throwOnError) { Contract.Assert(type != null, "type cannot be null."); + +#if NETSTANDARD1_3 // XsdDataContractExporter is not supported in netstandard1.3 + if (!UseXmlSerializer) + { + if (throwOnError) + { + throw new PlatformNotSupportedException(Error.Format( + Properties.Resources.XmlMediaTypeFormatter_DCS_NotSupported, + nameof(UseXmlSerializer))); + } + else + { + return null; + } + } +#endif + Exception exception = null; object serializer = null; @@ -522,13 +539,12 @@ private object CreateDefaultSerializer(Type type, bool throwOnError) } else { -#if !NETSTANDARD1_3 // XsdDataContractExporter is not supported in netstandard1.3 - // REVIEW: Is there something comparable in WinRT? +#if !NETSTANDARD1_3 // Unreachable when targeting netstandard1.3. // Verify that type is a valid data contract by forcing the serializer to try to create a data contract FormattingUtilities.XsdDataContractExporter.GetRootElementName(type); -#endif serializer = CreateDataContractSerializer(type); +#endif } } catch (Exception caught) diff --git a/src/System.Net.Http.Formatting/Properties/Resources.Designer.cs b/src/System.Net.Http.Formatting/Properties/Resources.Designer.cs index 7a0bd97ba..88d4eefbc 100644 --- a/src/System.Net.Http.Formatting/Properties/Resources.Designer.cs +++ b/src/System.Net.Http.Formatting/Properties/Resources.Designer.cs @@ -390,6 +390,15 @@ internal static string JQuery13CompatModeNotSupportNestedJson { } } + /// + /// Looks up a localized string similar to Unable to validate types on this platform when {0} is 'true'. Please reset {0} or move to a supported platform, one where the 'netstandard2.0' assembly is usable.. + /// + internal static string JsonMediaTypeFormatter_DCS_NotSupported { + get { + return ResourceManager.GetString("JsonMediaTypeFormatter_DCS_NotSupported", resourceCulture); + } + } + /// /// Looks up a localized string similar to The '{0}' method returned null. It must return a JSON serializer instance.. /// @@ -768,6 +777,15 @@ internal static string UnsupportedIndent { } } + /// + /// Looks up a localized string similar to Unable to validate types on this platform when {0} is 'false'. Please set {0} or move to a supported platform, one where the 'netstandard2.0' assembly is usable.. + /// + internal static string XmlMediaTypeFormatter_DCS_NotSupported { + get { + return ResourceManager.GetString("XmlMediaTypeFormatter_DCS_NotSupported", resourceCulture); + } + } + /// /// Looks up a localized string similar to The object of type '{0}' returned by {1} must be an instance of either XmlObjectSerializer or XmlSerializer.. /// diff --git a/src/System.Net.Http.Formatting/Properties/Resources.resx b/src/System.Net.Http.Formatting/Properties/Resources.resx index 1b8df2cd2..ef5c4a7db 100644 --- a/src/System.Net.Http.Formatting/Properties/Resources.resx +++ b/src/System.Net.Http.Formatting/Properties/Resources.resx @@ -357,4 +357,10 @@ Cannot access a closed stream. + + Unable to validate types on this platform when {0} is 'true'. Please reset {0} or move to a supported platform, one where the 'netstandard2.0' assembly is usable. + + + Unable to validate types on this platform when {0} is 'false'. Please set {0} or move to a supported platform, one where the 'netstandard2.0' assembly is usable. + \ No newline at end of file diff --git a/test/System.Net.Http.Formatting.Test/Formatting/DataContractJsonMediaTypeFormatterTests.cs b/test/System.Net.Http.Formatting.Test/Formatting/DataContractJsonMediaTypeFormatterTests.cs index 1d3d1999a..7ad93ee2a 100644 --- a/test/System.Net.Http.Formatting.Test/Formatting/DataContractJsonMediaTypeFormatterTests.cs +++ b/test/System.Net.Http.Formatting.Test/Formatting/DataContractJsonMediaTypeFormatterTests.cs @@ -24,6 +24,13 @@ public DataContractJsonMediaTypeFormatter() public class DataContractJsonMediaTypeFormatterTests : MediaTypeFormatterTestBase { + public static readonly TheoryDataSet AFewValidTypes = new() + { + typeof(bool), + typeof(int), + typeof(string), + }; + public override IEnumerable ExpectedSupportedMediaTypes { get { return HttpTestData.StandardJsonMediaTypes; } @@ -87,21 +94,20 @@ public void CanReadType_ReturnsExpectedValues(Type variationType, object testDat Assert.False(isSerializable != canSupport && isSerializable, String.Format("2nd CanReadType returned wrong value for '{0}'.", variationType)); } -#if !Testing_NetStandard1_3 // XsdDataContractExporterMethods unconditionally return true without XsdDataContractExporter to use. - [Fact] - public void CanReadType_ReturnsFalse_ForInvalidDataContracts() + [Theory] + [PropertyData(nameof(AFewValidTypes))] + public void CanWriteType_ReturnsFalse_ForValidTypes(Type type) { - JsonMediaTypeFormatter formatter = new DataContractJsonMediaTypeFormatter(); - Assert.False(formatter.CanReadType(typeof(InvalidDataContract))); - } + XmlMediaTypeFormatter formatter = new(); - [Fact] - public void CanWriteType_ReturnsFalse_ForInvalidDataContracts() - { - JsonMediaTypeFormatter formatter = new DataContractJsonMediaTypeFormatter(); - Assert.False(formatter.CanWriteType(typeof(InvalidDataContract))); - } + var canWrite = formatter.CanWriteType(type); + +#if Testing_NetStandard1_3 // Different behavior in netstandard1.3 due to no DataContract validation. + Assert.False(canWrite); +#else + Assert.True(canWrite); #endif + } public class InvalidDataContract { @@ -111,6 +117,7 @@ public InvalidDataContract(string s) } } +#if !Testing_NetStandard1_3 // Cannot read or write w/ DCS in netstandard1.3. [Theory] [InlineData(typeof(IQueryable))] [InlineData(typeof(IEnumerable))] @@ -124,6 +131,7 @@ public async Task UseJsonFormatterWithNull(Type type) string serializedString = new StreamReader(memoryStream).ReadToEnd(); Assert.True(serializedString.Contains("null"), "Using Json formatter to serialize null should emit 'null'."); } +#endif [Theory] [TestDataSet(typeof(JsonMediaTypeFormatterTests), "ValueAndRefTypeTestDataCollectionExceptULong", RoundTripDataVariations)] @@ -159,6 +167,54 @@ public async Task ReadFromStreamAsync_RoundTripsWriteToStreamAsync_KnownTypes(Ty } } +#if Testing_NetStandard1_3 // Cannot read or write w/ DCS in netstandard1.3. + [Theory] + [TestDataSet(typeof(CommonUnitTestDataSets), "RepresentativeValueAndRefTypeTestDataCollection", RoundTripDataVariations)] + public async Task ReadFromStreamAsync_UsingDataContractSerializer_Throws(Type variationType, object testData) + { + // Arrange. First, get some data using XmlSerializer. + bool canSerialize = IsTypeSerializableWithJsonSerializer(variationType, testData, actuallyCheck: true) && + Assert.Http.CanRoundTrip(variationType); + if (canSerialize) + { + var formatter = new JsonMediaTypeFormatter(); + using var stream = new MemoryStream(); + using var content = new StringContent(string.Empty); + + await formatter.WriteToStreamAsync(variationType, testData, stream, content, transportContext: null); + await stream.FlushAsync(); + stream.Position = 0L; + + content.Headers.ContentLength = stream.Length; + formatter.UseDataContractJsonSerializer = true; + + // Act & Assert + await Assert.ThrowsAsync(() => + formatter.ReadFromStreamAsync(variationType, stream, content, formatterLogger: null), + "Unable to validate types on this platform when UseDataContractJsonSerializer is 'true'. " + + "Please reset UseDataContractJsonSerializer or move to a supported platform, one where the " + + "'netstandard2.0' assembly is usable."); + } + } + + [Theory] + [TestDataSet(typeof(CommonUnitTestDataSets), "RepresentativeValueAndRefTypeTestDataCollection", RoundTripDataVariations)] + public async Task WriteToStreamAsync_UsingDataContractSerializer_Throws(Type variationType, object testData) + { + // Arrange + var formatter = new JsonMediaTypeFormatter() { UseDataContractJsonSerializer = true}; + using var stream = new MemoryStream(); + using var content = new StringContent(string.Empty); + + // Act & Assert + await Assert.ThrowsAsync(() => + formatter.WriteToStreamAsync(variationType, testData, stream, content, transportContext: null), + "Unable to validate types on this platform when UseDataContractJsonSerializer is 'true'. " + + "Please reset UseDataContractJsonSerializer or move to a supported platform, one where the " + + "'netstandard2.0' assembly is usable."); + } + +#else #if !NETCOREAPP2_1 // DBNull not serializable on .NET Core 2.1. // Test alternate null value [Fact] @@ -203,6 +259,7 @@ public async Task UseDataContractJsonSerializer_Default() string serializedString = new StreamReader(memoryStream).ReadToEnd(); Assert.False(serializedString.Contains("\r\n"), "Using DCJS should emit data without indentation by default."); } +#endif [Fact] public void UseDataContractJsonSerializer_True_Indent_Throws() @@ -216,6 +273,67 @@ public void UseDataContractJsonSerializer_True_Indent_Throws() memoryStream, content, transportContext: null)); } +#if Testing_NetStandard1_3 // Cannot read or write w/ DCS in netstandard1.3. + [Fact] + public override Task Overridden_ReadFromStreamAsyncWithCancellationToken_GetsCalled() + { + return Task.CompletedTask; + } + + [Fact] + public override Task Overridden_ReadFromStreamAsyncWithoutCancellationToken_GetsCalled() + { + return Task.CompletedTask; + } + + [Fact] + public override Task Overridden_WriteToStreamAsyncWithCancellationToken_GetsCalled() + { + return Task.CompletedTask; + } + + [Fact] + public override Task Overridden_WriteToStreamAsyncWithoutCancellationToken_GetsCalled() + { + return Task.CompletedTask; + } + + [Fact] + public override Task ReadFromStreamAsync_ReadsDataButDoesNotCloseStream() + { + return Task.CompletedTask; + } + + // Attributes are in base class. + public override Task ReadFromStreamAsync_UsesCorrectCharacterEncoding(string content, string encoding, bool isDefaultEncoding) + { + return Task.CompletedTask; + } + + [Fact] + public override Task ReadFromStreamAsync_WhenContentLengthIsNull_ReadsDataButDoesNotCloseStream() + { + return Task.CompletedTask; + } + + // Attributes are in base class. + public override Task WriteToStreamAsync_UsesCorrectCharacterEncoding(string content, string encoding, bool isDefaultEncoding) + { + return Task.CompletedTask; + } + + [Fact] + public override Task WriteToStreamAsync_WhenObjectIsNull_WritesDataButDoesNotCloseStream() + { + return Task.CompletedTask; + } + + [Fact] + public override Task WriteToStreamAsync_WritesDataButDoesNotCloseStream() + { + return Task.CompletedTask; + } +#else public override Task ReadFromStreamAsync_UsesCorrectCharacterEncoding(string content, string encoding, bool isDefaultEncoding) { // Arrange @@ -239,6 +357,7 @@ public override Task WriteToStreamAsync_UsesCorrectCharacterEncoding(string cont return WriteContentUsingCorrectCharacterEncodingHelperAsync( formatter, content, formattedContent, mediaType, encoding, isDefaultEncoding); } +#endif public class TestJsonMediaTypeFormatter : DataContractJsonMediaTypeFormatter { @@ -267,8 +386,15 @@ public override DataContractJsonSerializer CreateDataContractSerializer(Type typ } } - private bool IsTypeSerializableWithJsonSerializer(Type type, object obj) + private bool IsTypeSerializableWithJsonSerializer(Type type, object obj, bool actuallyCheck = false) { +#if Testing_NetStandard1_3 // Different behavior in netstandard1.3 due to no DataContract validation. + if (!actuallyCheck) + { + return false; + } +#endif + try { new DataContractJsonSerializer(type); diff --git a/test/System.Net.Http.Formatting.Test/Formatting/JsonMediaTypeFormatterTests.cs b/test/System.Net.Http.Formatting.Test/Formatting/JsonMediaTypeFormatterTests.cs index 26d85ec46..31de4facd 100644 --- a/test/System.Net.Http.Formatting.Test/Formatting/JsonMediaTypeFormatterTests.cs +++ b/test/System.Net.Http.Formatting.Test/Formatting/JsonMediaTypeFormatterTests.cs @@ -225,6 +225,7 @@ public async Task FormatterThrowsOnReadWhenOverridenCreateReturnsNull() Assert.NotNull(formatter.InnerJsonSerializer); } +#if !Testing_NetStandard1_3 // Cannot read or write w/ DCS in netstandard1.3. [Fact] public async Task DataContractFormatterThrowsOnWriteWhenOverridenCreateFails() { @@ -309,6 +310,7 @@ public async Task DataContractFormatterThrowsOnReadWhenOverridenCreateReturnsNul Assert.NotNull(formatter.InnerDataContractSerializer); Assert.Null(formatter.InnerJsonSerializer); } +#endif [Fact] public void CanReadType_ReturnsTrueOnJtoken() diff --git a/test/System.Net.Http.Formatting.Test/Formatting/MediaTypeFormatterTestBase.cs b/test/System.Net.Http.Formatting.Test/Formatting/MediaTypeFormatterTestBase.cs index d5618f8db..b3c4e4831 100644 --- a/test/System.Net.Http.Formatting.Test/Formatting/MediaTypeFormatterTestBase.cs +++ b/test/System.Net.Http.Formatting.Test/Formatting/MediaTypeFormatterTestBase.cs @@ -152,7 +152,7 @@ public async Task ReadFromStreamAsync_WhenContentLengthIsZero_ReturnsDefaultType } [Fact] - public async Task ReadFromStreamAsync_ReadsDataButDoesNotCloseStream() + public virtual async Task ReadFromStreamAsync_ReadsDataButDoesNotCloseStream() { // Arrange TFormatter formatter = CreateFormatter(); @@ -173,7 +173,7 @@ public async Task ReadFromStreamAsync_ReadsDataButDoesNotCloseStream() } [Fact] - public async Task ReadFromStreamAsync_WhenContentLengthIsNull_ReadsDataButDoesNotCloseStream() + public virtual async Task ReadFromStreamAsync_WhenContentLengthIsNull_ReadsDataButDoesNotCloseStream() { // Arrange TFormatter formatter = CreateFormatter(); @@ -219,7 +219,7 @@ public virtual async Task WriteToStreamAsync_WhenObjectIsNull_WritesDataButDoesN } [Fact] - public async Task WriteToStreamAsync_WritesDataButDoesNotCloseStream() + public virtual async Task WriteToStreamAsync_WritesDataButDoesNotCloseStream() { // Arrange TFormatter formatter = CreateFormatter(); diff --git a/test/System.Net.Http.Formatting.Test/Formatting/SerializerConsistencyTests.cs b/test/System.Net.Http.Formatting.Test/Formatting/SerializerConsistencyTests.cs index 63dec00a3..a2ae6aa7b 100644 --- a/test/System.Net.Http.Formatting.Test/Formatting/SerializerConsistencyTests.cs +++ b/test/System.Net.Http.Formatting.Test/Formatting/SerializerConsistencyTests.cs @@ -4,12 +4,11 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using System.Net.Http.Formatting; using System.Runtime.Serialization; using System.Threading.Tasks; using Microsoft.TestCommon; -namespace System.Net.Formatting.Tests +namespace System.Net.Http.Formatting { // Tests for ensuring the serializers behave consistently in various cases. // This is important for conneg. @@ -18,7 +17,12 @@ public class SerializerConsistencyTests [Fact] public Task PartialContract() { - var c = new PartialDataContract { PropertyWithAttribute = "one", PropertyWithoutAttribute = "false" }; + var c = new PartialDataContract { + PropertyWithAttribute = "one", +#if !Testing_NetStandard1_3 // Xml formatter ignores DCS attributes but JSON one does not in netstandard1.3. + PropertyWithoutAttribute = "false" +#endif + }; return SerializerConsistencyHepers.TestAsync(c); } @@ -62,6 +66,7 @@ public Task NullEmptyWhitespaceString() return SerializerConsistencyHepers.TestAsync(source); } +#if !Testing_NetStandard1_3 // XmlSerializer is unable to write XML for a dictionary. [Fact] public Task Dictionary() { @@ -71,6 +76,7 @@ public Task Dictionary() return SerializerConsistencyHepers.TestAsync(dict); } +#endif [Fact] public Task Array() @@ -80,6 +86,7 @@ public Task Array() return SerializerConsistencyHepers.TestAsync(array); } +#if !Testing_NetStandard1_3 // XmlSerializer is unable to read XML for interfaces. [Fact] public async Task ArrayInterfaces() { @@ -99,6 +106,7 @@ public Task Linq() // So explicitly call out IEnumerable return SerializerConsistencyHepers.TestAsync(l, typeof(IEnumerable)); } +#endif [Fact] public Task StaticProps() @@ -141,8 +149,10 @@ public class PartialDataContract [DataMember] public string PropertyWithAttribute { get; set; } +#if !Testing_NetStandard1_3 // Xml formatter ignores DCS attributes but JSON one does not in netstandard1.3. // no attribute here public string PropertyWithoutAttribute { get; set; } +#endif } public class PrivateProperty // with private field diff --git a/test/System.Net.Http.Formatting.Test/Formatting/XmlMediaTypeFormatterTests.cs b/test/System.Net.Http.Formatting.Test/Formatting/XmlMediaTypeFormatterTests.cs index 28b73acfd..c83f687ec 100644 --- a/test/System.Net.Http.Formatting.Test/Formatting/XmlMediaTypeFormatterTests.cs +++ b/test/System.Net.Http.Formatting.Test/Formatting/XmlMediaTypeFormatterTests.cs @@ -41,6 +41,13 @@ public class XmlMediaTypeFormatterTests : MediaTypeFormatterTestBase AFewValidTypes = new() + { + typeof(bool), + typeof(int), + typeof(string), + }; + public static IEnumerable BunchOfTypedObjectsTestDataCollection { get { return new TestData[] { BunchOfTypedObjectsTestData, }; } @@ -100,6 +107,7 @@ public void MaxDepthReturnsCorrectValue() roundTripTestValue: 10); } +#if !Testing_NetStandard1_3 // Cannot read or write w/ DCS in netstandard1.3. [Fact] public async Task ReadDeeplyNestedObjectThrows() { @@ -110,6 +118,7 @@ public async Task ReadDeeplyNestedObjectThrows() stream.Position = 0; await Assert.ThrowsAsync(() => formatter.ReadFromStreamAsync(typeof(SampleType), stream, null, null)); } +#endif [Fact] public void Indent_RoundTrips() @@ -129,6 +138,7 @@ public void UseXmlSerializer_RoundTrips() expectedDefaultValue: false); } +#if !Testing_NetStandard1_3 // Cannot read or write w/ DCS in netstandard1.3. [Theory] [InlineData(typeof(IEnumerable))] [InlineData(typeof(IQueryable))] @@ -173,6 +183,7 @@ public async Task UseXmlSerializer_False_Indent() string serializedString = new StreamReader(memoryStream).ReadToEnd(); Assert.True(serializedString.Contains("\r\n"), "Using DCS with indent set to true should emit data with indentation."); } +#endif [Fact] public void SetSerializer_ThrowsWithNullType() @@ -225,6 +236,7 @@ public void RemoveSerializer_ThrowsWithNullType() Assert.ThrowsArgumentNull(() => { formatter.RemoveSerializer(null); }, "type"); } +#if !Testing_NetStandard1_3 // Cannot read or write w/ DCS in netstandard1.3. [Fact] public async Task FormatterThrowsOnWriteWhenOverridenCreateFails() { @@ -305,9 +317,10 @@ public async Task FormatterThrowsOnReadWhenOverridenCreateReturnsNull() Assert.NotNull(formatter.InnerDataContractSerializer); Assert.Null(formatter.InnerXmlSerializer); } +#endif [Fact] - public async Task DataContractFormatterThrowsOnWriteWhenOverridenCreateFails() + public async Task XmlSerializerFormatterThrowsOnWriteWhenOverridenCreateFails() { // Arrange TestXmlMediaTypeFormatter formatter = new TestXmlMediaTypeFormatter(); @@ -327,7 +340,7 @@ public async Task DataContractFormatterThrowsOnWriteWhenOverridenCreateFails() } [Fact] - public async Task DataContractFormatterThrowsOnWriteWhenOverridenCreateReturnsNull() + public async Task XmlSerializerFormatterThrowsOnWriteWhenOverridenCreateReturnsNull() { // Arrange TestXmlMediaTypeFormatter formatter = new TestXmlMediaTypeFormatter(); @@ -347,7 +360,7 @@ public async Task DataContractFormatterThrowsOnWriteWhenOverridenCreateReturnsNu } [Fact] - public async Task DataContractFormatterThrowsOnReadWhenOverridenCreateFails() + public async Task XmlSerializerFormatterThrowsOnReadWhenOverridenCreateFails() { // Arrange TestXmlMediaTypeFormatter formatter = new TestXmlMediaTypeFormatter(); @@ -369,7 +382,7 @@ public async Task DataContractFormatterThrowsOnReadWhenOverridenCreateFails() } [Fact] - public async Task DataContractFormatterThrowsOnReadWhenOverridenCreateReturnsNull() + public async Task XmlSerializerFormatterThrowsOnReadWhenOverridenCreateReturnsNull() { // Arrange TestXmlMediaTypeFormatter formatter = new TestXmlMediaTypeFormatter(); @@ -478,6 +491,54 @@ public async Task ReadFromStream_AsyncRoundTripsWriteToStreamUsingDataContractSe } } +#if Testing_NetStandard1_3 // Cannot read or write w/ DCS in netstandard1.3. + [Theory] + [TestDataSet(typeof(CommonUnitTestDataSets), "RepresentativeValueAndRefTypeTestDataCollection", RoundTripDataVariations)] + public async Task ReadFromStreamAsync_UsingDataContractSerializer_Throws(Type variationType, object testData) + { + // Arrange. First, get some data using XmlSerializer. + bool canSerialize = IsSerializableWithXmlSerializer(variationType, testData) && Assert.Http.CanRoundTrip(variationType); + if (canSerialize) + { + var formatter = new XmlMediaTypeFormatter() { UseXmlSerializer = true }; + using var stream = new MemoryStream(); + using var content = new StringContent(string.Empty); + + await formatter.WriteToStreamAsync(variationType, testData, stream, content, transportContext: null); + await stream.FlushAsync(); + stream.Position = 0L; + + content.Headers.ContentLength = stream.Length; + formatter.RemoveSerializer(variationType); + formatter.UseXmlSerializer = false; + + // Act & Assert + await Assert.ThrowsAsync(() => + formatter.ReadFromStreamAsync(variationType, stream, content, formatterLogger: null), + "Unable to validate types on this platform when UseXmlSerializer is 'false'. Please set " + + "UseXmlSerializer or move to a supported platform, one where the 'netstandard2.0' assembly " + + "is usable."); + } + } + + [Theory] + [TestDataSet(typeof(CommonUnitTestDataSets), "RepresentativeValueAndRefTypeTestDataCollection", RoundTripDataVariations)] + public async Task WriteToStreamAsync_UsingDataContractSerializer_Throws(Type variationType, object testData) + { + // Arrange + var formatter = new XmlMediaTypeFormatter(); + using var stream = new MemoryStream(); + using var content = new StringContent(string.Empty); + + // Act & Assert + await Assert.ThrowsAsync(() => + formatter.WriteToStreamAsync(variationType, testData, stream, content, transportContext: null), + "Unable to validate types on this platform when UseXmlSerializer is 'false'. Please set " + + "UseXmlSerializer or move to a supported platform, one where the 'netstandard2.0' assembly " + + "is usable."); + } + +#else #if !NETCOREAPP2_1 // DBNull not serializable on .NET Core 2.1. [Fact] public async Task ReadFromStreamAsync_RoundTripsWriteToStreamAsyncUsingDataContractSerializer_DBNull() @@ -523,6 +584,7 @@ public override Task ReadFromStreamAsync_UsesCorrectCharacterEncoding(string con // Act & assert return ReadFromStreamAsync_UsesCorrectCharacterEncodingHelper(formatter, content, formattedContent, mediaType, encoding, isDefaultEncoding); } +#endif [Fact] public async Task ReadFromStreamAsync_UsesGetDeserializerAndCreateXmlReader() @@ -567,6 +629,7 @@ public Task ReadFromStreamAsync_ThrowsException_WhenGetDeserializerReturnsInvali "The object of type 'JsonSerializer' returned by GetDeserializer must be an instance of either XmlObjectSerializer or XmlSerializer."); } +#if !Testing_NetStandard1_3 // Cannot read or write w/ DCS in netstandard1.3. public override Task WriteToStreamAsync_UsesCorrectCharacterEncoding(string content, string encoding, bool isDefaultEncoding) { // Arrange @@ -578,6 +641,7 @@ public override Task WriteToStreamAsync_UsesCorrectCharacterEncoding(string cont // Act & assert return WriteToStreamAsync_UsesCorrectCharacterEncodingHelper(formatter, content, formattedContent, mediaType, encoding, isDefaultEncoding); } +#endif [Fact] public async Task WriteToStreamAsync_UsesGetSerializerAndCreateXmlWriter() @@ -650,6 +714,7 @@ public void Property_WriterSettings_DefaultValues() Assert.False(formatter.WriterSettings.CheckCharacters); } +#if !Testing_NetStandard1_3 // Cannot read or write w/ DCS in netstandard1.3. [Fact] public async Task InvalidXmlCharacters_CanBeSerialized_Default() { @@ -672,8 +737,38 @@ public Task InvalidXmlCharacters_CannotBeSerialized_IfCheckCharactersIsTrue() () => formatter.WriteToStreamAsync(typeof(string), "\x16", stream, content, null), "'\x16', hexadecimal value 0x16, is an invalid character."); } +#endif + + [Theory] + [PropertyData(nameof(AFewValidTypes))] + public void CanReadType_ReturnsFalse_ForValidTypes(Type type) + { + XmlMediaTypeFormatter formatter = new(); + + var canRead = formatter.CanReadType(type); + +#if Testing_NetStandard1_3 // Different behavior in netstandard1.3 due to no DataContract validation. + Assert.False(canRead); +#else + Assert.True(canRead); +#endif + } + + [Theory] + [PropertyData(nameof(AFewValidTypes))] + public void CanWriteType_ReturnsFalse_ForValidTypes(Type type) + { + XmlMediaTypeFormatter formatter = new(); + + var canWrite = formatter.CanWriteType(type); + +#if Testing_NetStandard1_3 // Different behavior in netstandard1.3 due to no DataContract validation. + Assert.False(canWrite); +#else + Assert.True(canWrite); +#endif + } -#if !Testing_NetStandard1_3 // Different behavior in netstandard1.3 due to no DataContract validation [Fact] public void CanReadType_ReturnsFalse_ForInvalidDataContracts() { @@ -689,23 +784,66 @@ public void CanWriteType_ReturnsFalse_ForInvalidDataContracts() Assert.False(formatter.CanWriteType(typeof(InvalidDataContract))); } -#else + +#if Testing_NetStandard1_3 // Cannot read or write w/ DCS in netstandard1.3. [Fact] - public void CanReadType_InPortableLibrary_ReturnsFalse_ForInvalidDataContracts() + public override Task Overridden_ReadFromStreamAsyncWithCancellationToken_GetsCalled() { - XmlMediaTypeFormatter formatter = new XmlMediaTypeFormatter(); + return Task.CompletedTask; + } - // The formatter is unable to positively identify non readable types, so true is always returned - Assert.True(formatter.CanReadType(typeof(InvalidDataContract))); + [Fact] + public override Task Overridden_ReadFromStreamAsyncWithoutCancellationToken_GetsCalled() + { + return Task.CompletedTask; } [Fact] - public void CanWriteType_InPortableLibrary_ReturnsTrue_ForInvalidDataContracts() + public override Task Overridden_WriteToStreamAsyncWithCancellationToken_GetsCalled() { - XmlMediaTypeFormatter formatter = new XmlMediaTypeFormatter(); + return Task.CompletedTask; + } + + [Fact] + public override Task Overridden_WriteToStreamAsyncWithoutCancellationToken_GetsCalled() + { + return Task.CompletedTask; + } - // The formatter is unable to positively identify non readable types, so true is always returned - Assert.True(formatter.CanWriteType(typeof(InvalidDataContract))); + [Fact] + public override Task ReadFromStreamAsync_ReadsDataButDoesNotCloseStream() + { + return Task.CompletedTask; + } + + // Attributes are in base class. + public override Task ReadFromStreamAsync_UsesCorrectCharacterEncoding(string content, string encoding, bool isDefaultEncoding) + { + return Task.CompletedTask; + } + + [Fact] + public override Task ReadFromStreamAsync_WhenContentLengthIsNull_ReadsDataButDoesNotCloseStream() + { + return Task.CompletedTask; + } + + // Attributes are in base class. + public override Task WriteToStreamAsync_UsesCorrectCharacterEncoding(string content, string encoding, bool isDefaultEncoding) + { + return Task.CompletedTask; + } + + [Fact] + public override Task WriteToStreamAsync_WhenObjectIsNull_WritesDataButDoesNotCloseStream() + { + return Task.CompletedTask; + } + + [Fact] + public override Task WriteToStreamAsync_WritesDataButDoesNotCloseStream() + { + return Task.CompletedTask; } #endif @@ -803,6 +941,9 @@ private bool IsSerializableWithXmlSerializer(Type type, object obj) private bool IsSerializableWithDataContractSerializer(Type type, object obj) { +#if Testing_NetStandard1_3 // Different behavior in netstandard1.3 due to no DataContract validation. + return false; +#else if (Assert.Http.IsKnownUnserializable(type, obj)) { return false; @@ -822,6 +963,7 @@ private bool IsSerializableWithDataContractSerializer(Type type, object obj) } return true; +#endif } } } diff --git a/test/System.Net.Http.Formatting.Test/HttpClientExtensionsTest.cs b/test/System.Net.Http.Formatting.Test/HttpClientExtensionsTest.cs index 5007ff4ac..2e6dc1d73 100644 --- a/test/System.Net.Http.Formatting.Test/HttpClientExtensionsTest.cs +++ b/test/System.Net.Http.Formatting.Test/HttpClientExtensionsTest.cs @@ -66,6 +66,7 @@ public void PostAsXmlAsync_String_WhenClientIsNull_ThrowsException() Assert.ThrowsArgumentNull(() => client.PostAsXmlAsync("http://www.example.com", new object()), "client"); } +#if !Testing_NetStandard1_3 // Avoid "The configured formatter 'System.Net.Http.Formatting.XmlMediaTypeFormatter' cannot write an object of type 'Object'." [Fact] public void PostAsXmlAsync_String_WhenUriIsNull_ThrowsException() { @@ -81,6 +82,7 @@ public async Task PostAsXmlAsync_String_UsesXmlMediaTypeFormatter() var content = Assert.IsType>(response.RequestMessage.Content); Assert.IsType(content.Formatter); } +#endif [Fact] public void PostAsync_String_WhenClientIsNull_ThrowsException() @@ -195,6 +197,7 @@ public void PutAsXmlAsync_String_WhenClientIsNull_ThrowsException() Assert.ThrowsArgumentNull(() => client.PutAsXmlAsync("http://www.example.com", new object()), "client"); } +#if !Testing_NetStandard1_3 // Avoid "The configured formatter 'System.Net.Http.Formatting.XmlMediaTypeFormatter' cannot write an object of type 'Object'." [Fact] public void PutAsXmlAsync_String_WhenUriIsNull_ThrowsException() { @@ -210,6 +213,7 @@ public async Task PutAsXmlAsync_String_UsesXmlMediaTypeFormatter() var content = Assert.IsType>(response.RequestMessage.Content); Assert.IsType(content.Formatter); } +#endif [Fact] public void PutAsync_String_WhenClientIsNull_ThrowsException() @@ -324,6 +328,7 @@ public void PostAsXmlAsync_Uri_WhenClientIsNull_ThrowsException() Assert.ThrowsArgumentNull(() => client.PostAsXmlAsync(new Uri("http://www.example.com"), new object()), "client"); } +#if !Testing_NetStandard1_3 // Avoid "The configured formatter 'System.Net.Http.Formatting.XmlMediaTypeFormatter' cannot write an object of type 'Object'." [Fact] public void PostAsXmlAsync_Uri_WhenUriIsNull_ThrowsException() { @@ -339,6 +344,7 @@ public async Task PostAsXmlAsync_Uri_UsesXmlMediaTypeFormatter() var content = Assert.IsType>(response.RequestMessage.Content); Assert.IsType(content.Formatter); } +#endif [Fact] public void PostAsync_Uri_WhenClientIsNull_ThrowsException() @@ -453,6 +459,7 @@ public void PutAsXmlAsync_Uri_WhenClientIsNull_ThrowsException() Assert.ThrowsArgumentNull(() => client.PutAsXmlAsync(new Uri("http://www.example.com"), new object()), "client"); } +#if !Testing_NetStandard1_3 // Avoid "The configured formatter 'System.Net.Http.Formatting.XmlMediaTypeFormatter' cannot write an object of type 'Object'." [Fact] public void PutAsXmlAsync_Uri_WhenUriIsNull_ThrowsException() { @@ -468,6 +475,7 @@ public async Task PutAsXmlAsync_Uri_UsesXmlMediaTypeFormatter() var content = Assert.IsType>(response.RequestMessage.Content); Assert.IsType(content.Formatter); } +#endif [Fact] public void PutAsync_Uri_WhenClientIsNull_ThrowsException() From 2da072a141878392d924657f855258c65380116f Mon Sep 17 00:00:00 2001 From: Doug Bunting <6431421+dougbu@users.noreply.github.com> Date: Mon, 6 Mar 2023 22:07:37 -0800 Subject: [PATCH 43/54] Use `msbuild` from VS 2022 if available (#395) * Use `msbuild` from VS 2022 if available - should ease local and TeamCity builds - make `%InstallDir%` unquoted (unlike `%vswhere%`) - shorten `%Path%` slightly - nits: - use script location more; no need to change directories * React to new build issues - follow up to #396 (unsure why new FxCop and "spelling" errors didn't fail that PR) * Put `PortReserver` users into an xUnit collection --- build.cmd | 35 +++++++++++++------ eng/GetXCopyMSBuild.ps1 | 3 +- .../GlobalSuppressions.cs | 2 ++ .../Properties/Resources.resx | 4 +-- test/Microsoft.TestCommon/PortReserver.cs | 5 +++ ...DataContractJsonMediaTypeFormatterTests.cs | 4 +-- .../Formatting/XmlMediaTypeFormatterTests.cs | 4 +-- .../OwinHostIntegrationTest.cs | 1 + .../Authentication/BasicOverHttpTest.cs | 1 + .../HttpSelfHostResponseTest.cs | 1 + .../HttpSelfHostServerTest.cs | 1 + 11 files changed, 44 insertions(+), 17 deletions(-) diff --git a/build.cmd b/build.cmd index 500eb973a..6b591d1da 100644 --- a/build.cmd +++ b/build.cmd @@ -1,5 +1,4 @@ @echo off -pushd %~dp0 setlocal if exist bin goto Build @@ -29,7 +28,7 @@ for /f "usebackq tokens=*" %%i in (`%vswhere% -version 16 -latest -prerelease -p -requires Microsoft.Net.Component.4.5.2.TargetingPack ^ -requires Microsoft.Net.Component.4.6.2.TargetingPack ^ -property installationPath`) do ( - set InstallDir="%%i" + set "InstallDir=%%i" ) if not DEFINED InstallDir ( @@ -38,35 +37,53 @@ if not DEFINED InstallDir ( goto BuildFail ) -REM Find or install MSBuild. Need v17.4 due to our .NET SDK choice. +REM Find a 64bit MSBuild and add it to path. Require v17.4 or later due to our .NET SDK choice. +REM Check for VS2022 first. +set InstallDir= +for /f "usebackq tokens=*" %%i in (`%vswhere% -version 17.4 -latest -prerelease -products * ^ + -requires Microsoft.Component.MSBuild ^ + -property installationPath`) do ( + set "InstallDir=%%i" +) + +if DEFINED InstallDir ( + REM Add MSBuild to the path. + set "PATH=%InstallDir%\MSBuild\Current\Bin;%PATH%" + goto FoundMSBuild +) + +REM Otherwise find or install an xcopy-able MSBuild. +echo "Could not find a VS2022 installation with the necessary components (MSBuild). Falling back..." + set "MSBuildVersion=17.4.1" set "Command=[System.Threading.Thread]::CurrentThread.CurrentCulture = ''" set "Command=%Command%; [System.Threading.Thread]::CurrentThread.CurrentUICulture = ''" set "Command=%Command%; try { & '%~dp0eng\GetXCopyMSBuild.ps1' %MSBuildVersion%; exit $LASTEXITCODE }" set "Command=%Command% catch { write-host $_; exit 1 }" -PowerShell -NoProfile -NoLogo -ExecutionPolicy Bypass -Command "%Command%" +PowerShell -NoProfile -NoLogo -ExecutionPolicy Bypass -Command "%Command%" if %ERRORLEVEL% neq 0 goto BuildFail REM Add MSBuild to the path. -set "PATH=%CD%\.msbuild\%MSBuildVersion%\tools\MSBuild\Current\Bin\;%PATH%" +set "PATH=%~dp0.msbuild\%MSBuildVersion%\tools\MSBuild\Current\Bin;%PATH%" +:FoundMSBuild REM Configure NuGet operations to work w/in this repo i.e. do not pollute system packages folder. REM Note this causes two copies of packages restored using packages.config to land in this folder e.g. REM StyleCpy.5.0.0/ and stylecop/5.0.0/. -set "NUGET_PACKAGES=%CD%\packages" +set "NUGET_PACKAGES=%~dp0packages" REM Are we running in a local dev environment (not on CI)? if DEFINED CI (set Desktop=false) else if DEFINED TEAMCITY_VERSION (set Desktop=false) else (set Desktop=true) if "%1" == "" goto BuildDefaults -MSBuild Runtime.msbuild /m /nr:false /p:Platform="Any CPU" /p:Desktop=%Desktop% /v:M ^ +MSBuild "%~dp0Runtime.msbuild" /m /nr:false /p:Platform="Any CPU" /p:Desktop=%Desktop% /v:M ^ /fl /fileLoggerParameters:LogFile=bin\msbuild.log;Verbosity=Normal /consoleLoggerParameters:Summary /t:%* if %ERRORLEVEL% neq 0 goto BuildFail goto BuildSuccess :BuildDefaults -MSBuild Runtime.msbuild /m /nr:false /p:Platform="Any CPU" /p:Desktop=%Desktop% /v:M ^ +MSBuild "%~dp0Runtime.msbuild" /m /nr:false /p:Platform="Any CPU" /p:Desktop=%Desktop% /v:M ^ /fl /fileLoggerParameters:LogFile=bin\msbuild.log;Verbosity=Normal /consoleLoggerParameters:Summary if %ERRORLEVEL% neq 0 goto BuildFail goto BuildSuccess @@ -74,13 +91,11 @@ goto BuildSuccess :BuildFail echo. echo *** BUILD FAILED *** -popd endlocal exit /B 999 :BuildSuccess echo. echo **** BUILD SUCCESSFUL *** -popd endlocal exit /B 0 diff --git a/eng/GetXCopyMSBuild.ps1 b/eng/GetXCopyMSBuild.ps1 index 6ab853c30..667839289 100644 --- a/eng/GetXCopyMSBuild.ps1 +++ b/eng/GetXCopyMSBuild.ps1 @@ -39,4 +39,5 @@ function InitializeXCopyMSBuild([string]$packageVersion, [bool]$install, [string return Join-Path $packageDir 'tools' } -InitializeXCopyMSBuild -packageVersion $Version -install $true -ToolsDir (join-path $PWD .msbuild) +$RepoRoot = Resolve-Path (Join-Path $PSScriptRoot '..\') +InitializeXCopyMSBuild -packageVersion $Version -install $true -ToolsDir (join-path $RepoRoot .msbuild) diff --git a/src/System.Net.Http.Formatting/GlobalSuppressions.cs b/src/System.Net.Http.Formatting/GlobalSuppressions.cs index deefc5652..d815e56e6 100644 --- a/src/System.Net.Http.Formatting/GlobalSuppressions.cs +++ b/src/System.Net.Http.Formatting/GlobalSuppressions.cs @@ -6,3 +6,5 @@ [assembly: SuppressMessage("Microsoft.Design", "CA2210:AssembliesShouldHaveValidStrongNames")] [assembly: SuppressMessage("Microsoft.Design", "CA1020:AvoidNamespacesWithFewTypes", Scope = "namespace", Target = "System.Net.Http.Headers", Justification = "We follow the layout of System.Net.Http.")] [assembly: SuppressMessage("Microsoft.Design", "CA1020:AvoidNamespacesWithFewTypes", Scope = "namespace", Target = "System.Net.Http.Handlers", Justification = "Handlers provide an extensibility hook which we want to keep in a separate namespace.")] +// Some resources are specific to the netstandard1.3 assembly +[assembly: SuppressMessage("Microsoft.Web.FxCop", "MW1000:UnusedResourceUsageRule", Justification = "There are a few unused resources due to missing netstandard1.3 features.")] diff --git a/src/System.Net.Http.Formatting/Properties/Resources.resx b/src/System.Net.Http.Formatting/Properties/Resources.resx index ef5c4a7db..82d90e68c 100644 --- a/src/System.Net.Http.Formatting/Properties/Resources.resx +++ b/src/System.Net.Http.Formatting/Properties/Resources.resx @@ -358,9 +358,9 @@ Cannot access a closed stream. - Unable to validate types on this platform when {0} is 'true'. Please reset {0} or move to a supported platform, one where the 'netstandard2.0' assembly is usable. + Unable to validate types on this platform when {0} is 'true'. Please reset {0} or move to a supported platform, one where the .NET Standard 2.0 assembly is usable. - Unable to validate types on this platform when {0} is 'false'. Please set {0} or move to a supported platform, one where the 'netstandard2.0' assembly is usable. + Unable to validate types on this platform when {0} is 'false'. Please set {0} or move to a supported platform, one where the .NET Standard 2.0 assembly is usable. \ No newline at end of file diff --git a/test/Microsoft.TestCommon/PortReserver.cs b/test/Microsoft.TestCommon/PortReserver.cs index f085399af..bfa95d610 100644 --- a/test/Microsoft.TestCommon/PortReserver.cs +++ b/test/Microsoft.TestCommon/PortReserver.cs @@ -12,6 +12,11 @@ namespace Microsoft.TestCommon { + [Xunit.CollectionDefinition("PortReserver Collection", DisableParallelization = true)] + public class PortReserverCollection + { + } + /// /// This class allocates ports while ensuring that: /// 1. Ports that are permanently taken (or taken for the duration of the test) are not being attempted to be used. diff --git a/test/System.Net.Http.Formatting.Test/Formatting/DataContractJsonMediaTypeFormatterTests.cs b/test/System.Net.Http.Formatting.Test/Formatting/DataContractJsonMediaTypeFormatterTests.cs index 7ad93ee2a..b94b19598 100644 --- a/test/System.Net.Http.Formatting.Test/Formatting/DataContractJsonMediaTypeFormatterTests.cs +++ b/test/System.Net.Http.Formatting.Test/Formatting/DataContractJsonMediaTypeFormatterTests.cs @@ -193,7 +193,7 @@ await Assert.ThrowsAsync(() => formatter.ReadFromStreamAsync(variationType, stream, content, formatterLogger: null), "Unable to validate types on this platform when UseDataContractJsonSerializer is 'true'. " + "Please reset UseDataContractJsonSerializer or move to a supported platform, one where the " + - "'netstandard2.0' assembly is usable."); + ".NET Standard 2.0 assembly is usable."); } } @@ -211,7 +211,7 @@ await Assert.ThrowsAsync(() => formatter.WriteToStreamAsync(variationType, testData, stream, content, transportContext: null), "Unable to validate types on this platform when UseDataContractJsonSerializer is 'true'. " + "Please reset UseDataContractJsonSerializer or move to a supported platform, one where the " + - "'netstandard2.0' assembly is usable."); + ".NET Standard 2.0 assembly is usable."); } #else diff --git a/test/System.Net.Http.Formatting.Test/Formatting/XmlMediaTypeFormatterTests.cs b/test/System.Net.Http.Formatting.Test/Formatting/XmlMediaTypeFormatterTests.cs index c83f687ec..8dd69fe12 100644 --- a/test/System.Net.Http.Formatting.Test/Formatting/XmlMediaTypeFormatterTests.cs +++ b/test/System.Net.Http.Formatting.Test/Formatting/XmlMediaTypeFormatterTests.cs @@ -516,7 +516,7 @@ public async Task ReadFromStreamAsync_UsingDataContractSerializer_Throws(Type va await Assert.ThrowsAsync(() => formatter.ReadFromStreamAsync(variationType, stream, content, formatterLogger: null), "Unable to validate types on this platform when UseXmlSerializer is 'false'. Please set " + - "UseXmlSerializer or move to a supported platform, one where the 'netstandard2.0' assembly " + + "UseXmlSerializer or move to a supported platform, one where the .NET Standard 2.0 assembly " + "is usable."); } } @@ -534,7 +534,7 @@ public async Task WriteToStreamAsync_UsingDataContractSerializer_Throws(Type var await Assert.ThrowsAsync(() => formatter.WriteToStreamAsync(variationType, testData, stream, content, transportContext: null), "Unable to validate types on this platform when UseXmlSerializer is 'false'. Please set " + - "UseXmlSerializer or move to a supported platform, one where the 'netstandard2.0' assembly " + + "UseXmlSerializer or move to a supported platform, one where the .NET Standard 2.0 assembly " + "is usable."); } diff --git a/test/System.Web.Http.Owin.Test/OwinHostIntegrationTest.cs b/test/System.Web.Http.Owin.Test/OwinHostIntegrationTest.cs index 17e2d15d0..1300d1fd5 100644 --- a/test/System.Web.Http.Owin.Test/OwinHostIntegrationTest.cs +++ b/test/System.Web.Http.Owin.Test/OwinHostIntegrationTest.cs @@ -12,6 +12,7 @@ namespace System.Web.Http.Owin { + [Xunit.Collection("PortReserver Collection")] // Avoid conflicts between different PortReserver consumers. public class OwinHostIntegrationTest { [Fact] diff --git a/test/System.Web.Http.SelfHost.Test/Authentication/BasicOverHttpTest.cs b/test/System.Web.Http.SelfHost.Test/Authentication/BasicOverHttpTest.cs index 0b2a5739e..85cde9467 100644 --- a/test/System.Web.Http.SelfHost.Test/Authentication/BasicOverHttpTest.cs +++ b/test/System.Web.Http.SelfHost.Test/Authentication/BasicOverHttpTest.cs @@ -10,6 +10,7 @@ namespace System.Web.Http { + [Xunit.Collection("PortReserver Collection")] // Avoid conflicts between different PortReserver consumers. public class BasicOverHttpTest { [Fact] diff --git a/test/System.Web.Http.SelfHost.Test/HttpSelfHostResponseTest.cs b/test/System.Web.Http.SelfHost.Test/HttpSelfHostResponseTest.cs index bb192b922..8a8919057 100644 --- a/test/System.Web.Http.SelfHost.Test/HttpSelfHostResponseTest.cs +++ b/test/System.Web.Http.SelfHost.Test/HttpSelfHostResponseTest.cs @@ -12,6 +12,7 @@ namespace System.Web.Http.SelfHost { + [Xunit.Collection("PortReserver Collection")] // Avoid conflicts between different PortReserver consumers. public class HttpSelfHostResponseTest { [Fact] diff --git a/test/System.Web.Http.SelfHost.Test/HttpSelfHostServerTest.cs b/test/System.Web.Http.SelfHost.Test/HttpSelfHostServerTest.cs index afd3b77c2..a53f4ba3c 100644 --- a/test/System.Web.Http.SelfHost.Test/HttpSelfHostServerTest.cs +++ b/test/System.Web.Http.SelfHost.Test/HttpSelfHostServerTest.cs @@ -18,6 +18,7 @@ namespace System.Web.Http.SelfHost { + [Xunit.Collection("PortReserver Collection")] // Avoid conflicts between different PortReserver consumers. public class HttpSelfHostServerTest : IDisposable { private HttpSelfHostServer server = null; From 6949d439be1d13ad0e1ac47a3c0db2c81eb9c71d Mon Sep 17 00:00:00 2001 From: Doug Bunting <6431421+dougbu@users.noreply.github.com> Date: Tue, 7 Mar 2023 16:39:29 -0800 Subject: [PATCH 44/54] Restore `pushd` and `popd` (#397) - oops, needed on TeamCity to find global.json - left this unconditional, mostly for the odd local build from another folder --- build.cmd | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build.cmd b/build.cmd index 6b591d1da..5802269fe 100644 --- a/build.cmd +++ b/build.cmd @@ -75,6 +75,7 @@ set "NUGET_PACKAGES=%~dp0packages" REM Are we running in a local dev environment (not on CI)? if DEFINED CI (set Desktop=false) else if DEFINED TEAMCITY_VERSION (set Desktop=false) else (set Desktop=true) +pushd %~dp0 if "%1" == "" goto BuildDefaults MSBuild "%~dp0Runtime.msbuild" /m /nr:false /p:Platform="Any CPU" /p:Desktop=%Desktop% /v:M ^ @@ -91,11 +92,13 @@ goto BuildSuccess :BuildFail echo. echo *** BUILD FAILED *** +popd endlocal exit /B 999 :BuildSuccess echo. echo **** BUILD SUCCESSFUL *** +popd endlocal exit /B 0 From 509661e54f2d985c568adc491d02327ab7fe9bce Mon Sep 17 00:00:00 2001 From: Doug Bunting <6431421+dougbu@users.noreply.github.com> Date: Wed, 15 Mar 2023 15:20:25 -0700 Subject: [PATCH 45/54] Separate Microsoft.TestCommon more (#400) - pre-restore and prebuild the project before anything that depends on it - avoid references from other test projects doing any real work - make ordering even more explicit - avoid confusion between batching builds and `$(BuildInParallel)` - turns out this also reduces the number of double writes binary logs show significantly --- Runtime.msbuild | 44 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/Runtime.msbuild b/Runtime.msbuild index c77f8bc72..815aaf93e 100644 --- a/Runtime.msbuild +++ b/Runtime.msbuild @@ -52,14 +52,26 @@ + + <_Testing_NetStandard1_3 Include="true;false" /> + + - - <_ToRestore Include="Runtime.sln" /> - <_ToRestore Include="test\Microsoft.TestCommon\Microsoft.TestCommon.csproj" - AdditionalProperties="Testing_NetStandard1_3=true" /> - - + + + @@ -79,14 +91,28 @@ - - + + + + + + Properties="Configuration=$(Configuration);CodeAnalysis=$(CodeAnalysis);StyleCopEnabled=$(StyleCopEnabled); + VisualStudioVersion=$(VisualStudioVersion)" /> From 1231b77d79956152831b75ad7f094f844251b97f Mon Sep 17 00:00:00 2001 From: William Godbe Date: Thu, 16 Mar 2023 12:56:48 -0700 Subject: [PATCH 46/54] Prepare for 5.3.0-preview1 (#401) * Prepare for 5.3.0-preview1 * Update AssemblyVersions for formatting --- src/CommonAssemblyInfo.cs | 13 +++++++++---- src/CommonAssemblyInfo.vb | 4 ++-- .../System.Net.Http.Formatting.ns1_3.csproj | 2 +- .../System.Net.Http.Formatting.ns2_0.csproj | 2 +- .../System.Net.Http.Formatting.csproj | 2 +- src/WebApiHelpPage/Areas/HelpPage/Views/Web.config | 2 +- .../VB/Areas/HelpPage/Views/Web.config | 2 +- test/Microsoft.Web.Mvc.Test/Test/VersionTest.cs | 2 +- test/System.Web.WebPages.Test/App.config | 2 +- 9 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/CommonAssemblyInfo.cs b/src/CommonAssemblyInfo.cs index 23f575974..de4e5d379 100644 --- a/src/CommonAssemblyInfo.cs +++ b/src/CommonAssemblyInfo.cs @@ -24,12 +24,17 @@ // BUILD_GENERATED_VERSION will be set in any CI build. Versions below are not used. // =================================================================================== -#if (ASPNETMVC && (ASPNETWEBPAGES || ASPNETFACEBOOK)) || (ASPNETWEBPAGES && ASPNETFACEBOOK) -#error Runtime projects cannot define more than one of ASPNETMVC, ASPNETWEBPAGES or ASPNETFACEBOOK +#if (ASPNETMVC && (ASPNETWEBPAGES || ASPNETFACEBOOK || ASPNETHTTPFORMATTING)) || (ASPNETWEBPAGES && (ASPNETFACEBOOK || ASPNETHTTPFORMATTING)) || (ASPNETFACEBOOK && ASPNETHTTPFORMATTING) +#error Runtime projects cannot define more than one of ASPNETMVC, ASPNETWEBPAGES, ASPNETFACEBOOK, or ASPNETHTTPFORMATTING +#elif ASPNETHTTPFORMATTING +#if !BUILD_GENERATED_VERSION +[assembly: AssemblyVersion("6.0.0.0")] // ASPNETHTTPFORMATTING +[assembly: AssemblyFileVersion("6.0.0.0")] // ASPNETHTTPFORMATTING +#endif #elif ASPNETMVC #if !BUILD_GENERATED_VERSION -[assembly: AssemblyVersion("5.2.9.0")] // ASPNETMVC -[assembly: AssemblyFileVersion("5.2.9.0")] // ASPNETMVC +[assembly: AssemblyVersion("5.3.0.0")] // ASPNETMVC +[assembly: AssemblyFileVersion("5.3.0.0")] // ASPNETMVC #endif [assembly: AssemblyProduct("Microsoft ASP.NET MVC")] #elif ASPNETWEBPAGES diff --git a/src/CommonAssemblyInfo.vb b/src/CommonAssemblyInfo.vb index 591dc0d89..d5dac6315 100644 --- a/src/CommonAssemblyInfo.vb +++ b/src/CommonAssemblyInfo.vb @@ -20,6 +20,6 @@ Imports System.Runtime.InteropServices ' Version numbers are automatically generated based on regular expressions. ' =========================================================================== - 'ASPNETMVC - 'ASPNETMVC + 'ASPNETMVC + 'ASPNETMVC \ No newline at end of file diff --git a/src/System.Net.Http.Formatting.ns1_3/System.Net.Http.Formatting.ns1_3.csproj b/src/System.Net.Http.Formatting.ns1_3/System.Net.Http.Formatting.ns1_3.csproj index 7e388ca5b..cb723ee1d 100644 --- a/src/System.Net.Http.Formatting.ns1_3/System.Net.Http.Formatting.ns1_3.csproj +++ b/src/System.Net.Http.Formatting.ns1_3/System.Net.Http.Formatting.ns1_3.csproj @@ -7,7 +7,7 @@ $(OutputPath)ns1_3\ $(OutputPath)$(AssemblyName).xml false - $(DefineConstants);ASPNETMVC + $(DefineConstants);ASPNETHTTPFORMATTING 1591 false $(Configurations);CodeAnalysis diff --git a/src/System.Net.Http.Formatting.ns2_0/System.Net.Http.Formatting.ns2_0.csproj b/src/System.Net.Http.Formatting.ns2_0/System.Net.Http.Formatting.ns2_0.csproj index b44945028..b31b98d40 100644 --- a/src/System.Net.Http.Formatting.ns2_0/System.Net.Http.Formatting.ns2_0.csproj +++ b/src/System.Net.Http.Formatting.ns2_0/System.Net.Http.Formatting.ns2_0.csproj @@ -7,7 +7,7 @@ $(OutputPath)ns2_0\ $(OutputPath)$(AssemblyName).xml false - $(DefineConstants);ASPNETMVC + $(DefineConstants);ASPNETHTTPFORMATTING 1591 false $(Configurations);CodeAnalysis diff --git a/src/System.Net.Http.Formatting/System.Net.Http.Formatting.csproj b/src/System.Net.Http.Formatting/System.Net.Http.Formatting.csproj index d52549eec..bf2cf46b1 100644 --- a/src/System.Net.Http.Formatting/System.Net.Http.Formatting.csproj +++ b/src/System.Net.Http.Formatting/System.Net.Http.Formatting.csproj @@ -10,7 +10,7 @@ $(OutputPath)$(AssemblyName).xml $(CodeAnalysis) ..\Strict.ruleset - $(DefineConstants);ASPNETMVC + $(DefineConstants);ASPNETHTTPFORMATTING Client 1591 diff --git a/src/WebApiHelpPage/Areas/HelpPage/Views/Web.config b/src/WebApiHelpPage/Areas/HelpPage/Views/Web.config index c9f6f08cb..5ce411ea8 100644 --- a/src/WebApiHelpPage/Areas/HelpPage/Views/Web.config +++ b/src/WebApiHelpPage/Areas/HelpPage/Views/Web.config @@ -9,7 +9,7 @@ - + diff --git a/src/WebApiHelpPage/VB/Areas/HelpPage/Views/Web.config b/src/WebApiHelpPage/VB/Areas/HelpPage/Views/Web.config index 8ff9486fe..b44b016c0 100644 --- a/src/WebApiHelpPage/VB/Areas/HelpPage/Views/Web.config +++ b/src/WebApiHelpPage/VB/Areas/HelpPage/Views/Web.config @@ -9,7 +9,7 @@ - + diff --git a/test/Microsoft.Web.Mvc.Test/Test/VersionTest.cs b/test/Microsoft.Web.Mvc.Test/Test/VersionTest.cs index 32e4bc1d7..5235e0fee 100644 --- a/test/Microsoft.Web.Mvc.Test/Test/VersionTest.cs +++ b/test/Microsoft.Web.Mvc.Test/Test/VersionTest.cs @@ -13,7 +13,7 @@ public class VersionTest public void VerifyMVCVersionChangesAreIntentional() { Version mvcVersion = VersionTestHelper.GetVersionFromAssembly("System.Web.Mvc", typeof(Controller)); - Assert.Equal(new Version(5, 2, 9, 0), mvcVersion); + Assert.Equal(new Version(5, 3, 0, 0), mvcVersion); } } } diff --git a/test/System.Web.WebPages.Test/App.config b/test/System.Web.WebPages.Test/App.config index e0565507e..df97ed804 100644 --- a/test/System.Web.WebPages.Test/App.config +++ b/test/System.Web.WebPages.Test/App.config @@ -11,7 +11,7 @@ - + From 4844a3c7d1602d8a7674b5ebd5143f660ffd098c Mon Sep 17 00:00:00 2001 From: William Godbe Date: Thu, 7 Mar 2024 15:06:47 -0800 Subject: [PATCH 47/54] Create azure-pipelines-public.yml (#415) --- azure-pipelines-public.yml | 100 +++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 azure-pipelines-public.yml diff --git a/azure-pipelines-public.yml b/azure-pipelines-public.yml new file mode 100644 index 000000000..b8b92278a --- /dev/null +++ b/azure-pipelines-public.yml @@ -0,0 +1,100 @@ +parameters: + # Test only the Release build by default. +- name: ReleaseBuildTarget + displayName: 'Build which target for Release?' + type: string + values: [ Build, Integration, UnitTest ] + default: UnitTest +- name: OtherBuildTarget + displayName: 'Build which target for Debug/CodeAnalysis?' + type: string + values: [ Build, Integration, UnitTest ] + default: Build + +variables: +- name: DOTNET_CLI_TELEMETRY_OPTOUT + value: 1 +- name: DOTNET_NOLOGO + value: 1 + # Run CodeQL3000 tasks in a separate internal pipeline; not needed here. +- name: Codeql.SkipTaskAutoInjection + value: true + +trigger: [main] +pr: ['*'] + +jobs: +- job: build + displayName: Build + pool: + ${{ if eq(variables['System.TeamProject'], 'public') }}: + name: NetCore-Svc-Public + demands: ImageOverride -equals windows.vs2019.amd64.open + ${{ else }}: + name: NetCore1ESPool-Svc-Internal + demands: ImageOverride -equals windows.vs2019.amd64 + timeoutInMinutes: 30 + + strategy: + matrix: + Release: + _BuildTarget: ${{ parameters.ReleaseBuildTarget }} + _Configuration: Release + _StyleCopEnabled: true + # Do CG work only in internal pipelines. + skipComponentGovernanceDetection: ${{ eq(variables['System.TeamProject'], 'public') }} + Debug: + _BuildTarget: ${{ parameters.OtherBuildTarget }} + _Configuration: Debug + _StyleCopEnabled: false + # Do not redo CG work. Configuration changes in this part of the matrix are not relevant to CG. + skipComponentGovernanceDetection: true + CodeAnalysis: + _BuildTarget: ${{ parameters.OtherBuildTarget }} + _Configuration: CodeAnalysis + _StyleCopEnabled: false + # Do not redo CG work. Configuration changes in this part of the matrix are not relevant to CG. + skipComponentGovernanceDetection: true + + steps: + - checkout: self + clean: true + displayName: Checkout + + - task: UseDotNet@2 + displayName: Get .NET SDK + inputs: + useGlobalJson: true + - task: UseDotNet@2 + displayName: Get .NET 2.1 runtime + inputs: + packageType: runtime + version: '2.1.x' + + - script: .\build.cmd EnableSkipStrongNames + displayName: Enable SkipStrongNames + - script: .\build.cmd $(_BuildTarget) ^ + /binaryLogger:artifacts/msbuild.binlog /p:Configuration=$(_Configuration) /p:StyleCopEnabled=$(_StyleCopEnabled) ^ + /fileLoggerParameters:LogFile=artifacts/msbuild.log;Summary;Verbosity=minimal + displayName: Build + + - publish: ./bin/$(_Configuration)/Test/TestResults/ + artifact: $(_Configuration) Test Results $(System.JobId) + condition: and(always(), ne(variables._BuildTarget, 'Build')) + continueOnError: true + displayName: Upload test results + - task: PublishTestResults@2 + condition: and(always(), ne(variables._BuildTarget, 'Build')) + continueOnError: true + displayName: Publish test results + inputs: + mergeTestResults: true + searchFolder: ./bin/$(_Configuration)/Test/TestResults/ + testResultsFiles: '*.xml' + testRunner: xUnit + testRunTitle: $(_Configuration) + + - publish: ./artifacts/ + artifact: $(_Configuration) Logs $(System.JobId) + condition: always() + displayName: Upload logs From d3c4055b361d3644df467c52b43b80576652180c Mon Sep 17 00:00:00 2001 From: William Godbe Date: Thu, 7 Mar 2024 17:24:33 -0800 Subject: [PATCH 48/54] Switch to 1es template (#416) * Remove Codeql3000 * Switch to 1es templates * Fix publish * Fix nuget.config * ^ * BL * public stage * No binlog * params * Fix it again --- .codeql.yml | 64 ---- .config/tsaoptions.json | 12 - azure-pipelines-public.yml | 81 +---- azure-pipelines.yml | 96 ++---- eng/common/templates/job/execute-sdl.yml | 134 --------- eng/common/templates/job/job.yml | 230 -------------- eng/common/templates/job/onelocbuild.yml | 107 ------- .../templates/job/publish-build-assets.yml | 150 ---------- eng/common/templates/job/source-build.yml | 74 ----- .../templates/job/source-index-stage1.yml | 67 ----- eng/common/templates/jobs/codeql-build.yml | 31 -- eng/common/templates/jobs/jobs.yml | 97 ------ eng/common/templates/jobs/source-build.yml | 46 --- .../templates/post-build/common-variables.yml | 22 -- .../templates/post-build/post-build.yml | 281 ------------------ .../post-build/setup-maestro-vars.yml | 70 ----- .../post-build/trigger-subscription.yml | 13 - .../templates/steps/add-build-to-channel.yml | 13 - eng/common/templates/steps/build-reason.yml | 12 - eng/common/templates/steps/execute-codeql.yml | 32 -- eng/common/templates/steps/execute-sdl.yml | 88 ------ eng/common/templates/steps/generate-sbom.yml | 48 --- eng/common/templates/steps/publish-logs.yml | 23 -- eng/common/templates/steps/retain-build.yml | 28 -- eng/common/templates/steps/run-on-unix.yml | 7 - eng/common/templates/steps/run-on-windows.yml | 7 - .../steps/run-script-ifequalelse.yml | 33 -- eng/common/templates/steps/send-to-helix.yml | 91 ------ eng/common/templates/steps/source-build.yml | 114 ------- eng/common/templates/steps/telemetry-end.yml | 102 ------- .../templates/steps/telemetry-start.yml | 241 --------------- .../templates/variables/pool-providers.yml | 48 --- .../templates/variables/sdl-variables.yml | 7 - eng/templates/default-build.yml | 95 ++++++ 34 files changed, 124 insertions(+), 2440 deletions(-) delete mode 100644 .codeql.yml delete mode 100644 .config/tsaoptions.json delete mode 100644 eng/common/templates/job/execute-sdl.yml delete mode 100644 eng/common/templates/job/job.yml delete mode 100644 eng/common/templates/job/onelocbuild.yml delete mode 100644 eng/common/templates/job/publish-build-assets.yml delete mode 100644 eng/common/templates/job/source-build.yml delete mode 100644 eng/common/templates/job/source-index-stage1.yml delete mode 100644 eng/common/templates/jobs/codeql-build.yml delete mode 100644 eng/common/templates/jobs/jobs.yml delete mode 100644 eng/common/templates/jobs/source-build.yml delete mode 100644 eng/common/templates/post-build/common-variables.yml delete mode 100644 eng/common/templates/post-build/post-build.yml delete mode 100644 eng/common/templates/post-build/setup-maestro-vars.yml delete mode 100644 eng/common/templates/post-build/trigger-subscription.yml delete mode 100644 eng/common/templates/steps/add-build-to-channel.yml delete mode 100644 eng/common/templates/steps/build-reason.yml delete mode 100644 eng/common/templates/steps/execute-codeql.yml delete mode 100644 eng/common/templates/steps/execute-sdl.yml delete mode 100644 eng/common/templates/steps/generate-sbom.yml delete mode 100644 eng/common/templates/steps/publish-logs.yml delete mode 100644 eng/common/templates/steps/retain-build.yml delete mode 100644 eng/common/templates/steps/run-on-unix.yml delete mode 100644 eng/common/templates/steps/run-on-windows.yml delete mode 100644 eng/common/templates/steps/run-script-ifequalelse.yml delete mode 100644 eng/common/templates/steps/send-to-helix.yml delete mode 100644 eng/common/templates/steps/source-build.yml delete mode 100644 eng/common/templates/steps/telemetry-end.yml delete mode 100644 eng/common/templates/steps/telemetry-start.yml delete mode 100644 eng/common/templates/variables/pool-providers.yml delete mode 100644 eng/common/templates/variables/sdl-variables.yml create mode 100644 eng/templates/default-build.yml diff --git a/.codeql.yml b/.codeql.yml deleted file mode 100644 index 65948ac75..000000000 --- a/.codeql.yml +++ /dev/null @@ -1,64 +0,0 @@ -parameters: - # Optionally do not publish to TSA. Useful for e.g. verifying fixes before PR. -- name: TSAEnabled - displayName: Publish results to TSA - type: boolean - default: true - -variables: - # CG is handled in the primary CI pipeline -- name: skipComponentGovernanceDetection - value: true - # Force CodeQL enabled so it may be run on any branch -- name: Codeql.Enabled - value: true - # Do not let CodeQL 3000 Extension gate scan frequency -- name: Codeql.Cadence - value: 0 -- name: Codeql.SourceRoot - value: src - # CodeQL needs this plumbed along as a variable to enable TSA -- name: Codeql.TSAEnabled - value: ${{ parameters.TSAEnabled }} -# Default expects tsaoptions.json under SourceRoot. -- name: Codeql.TSAOptionsPath - value: '$(Build.SourcesDirectory)/.config/tsaoptions.json' - - # Build variables -- name: _BuildConfig - value: Release - -trigger: none - -schedules: - - cron: 0 12 * * 1 - displayName: Weekly Monday CodeQL run - branches: - include: - - main - always: true - -jobs: -- job: codeql - displayName: CodeQL - pool: - name: NetCore1ESPool-Svc-Internal - demands: ImageOverride -equals windows.vs2019.amd64 - timeoutInMinutes: 90 - - steps: - - task: UseDotNet@2 - inputs: - useGlobalJson: true - - - task: CodeQL3000Init@0 - displayName: CodeQL Initialize - - - script: .\build.cmd EnableSkipStrongNames - displayName: Windows Build - EnableSkipStrongNames - - - script: .\build.cmd Build - displayName: Windows Build - - - task: CodeQL3000Finalize@0 - displayName: CodeQL Finalize diff --git a/.config/tsaoptions.json b/.config/tsaoptions.json deleted file mode 100644 index ae5e4f91d..000000000 --- a/.config/tsaoptions.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "areaPath": "DevDiv\\ASP.NET Core", - "codebaseName": "AspNetWebStack", - "instanceUrl": "https://devdiv.visualstudio.com/", - "iterationPath": "DevDiv", - "notificationAliases": [ - "aspnetcore-build@microsoft.com" - ], - "projectName": "DEVDIV", - "repositoryName": "AspNetWebStack", - "template": "TFSDEVDIV" -} \ No newline at end of file diff --git a/azure-pipelines-public.yml b/azure-pipelines-public.yml index b8b92278a..7089d6acb 100644 --- a/azure-pipelines-public.yml +++ b/azure-pipelines-public.yml @@ -23,78 +23,11 @@ variables: trigger: [main] pr: ['*'] -jobs: -- job: build +stages: +- stage: build displayName: Build - pool: - ${{ if eq(variables['System.TeamProject'], 'public') }}: - name: NetCore-Svc-Public - demands: ImageOverride -equals windows.vs2019.amd64.open - ${{ else }}: - name: NetCore1ESPool-Svc-Internal - demands: ImageOverride -equals windows.vs2019.amd64 - timeoutInMinutes: 30 - - strategy: - matrix: - Release: - _BuildTarget: ${{ parameters.ReleaseBuildTarget }} - _Configuration: Release - _StyleCopEnabled: true - # Do CG work only in internal pipelines. - skipComponentGovernanceDetection: ${{ eq(variables['System.TeamProject'], 'public') }} - Debug: - _BuildTarget: ${{ parameters.OtherBuildTarget }} - _Configuration: Debug - _StyleCopEnabled: false - # Do not redo CG work. Configuration changes in this part of the matrix are not relevant to CG. - skipComponentGovernanceDetection: true - CodeAnalysis: - _BuildTarget: ${{ parameters.OtherBuildTarget }} - _Configuration: CodeAnalysis - _StyleCopEnabled: false - # Do not redo CG work. Configuration changes in this part of the matrix are not relevant to CG. - skipComponentGovernanceDetection: true - - steps: - - checkout: self - clean: true - displayName: Checkout - - - task: UseDotNet@2 - displayName: Get .NET SDK - inputs: - useGlobalJson: true - - task: UseDotNet@2 - displayName: Get .NET 2.1 runtime - inputs: - packageType: runtime - version: '2.1.x' - - - script: .\build.cmd EnableSkipStrongNames - displayName: Enable SkipStrongNames - - script: .\build.cmd $(_BuildTarget) ^ - /binaryLogger:artifacts/msbuild.binlog /p:Configuration=$(_Configuration) /p:StyleCopEnabled=$(_StyleCopEnabled) ^ - /fileLoggerParameters:LogFile=artifacts/msbuild.log;Summary;Verbosity=minimal - displayName: Build - - - publish: ./bin/$(_Configuration)/Test/TestResults/ - artifact: $(_Configuration) Test Results $(System.JobId) - condition: and(always(), ne(variables._BuildTarget, 'Build')) - continueOnError: true - displayName: Upload test results - - task: PublishTestResults@2 - condition: and(always(), ne(variables._BuildTarget, 'Build')) - continueOnError: true - displayName: Publish test results - inputs: - mergeTestResults: true - searchFolder: ./bin/$(_Configuration)/Test/TestResults/ - testResultsFiles: '*.xml' - testRunner: xUnit - testRunTitle: $(_Configuration) - - - publish: ./artifacts/ - artifact: $(_Configuration) Logs $(System.JobId) - condition: always() - displayName: Upload logs + jobs: + - template: /eng/templates/default-build.yml + parameters: + ReleaseBuildTarget: ${{ parameters.ReleaseBuildTarget }} + OtherBuildTarget: ${{ parameters.OtherBuildTarget }} diff --git a/azure-pipelines.yml b/azure-pipelines.yml index b8b92278a..8b8cf5324 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -23,78 +23,26 @@ variables: trigger: [main] pr: ['*'] -jobs: -- job: build - displayName: Build - pool: - ${{ if eq(variables['System.TeamProject'], 'public') }}: - name: NetCore-Svc-Public - demands: ImageOverride -equals windows.vs2019.amd64.open - ${{ else }}: +resources: + repositories: + # Repo: 1ESPipelineTemplates/1ESPipelineTemplates + - repository: 1esPipelines + type: git + name: 1ESPipelineTemplates/1ESPipelineTemplates + ref: refs/tags/release + +extends: + template: v1/1ES.Official.PipelineTemplate.yml@1esPipelines + parameters: + pool: name: NetCore1ESPool-Svc-Internal - demands: ImageOverride -equals windows.vs2019.amd64 - timeoutInMinutes: 30 - - strategy: - matrix: - Release: - _BuildTarget: ${{ parameters.ReleaseBuildTarget }} - _Configuration: Release - _StyleCopEnabled: true - # Do CG work only in internal pipelines. - skipComponentGovernanceDetection: ${{ eq(variables['System.TeamProject'], 'public') }} - Debug: - _BuildTarget: ${{ parameters.OtherBuildTarget }} - _Configuration: Debug - _StyleCopEnabled: false - # Do not redo CG work. Configuration changes in this part of the matrix are not relevant to CG. - skipComponentGovernanceDetection: true - CodeAnalysis: - _BuildTarget: ${{ parameters.OtherBuildTarget }} - _Configuration: CodeAnalysis - _StyleCopEnabled: false - # Do not redo CG work. Configuration changes in this part of the matrix are not relevant to CG. - skipComponentGovernanceDetection: true - - steps: - - checkout: self - clean: true - displayName: Checkout - - - task: UseDotNet@2 - displayName: Get .NET SDK - inputs: - useGlobalJson: true - - task: UseDotNet@2 - displayName: Get .NET 2.1 runtime - inputs: - packageType: runtime - version: '2.1.x' - - - script: .\build.cmd EnableSkipStrongNames - displayName: Enable SkipStrongNames - - script: .\build.cmd $(_BuildTarget) ^ - /binaryLogger:artifacts/msbuild.binlog /p:Configuration=$(_Configuration) /p:StyleCopEnabled=$(_StyleCopEnabled) ^ - /fileLoggerParameters:LogFile=artifacts/msbuild.log;Summary;Verbosity=minimal - displayName: Build - - - publish: ./bin/$(_Configuration)/Test/TestResults/ - artifact: $(_Configuration) Test Results $(System.JobId) - condition: and(always(), ne(variables._BuildTarget, 'Build')) - continueOnError: true - displayName: Upload test results - - task: PublishTestResults@2 - condition: and(always(), ne(variables._BuildTarget, 'Build')) - continueOnError: true - displayName: Publish test results - inputs: - mergeTestResults: true - searchFolder: ./bin/$(_Configuration)/Test/TestResults/ - testResultsFiles: '*.xml' - testRunner: xUnit - testRunTitle: $(_Configuration) - - - publish: ./artifacts/ - artifact: $(_Configuration) Logs $(System.JobId) - condition: always() - displayName: Upload logs + image: 1es-windows-2019-pt + os: windows + stages: + - stage: build + displayName: Build + jobs: + - template: /eng/templates/default-build.yml@self + parameters: + ReleaseBuildTarget: ${{ parameters.ReleaseBuildTarget }} + OtherBuildTarget: ${{ parameters.OtherBuildTarget }} diff --git a/eng/common/templates/job/execute-sdl.yml b/eng/common/templates/job/execute-sdl.yml deleted file mode 100644 index 7aabaa180..000000000 --- a/eng/common/templates/job/execute-sdl.yml +++ /dev/null @@ -1,134 +0,0 @@ -parameters: - enable: 'false' # Whether the SDL validation job should execute or not - overrideParameters: '' # Optional: to override values for parameters. - additionalParameters: '' # Optional: parameters that need user specific values eg: '-SourceToolsList @("abc","def") -ArtifactToolsList @("ghi","jkl")' - # Optional: if specified, restore and use this version of Guardian instead of the default. - overrideGuardianVersion: '' - # Optional: if true, publish the '.gdn' folder as a pipeline artifact. This can help with in-depth - # diagnosis of problems with specific tool configurations. - publishGuardianDirectoryToPipeline: false - # The script to run to execute all SDL tools. Use this if you want to use a script to define SDL - # parameters rather than relying on YAML. It may be better to use a local script, because you can - # reproduce results locally without piecing together a command based on the YAML. - executeAllSdlToolsScript: 'eng/common/sdl/execute-all-sdl-tools.ps1' - # There is some sort of bug (has been reported) in Azure DevOps where if this parameter is named - # 'continueOnError', the parameter value is not correctly picked up. - # This can also be remedied by the caller (post-build.yml) if it does not use a nested parameter - sdlContinueOnError: false # optional: determines whether to continue the build if the step errors; - # optional: determines if build artifacts should be downloaded. - downloadArtifacts: true - # optional: determines if this job should search the directory of downloaded artifacts for - # 'tar.gz' and 'zip' archive files and extract them before running SDL validation tasks. - extractArchiveArtifacts: false - dependsOn: '' # Optional: dependencies of the job - artifactNames: '' # Optional: patterns supplied to DownloadBuildArtifacts - # Usage: - # artifactNames: - # - 'BlobArtifacts' - # - 'Artifacts_Windows_NT_Release' - # Optional: download a list of pipeline artifacts. 'downloadArtifacts' controls build artifacts, - # not pipeline artifacts, so doesn't affect the use of this parameter. - pipelineArtifactNames: [] - -jobs: -- job: Run_SDL - dependsOn: ${{ parameters.dependsOn }} - displayName: Run SDL tool - condition: and(succeededOrFailed(), eq( ${{ parameters.enable }}, 'true')) - variables: - - group: DotNet-VSTS-Bot - - name: AzDOProjectName - value: ${{ parameters.AzDOProjectName }} - - name: AzDOPipelineId - value: ${{ parameters.AzDOPipelineId }} - - name: AzDOBuildId - value: ${{ parameters.AzDOBuildId }} - - template: /eng/common/templates/variables/sdl-variables.yml - - name: GuardianVersion - value: ${{ coalesce(parameters.overrideGuardianVersion, '$(DefaultGuardianVersion)') }} - - template: /eng/common/templates/variables/pool-providers.yml - pool: - # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) - ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: - name: VSEngSS-MicroBuild2022-1ES - demands: Cmd - # If it's not devdiv, it's dnceng - ${{ if ne(variables['System.TeamProject'], 'DevDiv') }}: - name: $(DncEngInternalBuildPool) - demands: ImageOverride -equals windows.vs2019.amd64 - steps: - - checkout: self - clean: true - - # If the template caller didn't provide an AzDO parameter, set them all up as Maestro vars. - - ${{ if not(and(parameters.AzDOProjectName, parameters.AzDOPipelineId, parameters.AzDOBuildId)) }}: - - template: /eng/common/templates/post-build/setup-maestro-vars.yml - - - ${{ if ne(parameters.downloadArtifacts, 'false')}}: - - ${{ if ne(parameters.artifactNames, '') }}: - - ${{ each artifactName in parameters.artifactNames }}: - - task: DownloadBuildArtifacts@0 - displayName: Download Build Artifacts - inputs: - buildType: specific - buildVersionToDownload: specific - project: $(AzDOProjectName) - pipeline: $(AzDOPipelineId) - buildId: $(AzDOBuildId) - artifactName: ${{ artifactName }} - downloadPath: $(Build.ArtifactStagingDirectory)\artifacts - checkDownloadedFiles: true - - ${{ if eq(parameters.artifactNames, '') }}: - - task: DownloadBuildArtifacts@0 - displayName: Download Build Artifacts - inputs: - buildType: specific - buildVersionToDownload: specific - project: $(AzDOProjectName) - pipeline: $(AzDOPipelineId) - buildId: $(AzDOBuildId) - downloadType: specific files - itemPattern: "**" - downloadPath: $(Build.ArtifactStagingDirectory)\artifacts - checkDownloadedFiles: true - - - ${{ each artifactName in parameters.pipelineArtifactNames }}: - - task: DownloadPipelineArtifact@2 - displayName: Download Pipeline Artifacts - inputs: - buildType: specific - buildVersionToDownload: specific - project: $(AzDOProjectName) - pipeline: $(AzDOPipelineId) - buildId: $(AzDOBuildId) - artifactName: ${{ artifactName }} - downloadPath: $(Build.ArtifactStagingDirectory)\artifacts - checkDownloadedFiles: true - - - powershell: eng/common/sdl/extract-artifact-packages.ps1 - -InputPath $(Build.ArtifactStagingDirectory)\artifacts\BlobArtifacts - -ExtractPath $(Build.ArtifactStagingDirectory)\artifacts\BlobArtifacts - displayName: Extract Blob Artifacts - continueOnError: ${{ parameters.sdlContinueOnError }} - - - powershell: eng/common/sdl/extract-artifact-packages.ps1 - -InputPath $(Build.ArtifactStagingDirectory)\artifacts\PackageArtifacts - -ExtractPath $(Build.ArtifactStagingDirectory)\artifacts\PackageArtifacts - displayName: Extract Package Artifacts - continueOnError: ${{ parameters.sdlContinueOnError }} - - - ${{ if ne(parameters.extractArchiveArtifacts, 'false') }}: - - powershell: eng/common/sdl/extract-artifact-archives.ps1 - -InputPath $(Build.ArtifactStagingDirectory)\artifacts - -ExtractPath $(Build.ArtifactStagingDirectory)\artifacts - displayName: Extract Archive Artifacts - continueOnError: ${{ parameters.sdlContinueOnError }} - - - template: /eng/common/templates/steps/execute-sdl.yml - parameters: - overrideGuardianVersion: ${{ parameters.overrideGuardianVersion }} - executeAllSdlToolsScript: ${{ parameters.executeAllSdlToolsScript }} - overrideParameters: ${{ parameters.overrideParameters }} - additionalParameters: ${{ parameters.additionalParameters }} - publishGuardianDirectoryToPipeline: ${{ parameters.publishGuardianDirectoryToPipeline }} - sdlContinueOnError: ${{ parameters.sdlContinueOnError }} diff --git a/eng/common/templates/job/job.yml b/eng/common/templates/job/job.yml deleted file mode 100644 index 9f55d3f46..000000000 --- a/eng/common/templates/job/job.yml +++ /dev/null @@ -1,230 +0,0 @@ -# Internal resources (telemetry, microbuild) can only be accessed from non-public projects, -# and some (Microbuild) should only be applied to non-PR cases for internal builds. - -parameters: -# Job schema parameters - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#job - cancelTimeoutInMinutes: '' - condition: '' - container: '' - continueOnError: false - dependsOn: '' - displayName: '' - pool: '' - steps: [] - strategy: '' - timeoutInMinutes: '' - variables: [] - workspace: '' - -# Job base template specific parameters - # See schema documentation - https://github.com/dotnet/arcade/blob/master/Documentation/AzureDevOps/TemplateSchema.md - artifacts: '' - enableMicrobuild: false - enablePublishBuildArtifacts: false - enablePublishBuildAssets: false - enablePublishTestResults: false - enablePublishUsingPipelines: false - disableComponentGovernance: false - componentGovernanceIgnoreDirectories: '' - mergeTestResults: false - testRunTitle: '' - testResultsFormat: '' - name: '' - preSteps: [] - runAsPublic: false -# Sbom related params - enableSbom: true - PackageVersion: 7.0.0 - BuildDropPath: '$(Build.SourcesDirectory)/artifacts' - -jobs: -- job: ${{ parameters.name }} - - ${{ if ne(parameters.cancelTimeoutInMinutes, '') }}: - cancelTimeoutInMinutes: ${{ parameters.cancelTimeoutInMinutes }} - - ${{ if ne(parameters.condition, '') }}: - condition: ${{ parameters.condition }} - - ${{ if ne(parameters.container, '') }}: - container: ${{ parameters.container }} - - ${{ if ne(parameters.continueOnError, '') }}: - continueOnError: ${{ parameters.continueOnError }} - - ${{ if ne(parameters.dependsOn, '') }}: - dependsOn: ${{ parameters.dependsOn }} - - ${{ if ne(parameters.displayName, '') }}: - displayName: ${{ parameters.displayName }} - - ${{ if ne(parameters.pool, '') }}: - pool: ${{ parameters.pool }} - - ${{ if ne(parameters.strategy, '') }}: - strategy: ${{ parameters.strategy }} - - ${{ if ne(parameters.timeoutInMinutes, '') }}: - timeoutInMinutes: ${{ parameters.timeoutInMinutes }} - - variables: - - ${{ if ne(parameters.enableTelemetry, 'false') }}: - - name: DOTNET_CLI_TELEMETRY_PROFILE - value: '$(Build.Repository.Uri)' - - ${{ if eq(parameters.enableRichCodeNavigation, 'true') }}: - - name: EnableRichCodeNavigation - value: 'true' - - ${{ each variable in parameters.variables }}: - # handle name-value variable syntax - # example: - # - name: [key] - # value: [value] - - ${{ if ne(variable.name, '') }}: - - name: ${{ variable.name }} - value: ${{ variable.value }} - - # handle variable groups - - ${{ if ne(variable.group, '') }}: - - group: ${{ variable.group }} - - # handle key-value variable syntax. - # example: - # - [key]: [value] - - ${{ if and(eq(variable.name, ''), eq(variable.group, '')) }}: - - ${{ each pair in variable }}: - - name: ${{ pair.key }} - value: ${{ pair.value }} - - # DotNet-HelixApi-Access provides 'HelixApiAccessToken' for internal builds - - ${{ if and(eq(parameters.enableTelemetry, 'true'), eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: - - group: DotNet-HelixApi-Access - - ${{ if ne(parameters.workspace, '') }}: - workspace: ${{ parameters.workspace }} - - steps: - - ${{ if ne(parameters.preSteps, '') }}: - - ${{ each preStep in parameters.preSteps }}: - - ${{ preStep }} - - - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: - - ${{ if eq(parameters.enableMicrobuild, 'true') }}: - - task: MicroBuildSigningPlugin@3 - displayName: Install MicroBuild plugin - inputs: - signType: $(_SignType) - zipSources: false - feedSource: https://dnceng.pkgs.visualstudio.com/_packaging/MicroBuildToolset/nuget/v3/index.json - env: - TeamName: $(_TeamName) - continueOnError: ${{ parameters.continueOnError }} - condition: and(succeeded(), in(variables['_SignType'], 'real', 'test'), eq(variables['Agent.Os'], 'Windows_NT')) - - - ${{ if and(eq(parameters.runAsPublic, 'false'), eq(variables['System.TeamProject'], 'internal')) }}: - - task: NuGetAuthenticate@0 - - - ${{ if or(eq(parameters.artifacts.download, 'true'), ne(parameters.artifacts.download, '')) }}: - - task: DownloadPipelineArtifact@2 - inputs: - buildType: current - artifactName: ${{ coalesce(parameters.artifacts.download.name, 'Artifacts_$(Agent.OS)_$(_BuildConfig)') }} - targetPath: ${{ coalesce(parameters.artifacts.download.path, 'artifacts') }} - itemPattern: ${{ coalesce(parameters.artifacts.download.pattern, '**') }} - - - ${{ each step in parameters.steps }}: - - ${{ step }} - - - ${{ if eq(parameters.enableRichCodeNavigation, true) }}: - - task: RichCodeNavIndexer@0 - displayName: RichCodeNav Upload - inputs: - languages: ${{ coalesce(parameters.richCodeNavigationLanguage, 'csharp') }} - environment: ${{ coalesce(parameters.richCodeNavigationEnvironment, 'production') }} - richNavLogOutputDirectory: $(Build.SourcesDirectory)/artifacts/bin - uploadRichNavArtifacts: ${{ coalesce(parameters.richCodeNavigationUploadArtifacts, false) }} - continueOnError: true - - - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest'), ne(parameters.disableComponentGovernance, 'true')) }}: - - task: ComponentGovernanceComponentDetection@0 - continueOnError: true - inputs: - ignoreDirectories: ${{ parameters.componentGovernanceIgnoreDirectories }} - - - ${{ if eq(parameters.enableMicrobuild, 'true') }}: - - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: - - task: MicroBuildCleanup@1 - displayName: Execute Microbuild cleanup tasks - condition: and(always(), in(variables['_SignType'], 'real', 'test'), eq(variables['Agent.Os'], 'Windows_NT')) - continueOnError: ${{ parameters.continueOnError }} - env: - TeamName: $(_TeamName) - - - ${{ if ne(parameters.artifacts.publish, '') }}: - - ${{ if or(eq(parameters.artifacts.publish.artifacts, 'true'), ne(parameters.artifacts.publish.artifacts, '')) }}: - - task: CopyFiles@2 - displayName: Gather binaries for publish to artifacts - inputs: - SourceFolder: 'artifacts/bin' - Contents: '**' - TargetFolder: '$(Build.ArtifactStagingDirectory)/artifacts/bin' - - task: CopyFiles@2 - displayName: Gather packages for publish to artifacts - inputs: - SourceFolder: 'artifacts/packages' - Contents: '**' - TargetFolder: '$(Build.ArtifactStagingDirectory)/artifacts/packages' - - task: PublishBuildArtifacts@1 - displayName: Publish pipeline artifacts - inputs: - PathtoPublish: '$(Build.ArtifactStagingDirectory)/artifacts' - PublishLocation: Container - ArtifactName: ${{ coalesce(parameters.artifacts.publish.artifacts.name , 'Artifacts_$(Agent.Os)_$(_BuildConfig)') }} - continueOnError: true - condition: always() - - ${{ if or(eq(parameters.artifacts.publish.logs, 'true'), ne(parameters.artifacts.publish.logs, '')) }}: - - publish: artifacts/log - artifact: ${{ coalesce(parameters.artifacts.publish.logs.name, 'Logs_Build_$(Agent.Os)_$(_BuildConfig)') }} - displayName: Publish logs - continueOnError: true - condition: always() - - - ${{ if ne(parameters.enablePublishBuildArtifacts, 'false') }}: - - task: PublishBuildArtifacts@1 - displayName: Publish Logs - inputs: - PathtoPublish: '$(Build.SourcesDirectory)/artifacts/log/$(_BuildConfig)' - PublishLocation: Container - ArtifactName: ${{ coalesce(parameters.enablePublishBuildArtifacts.artifactName, '$(Agent.Os)_$(Agent.JobName)' ) }} - continueOnError: true - condition: always() - - - ${{ if or(and(eq(parameters.enablePublishTestResults, 'true'), eq(parameters.testResultsFormat, '')), eq(parameters.testResultsFormat, 'xunit')) }}: - - task: PublishTestResults@2 - displayName: Publish XUnit Test Results - inputs: - testResultsFormat: 'xUnit' - testResultsFiles: '*.xml' - searchFolder: '$(Build.SourcesDirectory)/artifacts/TestResults/$(_BuildConfig)' - testRunTitle: ${{ coalesce(parameters.testRunTitle, parameters.name, '$(System.JobName)') }}-xunit - mergeTestResults: ${{ parameters.mergeTestResults }} - continueOnError: true - condition: always() - - ${{ if or(and(eq(parameters.enablePublishTestResults, 'true'), eq(parameters.testResultsFormat, '')), eq(parameters.testResultsFormat, 'vstest')) }}: - - task: PublishTestResults@2 - displayName: Publish TRX Test Results - inputs: - testResultsFormat: 'VSTest' - testResultsFiles: '*.trx' - searchFolder: '$(Build.SourcesDirectory)/artifacts/TestResults/$(_BuildConfig)' - testRunTitle: ${{ coalesce(parameters.testRunTitle, parameters.name, '$(System.JobName)') }}-trx - mergeTestResults: ${{ parameters.mergeTestResults }} - continueOnError: true - condition: always() - - - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest'), eq(parameters.enableSbom, 'true')) }}: - - template: /eng/common/templates/steps/generate-sbom.yml - parameters: - PackageVersion: ${{ parameters.packageVersion}} - BuildDropPath: ${{ parameters.buildDropPath }} - IgnoreDirectories: ${{ parameters.componentGovernanceIgnoreDirectories }} - diff --git a/eng/common/templates/job/onelocbuild.yml b/eng/common/templates/job/onelocbuild.yml deleted file mode 100644 index c2cabcf9e..000000000 --- a/eng/common/templates/job/onelocbuild.yml +++ /dev/null @@ -1,107 +0,0 @@ -parameters: - # Optional: dependencies of the job - dependsOn: '' - - # Optional: A defined YAML pool - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#pool - pool: '' - - CeapexPat: $(dn-bot-ceapex-package-r) # PAT for the loc AzDO instance https://dev.azure.com/ceapex - GithubPat: $(BotAccount-dotnet-bot-repo-PAT) - - SourcesDirectory: $(Build.SourcesDirectory) - CreatePr: true - AutoCompletePr: false - ReusePr: true - UseLfLineEndings: true - UseCheckedInLocProjectJson: false - LanguageSet: VS_Main_Languages - LclSource: lclFilesInRepo - LclPackageId: '' - RepoType: gitHub - GitHubOrg: dotnet - MirrorRepo: '' - MirrorBranch: main - condition: '' - JobNameSuffix: '' - -jobs: -- job: OneLocBuild${{ parameters.JobNameSuffix }} - - dependsOn: ${{ parameters.dependsOn }} - - displayName: OneLocBuild${{ parameters.JobNameSuffix }} - - variables: - - group: OneLocBuildVariables # Contains the CeapexPat and GithubPat - - name: _GenerateLocProjectArguments - value: -SourcesDirectory ${{ parameters.SourcesDirectory }} - -LanguageSet "${{ parameters.LanguageSet }}" - -CreateNeutralXlfs - - ${{ if eq(parameters.UseCheckedInLocProjectJson, 'true') }}: - - name: _GenerateLocProjectArguments - value: ${{ variables._GenerateLocProjectArguments }} -UseCheckedInLocProjectJson - - template: /eng/common/templates/variables/pool-providers.yml - - ${{ if ne(parameters.pool, '') }}: - pool: ${{ parameters.pool }} - ${{ if eq(parameters.pool, '') }}: - pool: - # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) - ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: - name: VSEngSS-MicroBuild2022-1ES - demands: Cmd - # If it's not devdiv, it's dnceng - ${{ if ne(variables['System.TeamProject'], 'DevDiv') }}: - name: $(DncEngInternalBuildPool) - demands: ImageOverride -equals windows.vs2019.amd64 - - steps: - - task: Powershell@2 - inputs: - filePath: $(Build.SourcesDirectory)/eng/common/generate-locproject.ps1 - arguments: $(_GenerateLocProjectArguments) - displayName: Generate LocProject.json - condition: ${{ parameters.condition }} - - - task: OneLocBuild@2 - displayName: OneLocBuild - env: - SYSTEM_ACCESSTOKEN: $(System.AccessToken) - inputs: - locProj: eng/Localize/LocProject.json - outDir: $(Build.ArtifactStagingDirectory) - lclSource: ${{ parameters.LclSource }} - lclPackageId: ${{ parameters.LclPackageId }} - isCreatePrSelected: ${{ parameters.CreatePr }} - isAutoCompletePrSelected: ${{ parameters.AutoCompletePr }} - ${{ if eq(parameters.CreatePr, true) }}: - isUseLfLineEndingsSelected: ${{ parameters.UseLfLineEndings }} - ${{ if eq(parameters.RepoType, 'gitHub') }}: - isShouldReusePrSelected: ${{ parameters.ReusePr }} - packageSourceAuth: patAuth - patVariable: ${{ parameters.CeapexPat }} - ${{ if eq(parameters.RepoType, 'gitHub') }}: - repoType: ${{ parameters.RepoType }} - gitHubPatVariable: "${{ parameters.GithubPat }}" - ${{ if ne(parameters.MirrorRepo, '') }}: - isMirrorRepoSelected: true - gitHubOrganization: ${{ parameters.GitHubOrg }} - mirrorRepo: ${{ parameters.MirrorRepo }} - mirrorBranch: ${{ parameters.MirrorBranch }} - condition: ${{ parameters.condition }} - - - task: PublishBuildArtifacts@1 - displayName: Publish Localization Files - inputs: - PathtoPublish: '$(Build.ArtifactStagingDirectory)/loc' - PublishLocation: Container - ArtifactName: Loc - condition: ${{ parameters.condition }} - - - task: PublishBuildArtifacts@1 - displayName: Publish LocProject.json - inputs: - PathtoPublish: '$(Build.SourcesDirectory)/eng/Localize/' - PublishLocation: Container - ArtifactName: Loc - condition: ${{ parameters.condition }} \ No newline at end of file diff --git a/eng/common/templates/job/publish-build-assets.yml b/eng/common/templates/job/publish-build-assets.yml deleted file mode 100644 index d7b634962..000000000 --- a/eng/common/templates/job/publish-build-assets.yml +++ /dev/null @@ -1,150 +0,0 @@ -parameters: - configuration: 'Debug' - - # Optional: condition for the job to run - condition: '' - - # Optional: 'true' if future jobs should run even if this job fails - continueOnError: false - - # Optional: dependencies of the job - dependsOn: '' - - # Optional: Include PublishBuildArtifacts task - enablePublishBuildArtifacts: false - - # Optional: A defined YAML pool - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#pool - pool: {} - - # Optional: should run as a public build even in the internal project - # if 'true', the build won't run any of the internal only steps, even if it is running in non-public projects. - runAsPublic: false - - # Optional: whether the build's artifacts will be published using release pipelines or direct feed publishing - publishUsingPipelines: false - - # Optional: whether the build's artifacts will be published using release pipelines or direct feed publishing - publishAssetsImmediately: false - - artifactsPublishingAdditionalParameters: '' - - signingValidationAdditionalParameters: '' - -jobs: -- job: Asset_Registry_Publish - - dependsOn: ${{ parameters.dependsOn }} - - ${{ if eq(parameters.publishAssetsImmediately, 'true') }}: - displayName: Publish Assets - ${{ else }}: - displayName: Publish to Build Asset Registry - - variables: - - template: /eng/common/templates/variables/pool-providers.yml - - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: - - group: Publish-Build-Assets - - group: AzureDevOps-Artifact-Feeds-Pats - - name: runCodesignValidationInjection - value: false - - ${{ if eq(parameters.publishAssetsImmediately, 'true') }}: - - template: /eng/common/templates/post-build/common-variables.yml - - pool: - # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) - ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: - name: VSEngSS-MicroBuild2022-1ES - demands: Cmd - # If it's not devdiv, it's dnceng - ${{ if ne(variables['System.TeamProject'], 'DevDiv') }}: - name: $(DncEngInternalBuildPool) - demands: ImageOverride -equals windows.vs2019.amd64 - - steps: - - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: - - task: DownloadBuildArtifacts@0 - displayName: Download artifact - inputs: - artifactName: AssetManifests - downloadPath: '$(Build.StagingDirectory)/Download' - checkDownloadedFiles: true - condition: ${{ parameters.condition }} - continueOnError: ${{ parameters.continueOnError }} - - - task: NuGetAuthenticate@0 - - - task: PowerShell@2 - displayName: Publish Build Assets - inputs: - filePath: eng\common\sdk-task.ps1 - arguments: -task PublishBuildAssets -restore -msbuildEngine dotnet - /p:ManifestsPath='$(Build.StagingDirectory)/Download/AssetManifests' - /p:BuildAssetRegistryToken=$(MaestroAccessToken) - /p:MaestroApiEndpoint=https://maestro-prod.westus2.cloudapp.azure.com - /p:PublishUsingPipelines=${{ parameters.publishUsingPipelines }} - /p:OfficialBuildId=$(Build.BuildNumber) - condition: ${{ parameters.condition }} - continueOnError: ${{ parameters.continueOnError }} - - - task: powershell@2 - displayName: Create ReleaseConfigs Artifact - inputs: - targetType: inline - script: | - Add-Content -Path "$(Build.StagingDirectory)/ReleaseConfigs.txt" -Value $(BARBuildId) - Add-Content -Path "$(Build.StagingDirectory)/ReleaseConfigs.txt" -Value "$(DefaultChannels)" - Add-Content -Path "$(Build.StagingDirectory)/ReleaseConfigs.txt" -Value $(IsStableBuild) - - - task: PublishBuildArtifacts@1 - displayName: Publish ReleaseConfigs Artifact - inputs: - PathtoPublish: '$(Build.StagingDirectory)/ReleaseConfigs.txt' - PublishLocation: Container - ArtifactName: ReleaseConfigs - - - task: powershell@2 - displayName: Check if SymbolPublishingExclusionsFile.txt exists - inputs: - targetType: inline - script: | - $symbolExclusionfile = "$(Build.SourcesDirectory)/eng/SymbolPublishingExclusionsFile.txt" - if(Test-Path -Path $symbolExclusionfile) - { - Write-Host "SymbolExclusionFile exists" - Write-Host "##vso[task.setvariable variable=SymbolExclusionFile]true" - } - else{ - Write-Host "Symbols Exclusion file does not exists" - Write-Host "##vso[task.setvariable variable=SymbolExclusionFile]false" - } - - - task: PublishBuildArtifacts@1 - displayName: Publish SymbolPublishingExclusionsFile Artifact - condition: eq(variables['SymbolExclusionFile'], 'true') - inputs: - PathtoPublish: '$(Build.SourcesDirectory)/eng/SymbolPublishingExclusionsFile.txt' - PublishLocation: Container - ArtifactName: ReleaseConfigs - - - ${{ if eq(parameters.publishAssetsImmediately, 'true') }}: - - template: /eng/common/templates/post-build/setup-maestro-vars.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - - - task: PowerShell@2 - displayName: Publish Using Darc - inputs: - filePath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1 - arguments: -BuildId $(BARBuildId) - -PublishingInfraVersion 3 - -AzdoToken '$(publishing-dnceng-devdiv-code-r-build-re)' - -MaestroToken '$(MaestroApiAccessToken)' - -WaitPublishingFinish true - -ArtifactsPublishingAdditionalParameters '${{ parameters.artifactsPublishingAdditionalParameters }}' - -SymbolPublishingAdditionalParameters '${{ parameters.symbolPublishingAdditionalParameters }}' - - - ${{ if eq(parameters.enablePublishBuildArtifacts, 'true') }}: - - template: /eng/common/templates/steps/publish-logs.yml - parameters: - JobLabel: 'Publish_Artifacts_Logs' diff --git a/eng/common/templates/job/source-build.yml b/eng/common/templates/job/source-build.yml deleted file mode 100644 index e40bf3520..000000000 --- a/eng/common/templates/job/source-build.yml +++ /dev/null @@ -1,74 +0,0 @@ -parameters: - # This template adds arcade-powered source-build to CI. The template produces a server job with a - # default ID 'Source_Build_Complete' to put in a dependency list if necessary. - - # Specifies the prefix for source-build jobs added to pipeline. Use this if disambiguation needed. - jobNamePrefix: 'Source_Build' - - # Defines the platform on which to run the job. By default, a linux-x64 machine, suitable for - # managed-only repositories. This is an object with these properties: - # - # name: '' - # The name of the job. This is included in the job ID. - # targetRID: '' - # The name of the target RID to use, instead of the one auto-detected by Arcade. - # nonPortable: false - # Enables non-portable mode. This means a more specific RID (e.g. fedora.32-x64 rather than - # linux-x64), and compiling against distro-provided packages rather than portable ones. - # skipPublishValidation: false - # Disables publishing validation. By default, a check is performed to ensure no packages are - # published by source-build. - # container: '' - # A container to use. Runs in docker. - # pool: {} - # A pool to use. Runs directly on an agent. - # buildScript: '' - # Specifies the build script to invoke to perform the build in the repo. The default - # './build.sh' should work for typical Arcade repositories, but this is customizable for - # difficult situations. - # jobProperties: {} - # A list of job properties to inject at the top level, for potential extensibility beyond - # container and pool. - platform: {} - -jobs: -- job: ${{ parameters.jobNamePrefix }}_${{ parameters.platform.name }} - displayName: Source-Build (${{ parameters.platform.name }}) - - ${{ each property in parameters.platform.jobProperties }}: - ${{ property.key }}: ${{ property.value }} - - ${{ if ne(parameters.platform.container, '') }}: - container: ${{ parameters.platform.container }} - - ${{ if eq(parameters.platform.pool, '') }}: - # The default VM host AzDO pool. This should be capable of running Docker containers: almost all - # source-build builds run in Docker, including the default managed platform. - # /eng/common/templates/variables/pool-providers.yml can't be used here (some customers declare variables already), so duplicate its logic - pool: - # Main environments - ${{ if and(eq(variables['System.TeamProject'], 'public'), ne(contains(coalesce(variables['System.PullRequest.TargetBranch'], variables['Build.SourceBranch'], 'refs/heads/main'), 'release'), true)) }}: - name: NetCore-Public - demands: ImageOverride -equals Build.Ubuntu.1804.Amd64.Open - ${{ if and(eq(variables['System.TeamProject'], 'internal'), ne(contains(coalesce(variables['System.PullRequest.TargetBranch'], variables['Build.SourceBranch'], 'refs/heads/main'), 'release'), true)) }}: - name: NetCore1ESPool-Internal - demands: ImageOverride -equals Build.Ubuntu.1804.Amd64 - - # Servicing build environments - ${{ if and(eq(variables['System.TeamProject'], 'public'), contains(coalesce(variables['System.PullRequest.TargetBranch'], variables['Build.SourceBranch'], 'refs/heads/main'), 'release')) }}: - name: NetCore-Svc-Public - demands: ImageOverride -equals Build.Ubuntu.1804.Amd64.Open - ${{ if and(eq(variables['System.TeamProject'], 'internal'), contains(coalesce(variables['System.PullRequest.TargetBranch'], variables['Build.SourceBranch'], 'refs/heads/main'), 'release')) }}: - name: NetCore1ESPool-Svc-Internal - demands: ImageOverride -equals Build.Ubuntu.1804.Amd64 - - ${{ if ne(parameters.platform.pool, '') }}: - pool: ${{ parameters.platform.pool }} - - workspace: - clean: all - - steps: - - template: /eng/common/templates/steps/source-build.yml - parameters: - platform: ${{ parameters.platform }} diff --git a/eng/common/templates/job/source-index-stage1.yml b/eng/common/templates/job/source-index-stage1.yml deleted file mode 100644 index 09c506d11..000000000 --- a/eng/common/templates/job/source-index-stage1.yml +++ /dev/null @@ -1,67 +0,0 @@ -parameters: - runAsPublic: false - sourceIndexPackageVersion: 1.0.1-20220804.1 - sourceIndexPackageSource: https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json - sourceIndexBuildCommand: powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -Command "eng/common/build.ps1 -restore -build -binarylog -ci" - preSteps: [] - binlogPath: artifacts/log/Debug/Build.binlog - condition: '' - dependsOn: '' - pool: '' - -jobs: -- job: SourceIndexStage1 - dependsOn: ${{ parameters.dependsOn }} - condition: ${{ parameters.condition }} - variables: - - name: SourceIndexPackageVersion - value: ${{ parameters.sourceIndexPackageVersion }} - - name: SourceIndexPackageSource - value: ${{ parameters.sourceIndexPackageSource }} - - name: BinlogPath - value: ${{ parameters.binlogPath }} - - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: - - group: source-dot-net stage1 variables - - template: /eng/common/templates/variables/pool-providers.yml - - ${{ if ne(parameters.pool, '') }}: - pool: ${{ parameters.pool }} - ${{ if eq(parameters.pool, '') }}: - pool: - ${{ if eq(variables['System.TeamProject'], 'public') }}: - name: $(DncEngPublicBuildPool) - demands: ImageOverride -equals windows.vs2019.amd64.open - ${{ if eq(variables['System.TeamProject'], 'internal') }}: - name: $(DncEngInternalBuildPool) - demands: ImageOverride -equals windows.vs2019.amd64 - - steps: - - ${{ each preStep in parameters.preSteps }}: - - ${{ preStep }} - - - task: UseDotNet@2 - displayName: Use .NET Core sdk 3.1 - inputs: - packageType: sdk - version: 3.1.x - installationPath: $(Agent.TempDirectory)/dotnet - workingDirectory: $(Agent.TempDirectory) - - - script: | - $(Agent.TempDirectory)/dotnet/dotnet tool install BinLogToSln --version $(SourceIndexPackageVersion) --add-source $(SourceIndexPackageSource) --tool-path $(Agent.TempDirectory)/.source-index/tools - $(Agent.TempDirectory)/dotnet/dotnet tool install UploadIndexStage1 --version $(SourceIndexPackageVersion) --add-source $(SourceIndexPackageSource) --tool-path $(Agent.TempDirectory)/.source-index/tools - displayName: Download Tools - # Set working directory to temp directory so 'dotnet' doesn't try to use global.json and use the repo's sdk. - workingDirectory: $(Agent.TempDirectory) - - - script: ${{ parameters.sourceIndexBuildCommand }} - displayName: Build Repository - - - script: $(Agent.TempDirectory)/.source-index/tools/BinLogToSln -i $(BinlogPath) -r $(Build.SourcesDirectory) -n $(Build.Repository.Name) -o .source-index/stage1output - displayName: Process Binlog into indexable sln - - - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: - - script: $(Agent.TempDirectory)/.source-index/tools/UploadIndexStage1 -i .source-index/stage1output -n $(Build.Repository.Name) - displayName: Upload stage1 artifacts to source index - env: - BLOB_CONTAINER_URL: $(source-dot-net-stage1-blob-container-url) diff --git a/eng/common/templates/jobs/codeql-build.yml b/eng/common/templates/jobs/codeql-build.yml deleted file mode 100644 index f7dc5ea4a..000000000 --- a/eng/common/templates/jobs/codeql-build.yml +++ /dev/null @@ -1,31 +0,0 @@ -parameters: - # See schema documentation in /Documentation/AzureDevOps/TemplateSchema.md - continueOnError: false - # Required: A collection of jobs to run - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#job - jobs: [] - # Optional: if specified, restore and use this version of Guardian instead of the default. - overrideGuardianVersion: '' - -jobs: -- template: /eng/common/templates/jobs/jobs.yml - parameters: - enableMicrobuild: false - enablePublishBuildArtifacts: false - enablePublishTestResults: false - enablePublishBuildAssets: false - enablePublishUsingPipelines: false - enableTelemetry: true - - variables: - - group: Publish-Build-Assets - # The Guardian version specified in 'eng/common/sdl/packages.config'. This value must be kept in - # sync with the packages.config file. - - name: DefaultGuardianVersion - value: 0.109.0 - - name: GuardianPackagesConfigFile - value: $(Build.SourcesDirectory)\eng\common\sdl\packages.config - - name: GuardianVersion - value: ${{ coalesce(parameters.overrideGuardianVersion, '$(DefaultGuardianVersion)') }} - - jobs: ${{ parameters.jobs }} - diff --git a/eng/common/templates/jobs/jobs.yml b/eng/common/templates/jobs/jobs.yml deleted file mode 100644 index 289bb2396..000000000 --- a/eng/common/templates/jobs/jobs.yml +++ /dev/null @@ -1,97 +0,0 @@ -parameters: - # See schema documentation in /Documentation/AzureDevOps/TemplateSchema.md - continueOnError: false - - # Optional: Include PublishBuildArtifacts task - enablePublishBuildArtifacts: false - - # Optional: Enable publishing using release pipelines - enablePublishUsingPipelines: false - - # Optional: Enable running the source-build jobs to build repo from source - enableSourceBuild: false - - # Optional: Parameters for source-build template. - # See /eng/common/templates/jobs/source-build.yml for options - sourceBuildParameters: [] - - graphFileGeneration: - # Optional: Enable generating the graph files at the end of the build - enabled: false - # Optional: Include toolset dependencies in the generated graph files - includeToolset: false - - # Required: A collection of jobs to run - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#job - jobs: [] - - # Optional: Override automatically derived dependsOn value for "publish build assets" job - publishBuildAssetsDependsOn: '' - - # Optional: Publish the assets as soon as the publish to BAR stage is complete, rather doing so in a separate stage. - publishAssetsImmediately: false - - # Optional: If using publishAssetsImmediately and additional parameters are needed, can be used to send along additional parameters (normally sent to post-build.yml) - artifactsPublishingAdditionalParameters: '' - signingValidationAdditionalParameters: '' - - # Optional: should run as a public build even in the internal project - # if 'true', the build won't run any of the internal only steps, even if it is running in non-public projects. - runAsPublic: false - - enableSourceIndex: false - sourceIndexParams: {} - -# Internal resources (telemetry, microbuild) can only be accessed from non-public projects, -# and some (Microbuild) should only be applied to non-PR cases for internal builds. - -jobs: -- ${{ each job in parameters.jobs }}: - - template: ../job/job.yml - parameters: - # pass along parameters - ${{ each parameter in parameters }}: - ${{ if ne(parameter.key, 'jobs') }}: - ${{ parameter.key }}: ${{ parameter.value }} - - # pass along job properties - ${{ each property in job }}: - ${{ if ne(property.key, 'job') }}: - ${{ property.key }}: ${{ property.value }} - - name: ${{ job.job }} - -- ${{ if eq(parameters.enableSourceBuild, true) }}: - - template: /eng/common/templates/jobs/source-build.yml - parameters: - allCompletedJobId: Source_Build_Complete - ${{ each parameter in parameters.sourceBuildParameters }}: - ${{ parameter.key }}: ${{ parameter.value }} - -- ${{ if eq(parameters.enableSourceIndex, 'true') }}: - - template: ../job/source-index-stage1.yml - parameters: - runAsPublic: ${{ parameters.runAsPublic }} - ${{ each parameter in parameters.sourceIndexParams }}: - ${{ parameter.key }}: ${{ parameter.value }} - -- ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: - - ${{ if or(eq(parameters.enablePublishBuildAssets, true), eq(parameters.artifacts.publish.manifests, 'true'), ne(parameters.artifacts.publish.manifests, '')) }}: - - template: ../job/publish-build-assets.yml - parameters: - continueOnError: ${{ parameters.continueOnError }} - dependsOn: - - ${{ if ne(parameters.publishBuildAssetsDependsOn, '') }}: - - ${{ each job in parameters.publishBuildAssetsDependsOn }}: - - ${{ job.job }} - - ${{ if eq(parameters.publishBuildAssetsDependsOn, '') }}: - - ${{ each job in parameters.jobs }}: - - ${{ job.job }} - - ${{ if eq(parameters.enableSourceBuild, true) }}: - - Source_Build_Complete - - runAsPublic: ${{ parameters.runAsPublic }} - publishUsingPipelines: ${{ parameters.enablePublishUsingPipelines }} - publishAssetsImmediately: ${{ parameters.publishAssetsImmediately }} - enablePublishBuildArtifacts: ${{ parameters.enablePublishBuildArtifacts }} - artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} - signingValidationAdditionalParameters: ${{ parameters.signingValidationAdditionalParameters }} diff --git a/eng/common/templates/jobs/source-build.yml b/eng/common/templates/jobs/source-build.yml deleted file mode 100644 index a15b07eb5..000000000 --- a/eng/common/templates/jobs/source-build.yml +++ /dev/null @@ -1,46 +0,0 @@ -parameters: - # This template adds arcade-powered source-build to CI. A job is created for each platform, as - # well as an optional server job that completes when all platform jobs complete. - - # The name of the "join" job for all source-build platforms. If set to empty string, the job is - # not included. Existing repo pipelines can use this job depend on all source-build jobs - # completing without maintaining a separate list of every single job ID: just depend on this one - # server job. By default, not included. Recommended name if used: 'Source_Build_Complete'. - allCompletedJobId: '' - - # See /eng/common/templates/job/source-build.yml - jobNamePrefix: 'Source_Build' - - # This is the default platform provided by Arcade, intended for use by a managed-only repo. - defaultManagedPlatform: - name: 'Managed' - container: 'mcr.microsoft.com/dotnet-buildtools/prereqs:centos-stream8' - - # Defines the platforms on which to run build jobs. One job is created for each platform, and the - # object in this array is sent to the job template as 'platform'. If no platforms are specified, - # one job runs on 'defaultManagedPlatform'. - platforms: [] - -jobs: - -- ${{ if ne(parameters.allCompletedJobId, '') }}: - - job: ${{ parameters.allCompletedJobId }} - displayName: Source-Build Complete - pool: server - dependsOn: - - ${{ each platform in parameters.platforms }}: - - ${{ parameters.jobNamePrefix }}_${{ platform.name }} - - ${{ if eq(length(parameters.platforms), 0) }}: - - ${{ parameters.jobNamePrefix }}_${{ parameters.defaultManagedPlatform.name }} - -- ${{ each platform in parameters.platforms }}: - - template: /eng/common/templates/job/source-build.yml - parameters: - jobNamePrefix: ${{ parameters.jobNamePrefix }} - platform: ${{ platform }} - -- ${{ if eq(length(parameters.platforms), 0) }}: - - template: /eng/common/templates/job/source-build.yml - parameters: - jobNamePrefix: ${{ parameters.jobNamePrefix }} - platform: ${{ parameters.defaultManagedPlatform }} diff --git a/eng/common/templates/post-build/common-variables.yml b/eng/common/templates/post-build/common-variables.yml deleted file mode 100644 index c24193acf..000000000 --- a/eng/common/templates/post-build/common-variables.yml +++ /dev/null @@ -1,22 +0,0 @@ -variables: - - group: Publish-Build-Assets - - # Whether the build is internal or not - - name: IsInternalBuild - value: ${{ and(ne(variables['System.TeamProject'], 'public'), contains(variables['Build.SourceBranch'], 'internal')) }} - - # Default Maestro++ API Endpoint and API Version - - name: MaestroApiEndPoint - value: "https://maestro-prod.westus2.cloudapp.azure.com" - - name: MaestroApiAccessToken - value: $(MaestroAccessToken) - - name: MaestroApiVersion - value: "2020-02-20" - - - name: SourceLinkCLIVersion - value: 3.0.0 - - name: SymbolToolVersion - value: 1.0.1 - - - name: runCodesignValidationInjection - value: false diff --git a/eng/common/templates/post-build/post-build.yml b/eng/common/templates/post-build/post-build.yml deleted file mode 100644 index ef720f9d7..000000000 --- a/eng/common/templates/post-build/post-build.yml +++ /dev/null @@ -1,281 +0,0 @@ -parameters: - # Which publishing infra should be used. THIS SHOULD MATCH THE VERSION ON THE BUILD MANIFEST. - # Publishing V1 is no longer supported - # Publishing V2 is no longer supported - # Publishing V3 is the default - - name: publishingInfraVersion - displayName: Which version of publishing should be used to promote the build definition? - type: number - default: 3 - values: - - 3 - - - name: BARBuildId - displayName: BAR Build Id - type: number - default: 0 - - - name: PromoteToChannelIds - displayName: Channel to promote BARBuildId to - type: string - default: '' - - - name: enableSourceLinkValidation - displayName: Enable SourceLink validation - type: boolean - default: false - - - name: enableSigningValidation - displayName: Enable signing validation - type: boolean - default: true - - - name: enableSymbolValidation - displayName: Enable symbol validation - type: boolean - default: false - - - name: enableNugetValidation - displayName: Enable NuGet validation - type: boolean - default: true - - - name: publishInstallersAndChecksums - displayName: Publish installers and checksums - type: boolean - default: true - - - name: SDLValidationParameters - type: object - default: - enable: false - publishGdn: false - continueOnError: false - params: '' - artifactNames: '' - downloadArtifacts: true - - # These parameters let the user customize the call to sdk-task.ps1 for publishing - # symbols & general artifacts as well as for signing validation - - name: symbolPublishingAdditionalParameters - displayName: Symbol publishing additional parameters - type: string - default: '' - - - name: artifactsPublishingAdditionalParameters - displayName: Artifact publishing additional parameters - type: string - default: '' - - - name: signingValidationAdditionalParameters - displayName: Signing validation additional parameters - type: string - default: '' - - # Which stages should finish execution before post-build stages start - - name: validateDependsOn - type: object - default: - - build - - - name: publishDependsOn - type: object - default: - - Validate - - # Optional: Call asset publishing rather than running in a separate stage - - name: publishAssetsImmediately - type: boolean - default: false - -stages: -- ${{ if or(eq( parameters.enableNugetValidation, 'true'), eq(parameters.enableSigningValidation, 'true'), eq(parameters.enableSourceLinkValidation, 'true'), eq(parameters.SDLValidationParameters.enable, 'true')) }}: - - stage: Validate - dependsOn: ${{ parameters.validateDependsOn }} - displayName: Validate Build Assets - variables: - - template: common-variables.yml - - template: /eng/common/templates/variables/pool-providers.yml - jobs: - - job: - displayName: NuGet Validation - condition: and(succeededOrFailed(), eq( ${{ parameters.enableNugetValidation }}, 'true')) - pool: - # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) - ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: - name: VSEngSS-MicroBuild2022-1ES - demands: Cmd - # If it's not devdiv, it's dnceng - ${{ else }}: - name: $(DncEngInternalBuildPool) - demands: ImageOverride -equals windows.vs2019.amd64 - - steps: - - template: setup-maestro-vars.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - - - task: DownloadBuildArtifacts@0 - displayName: Download Package Artifacts - inputs: - buildType: specific - buildVersionToDownload: specific - project: $(AzDOProjectName) - pipeline: $(AzDOPipelineId) - buildId: $(AzDOBuildId) - artifactName: PackageArtifacts - checkDownloadedFiles: true - - - task: PowerShell@2 - displayName: Validate - inputs: - filePath: $(Build.SourcesDirectory)/eng/common/post-build/nuget-validation.ps1 - arguments: -PackagesPath $(Build.ArtifactStagingDirectory)/PackageArtifacts/ - -ToolDestinationPath $(Agent.BuildDirectory)/Extract/ - - - job: - displayName: Signing Validation - condition: and( eq( ${{ parameters.enableSigningValidation }}, 'true'), ne( variables['PostBuildSign'], 'true')) - pool: - # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) - ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: - name: VSEngSS-MicroBuild2022-1ES - demands: Cmd - # If it's not devdiv, it's dnceng - ${{ else }}: - name: $(DncEngInternalBuildPool) - demands: ImageOverride -equals windows.vs2019.amd64 - steps: - - template: setup-maestro-vars.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - - - task: DownloadBuildArtifacts@0 - displayName: Download Package Artifacts - inputs: - buildType: specific - buildVersionToDownload: specific - project: $(AzDOProjectName) - pipeline: $(AzDOPipelineId) - buildId: $(AzDOBuildId) - artifactName: PackageArtifacts - checkDownloadedFiles: true - itemPattern: | - ** - !**/Microsoft.SourceBuild.Intermediate.*.nupkg - - # This is necessary whenever we want to publish/restore to an AzDO private feed - # Since sdk-task.ps1 tries to restore packages we need to do this authentication here - # otherwise it'll complain about accessing a private feed. - - task: NuGetAuthenticate@0 - displayName: 'Authenticate to AzDO Feeds' - - # Signing validation will optionally work with the buildmanifest file which is downloaded from - # Azure DevOps above. - - task: PowerShell@2 - displayName: Validate - inputs: - filePath: eng\common\sdk-task.ps1 - arguments: -task SigningValidation -restore -msbuildEngine vs - /p:PackageBasePath='$(Build.ArtifactStagingDirectory)/PackageArtifacts' - /p:SignCheckExclusionsFile='$(Build.SourcesDirectory)/eng/SignCheckExclusionsFile.txt' - ${{ parameters.signingValidationAdditionalParameters }} - - - template: ../steps/publish-logs.yml - parameters: - StageLabel: 'Validation' - JobLabel: 'Signing' - - - job: - displayName: SourceLink Validation - condition: eq( ${{ parameters.enableSourceLinkValidation }}, 'true') - pool: - # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) - ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: - name: VSEngSS-MicroBuild2022-1ES - demands: Cmd - # If it's not devdiv, it's dnceng - ${{ else }}: - name: $(DncEngInternalBuildPool) - demands: ImageOverride -equals windows.vs2019.amd64 - steps: - - template: setup-maestro-vars.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - - - task: DownloadBuildArtifacts@0 - displayName: Download Blob Artifacts - inputs: - buildType: specific - buildVersionToDownload: specific - project: $(AzDOProjectName) - pipeline: $(AzDOPipelineId) - buildId: $(AzDOBuildId) - artifactName: BlobArtifacts - checkDownloadedFiles: true - - - task: PowerShell@2 - displayName: Validate - inputs: - filePath: $(Build.SourcesDirectory)/eng/common/post-build/sourcelink-validation.ps1 - arguments: -InputPath $(Build.ArtifactStagingDirectory)/BlobArtifacts/ - -ExtractPath $(Agent.BuildDirectory)/Extract/ - -GHRepoName $(Build.Repository.Name) - -GHCommit $(Build.SourceVersion) - -SourcelinkCliVersion $(SourceLinkCLIVersion) - continueOnError: true - - - template: /eng/common/templates/job/execute-sdl.yml - parameters: - enable: ${{ parameters.SDLValidationParameters.enable }} - publishGuardianDirectoryToPipeline: ${{ parameters.SDLValidationParameters.publishGdn }} - additionalParameters: ${{ parameters.SDLValidationParameters.params }} - continueOnError: ${{ parameters.SDLValidationParameters.continueOnError }} - artifactNames: ${{ parameters.SDLValidationParameters.artifactNames }} - downloadArtifacts: ${{ parameters.SDLValidationParameters.downloadArtifacts }} - -- ${{ if ne(parameters.publishAssetsImmediately, 'true') }}: - - stage: publish_using_darc - ${{ if or(eq(parameters.enableNugetValidation, 'true'), eq(parameters.enableSigningValidation, 'true'), eq(parameters.enableSourceLinkValidation, 'true'), eq(parameters.SDLValidationParameters.enable, 'true')) }}: - dependsOn: ${{ parameters.publishDependsOn }} - ${{ else }}: - dependsOn: ${{ parameters.validateDependsOn }} - displayName: Publish using Darc - variables: - - template: common-variables.yml - - template: /eng/common/templates/variables/pool-providers.yml - jobs: - - job: - displayName: Publish Using Darc - timeoutInMinutes: 120 - pool: - # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) - ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: - name: VSEngSS-MicroBuild2022-1ES - demands: Cmd - # If it's not devdiv, it's dnceng - ${{ else }}: - name: $(DncEngInternalBuildPool) - demands: ImageOverride -equals windows.vs2019.amd64 - steps: - - template: setup-maestro-vars.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - - - task: NuGetAuthenticate@0 - - - task: PowerShell@2 - displayName: Publish Using Darc - inputs: - filePath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1 - arguments: -BuildId $(BARBuildId) - -PublishingInfraVersion ${{ parameters.publishingInfraVersion }} - -AzdoToken '$(publishing-dnceng-devdiv-code-r-build-re)' - -MaestroToken '$(MaestroApiAccessToken)' - -WaitPublishingFinish true - -ArtifactsPublishingAdditionalParameters '${{ parameters.artifactsPublishingAdditionalParameters }}' - -SymbolPublishingAdditionalParameters '${{ parameters.symbolPublishingAdditionalParameters }}' diff --git a/eng/common/templates/post-build/setup-maestro-vars.yml b/eng/common/templates/post-build/setup-maestro-vars.yml deleted file mode 100644 index 0c87f149a..000000000 --- a/eng/common/templates/post-build/setup-maestro-vars.yml +++ /dev/null @@ -1,70 +0,0 @@ -parameters: - BARBuildId: '' - PromoteToChannelIds: '' - -steps: - - ${{ if eq(coalesce(parameters.PromoteToChannelIds, 0), 0) }}: - - task: DownloadBuildArtifacts@0 - displayName: Download Release Configs - inputs: - buildType: current - artifactName: ReleaseConfigs - checkDownloadedFiles: true - - - task: PowerShell@2 - name: setReleaseVars - displayName: Set Release Configs Vars - inputs: - targetType: inline - pwsh: true - script: | - try { - if (!$Env:PromoteToMaestroChannels -or $Env:PromoteToMaestroChannels.Trim() -eq '') { - $Content = Get-Content $(Build.StagingDirectory)/ReleaseConfigs/ReleaseConfigs.txt - - $BarId = $Content | Select -Index 0 - $Channels = $Content | Select -Index 1 - $IsStableBuild = $Content | Select -Index 2 - - $AzureDevOpsProject = $Env:System_TeamProject - $AzureDevOpsBuildDefinitionId = $Env:System_DefinitionId - $AzureDevOpsBuildId = $Env:Build_BuildId - } - else { - $buildApiEndpoint = "${Env:MaestroApiEndPoint}/api/builds/${Env:BARBuildId}?api-version=${Env:MaestroApiVersion}" - - $apiHeaders = New-Object 'System.Collections.Generic.Dictionary[[String],[String]]' - $apiHeaders.Add('Accept', 'application/json') - $apiHeaders.Add('Authorization',"Bearer ${Env:MAESTRO_API_TOKEN}") - - $buildInfo = try { Invoke-WebRequest -Method Get -Uri $buildApiEndpoint -Headers $apiHeaders | ConvertFrom-Json } catch { Write-Host "Error: $_" } - - $BarId = $Env:BARBuildId - $Channels = $Env:PromoteToMaestroChannels -split "," - $Channels = $Channels -join "][" - $Channels = "[$Channels]" - - $IsStableBuild = $buildInfo.stable - $AzureDevOpsProject = $buildInfo.azureDevOpsProject - $AzureDevOpsBuildDefinitionId = $buildInfo.azureDevOpsBuildDefinitionId - $AzureDevOpsBuildId = $buildInfo.azureDevOpsBuildId - } - - Write-Host "##vso[task.setvariable variable=BARBuildId]$BarId" - Write-Host "##vso[task.setvariable variable=TargetChannels]$Channels" - Write-Host "##vso[task.setvariable variable=IsStableBuild]$IsStableBuild" - - Write-Host "##vso[task.setvariable variable=AzDOProjectName]$AzureDevOpsProject" - Write-Host "##vso[task.setvariable variable=AzDOPipelineId]$AzureDevOpsBuildDefinitionId" - Write-Host "##vso[task.setvariable variable=AzDOBuildId]$AzureDevOpsBuildId" - } - catch { - Write-Host $_ - Write-Host $_.Exception - Write-Host $_.ScriptStackTrace - exit 1 - } - env: - MAESTRO_API_TOKEN: $(MaestroApiAccessToken) - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToMaestroChannels: ${{ parameters.PromoteToChannelIds }} diff --git a/eng/common/templates/post-build/trigger-subscription.yml b/eng/common/templates/post-build/trigger-subscription.yml deleted file mode 100644 index da669030d..000000000 --- a/eng/common/templates/post-build/trigger-subscription.yml +++ /dev/null @@ -1,13 +0,0 @@ -parameters: - ChannelId: 0 - -steps: -- task: PowerShell@2 - displayName: Triggering subscriptions - inputs: - filePath: $(Build.SourcesDirectory)/eng/common/post-build/trigger-subscriptions.ps1 - arguments: -SourceRepo $(Build.Repository.Uri) - -ChannelId ${{ parameters.ChannelId }} - -MaestroApiAccessToken $(MaestroAccessToken) - -MaestroApiEndPoint $(MaestroApiEndPoint) - -MaestroApiVersion $(MaestroApiVersion) diff --git a/eng/common/templates/steps/add-build-to-channel.yml b/eng/common/templates/steps/add-build-to-channel.yml deleted file mode 100644 index f67a210d6..000000000 --- a/eng/common/templates/steps/add-build-to-channel.yml +++ /dev/null @@ -1,13 +0,0 @@ -parameters: - ChannelId: 0 - -steps: -- task: PowerShell@2 - displayName: Add Build to Channel - inputs: - filePath: $(Build.SourcesDirectory)/eng/common/post-build/add-build-to-channel.ps1 - arguments: -BuildId $(BARBuildId) - -ChannelId ${{ parameters.ChannelId }} - -MaestroApiAccessToken $(MaestroApiAccessToken) - -MaestroApiEndPoint $(MaestroApiEndPoint) - -MaestroApiVersion $(MaestroApiVersion) diff --git a/eng/common/templates/steps/build-reason.yml b/eng/common/templates/steps/build-reason.yml deleted file mode 100644 index eba58109b..000000000 --- a/eng/common/templates/steps/build-reason.yml +++ /dev/null @@ -1,12 +0,0 @@ -# build-reason.yml -# Description: runs steps if build.reason condition is valid. conditions is a string of valid build reasons -# to include steps (',' separated). -parameters: - conditions: '' - steps: [] - -steps: - - ${{ if and( not(startsWith(parameters.conditions, 'not')), contains(parameters.conditions, variables['build.reason'])) }}: - - ${{ parameters.steps }} - - ${{ if and( startsWith(parameters.conditions, 'not'), not(contains(parameters.conditions, variables['build.reason']))) }}: - - ${{ parameters.steps }} diff --git a/eng/common/templates/steps/execute-codeql.yml b/eng/common/templates/steps/execute-codeql.yml deleted file mode 100644 index 3930b1630..000000000 --- a/eng/common/templates/steps/execute-codeql.yml +++ /dev/null @@ -1,32 +0,0 @@ -parameters: - # Language that should be analyzed. Defaults to csharp - language: csharp - # Build Commands - buildCommands: '' - overrideParameters: '' # Optional: to override values for parameters. - additionalParameters: '' # Optional: parameters that need user specific values eg: '-SourceToolsList @("abc","def") -ArtifactToolsList @("ghi","jkl")' - # Optional: if specified, restore and use this version of Guardian instead of the default. - overrideGuardianVersion: '' - # Optional: if true, publish the '.gdn' folder as a pipeline artifact. This can help with in-depth - # diagnosis of problems with specific tool configurations. - publishGuardianDirectoryToPipeline: false - # The script to run to execute all SDL tools. Use this if you want to use a script to define SDL - # parameters rather than relying on YAML. It may be better to use a local script, because you can - # reproduce results locally without piecing together a command based on the YAML. - executeAllSdlToolsScript: 'eng/common/sdl/execute-all-sdl-tools.ps1' - # There is some sort of bug (has been reported) in Azure DevOps where if this parameter is named - # 'continueOnError', the parameter value is not correctly picked up. - # This can also be remedied by the caller (post-build.yml) if it does not use a nested parameter - # optional: determines whether to continue the build if the step errors; - sdlContinueOnError: false - -steps: -- template: /eng/common/templates/steps/execute-sdl.yml - parameters: - overrideGuardianVersion: ${{ parameters.overrideGuardianVersion }} - executeAllSdlToolsScript: ${{ parameters.executeAllSdlToolsScript }} - overrideParameters: ${{ parameters.overrideParameters }} - additionalParameters: '${{ parameters.additionalParameters }} - -CodeQLAdditionalRunConfigParams @("BuildCommands < ${{ parameters.buildCommands }}", "Language < ${{ parameters.language }}")' - publishGuardianDirectoryToPipeline: ${{ parameters.publishGuardianDirectoryToPipeline }} - sdlContinueOnError: ${{ parameters.sdlContinueOnError }} \ No newline at end of file diff --git a/eng/common/templates/steps/execute-sdl.yml b/eng/common/templates/steps/execute-sdl.yml deleted file mode 100644 index 9dd5709f6..000000000 --- a/eng/common/templates/steps/execute-sdl.yml +++ /dev/null @@ -1,88 +0,0 @@ -parameters: - overrideGuardianVersion: '' - executeAllSdlToolsScript: '' - overrideParameters: '' - additionalParameters: '' - publishGuardianDirectoryToPipeline: false - sdlContinueOnError: false - condition: '' - -steps: -- task: NuGetAuthenticate@1 - inputs: - nuGetServiceConnections: GuardianConnect - -- task: NuGetToolInstaller@1 - displayName: 'Install NuGet.exe' - -- ${{ if ne(parameters.overrideGuardianVersion, '') }}: - - pwsh: | - Set-Location -Path $(Build.SourcesDirectory)\eng\common\sdl - . .\sdl.ps1 - $guardianCliLocation = Install-Gdn -Path $(Build.SourcesDirectory)\.artifacts -Version ${{ parameters.overrideGuardianVersion }} - Write-Host "##vso[task.setvariable variable=GuardianCliLocation]$guardianCliLocation" - displayName: Install Guardian (Overridden) - -- ${{ if eq(parameters.overrideGuardianVersion, '') }}: - - pwsh: | - Set-Location -Path $(Build.SourcesDirectory)\eng\common\sdl - . .\sdl.ps1 - $guardianCliLocation = Install-Gdn -Path $(Build.SourcesDirectory)\.artifacts - Write-Host "##vso[task.setvariable variable=GuardianCliLocation]$guardianCliLocation" - displayName: Install Guardian - -- ${{ if ne(parameters.overrideParameters, '') }}: - - powershell: ${{ parameters.executeAllSdlToolsScript }} ${{ parameters.overrideParameters }} - displayName: Execute SDL - continueOnError: ${{ parameters.sdlContinueOnError }} - condition: ${{ parameters.condition }} - -- ${{ if eq(parameters.overrideParameters, '') }}: - - powershell: ${{ parameters.executeAllSdlToolsScript }} - -GuardianCliLocation $(GuardianCliLocation) - -NugetPackageDirectory $(Build.SourcesDirectory)\.packages - -AzureDevOpsAccessToken $(dn-bot-dotnet-build-rw-code-rw) - ${{ parameters.additionalParameters }} - displayName: Execute SDL - continueOnError: ${{ parameters.sdlContinueOnError }} - condition: ${{ parameters.condition }} - -- ${{ if ne(parameters.publishGuardianDirectoryToPipeline, 'false') }}: - # We want to publish the Guardian results and configuration for easy diagnosis. However, the - # '.gdn' dir is a mix of configuration, results, extracted dependencies, and Guardian default - # tooling files. Some of these files are large and aren't useful during an investigation, so - # exclude them by simply deleting them before publishing. (As of writing, there is no documented - # way to selectively exclude a dir from the pipeline artifact publish task.) - - task: DeleteFiles@1 - displayName: Delete Guardian dependencies to avoid uploading - inputs: - SourceFolder: $(Agent.BuildDirectory)/.gdn - Contents: | - c - i - condition: succeededOrFailed() - - - publish: $(Agent.BuildDirectory)/.gdn - artifact: GuardianConfiguration - displayName: Publish GuardianConfiguration - condition: succeededOrFailed() - - # Publish the SARIF files in a container named CodeAnalysisLogs to enable integration - # with the "SARIF SAST Scans Tab" Azure DevOps extension - - task: CopyFiles@2 - displayName: Copy SARIF files - inputs: - flattenFolders: true - sourceFolder: $(Agent.BuildDirectory)/.gdn/rc/ - contents: '**/*.sarif' - targetFolder: $(Build.SourcesDirectory)/CodeAnalysisLogs - condition: succeededOrFailed() - - # Use PublishBuildArtifacts because the SARIF extension only checks this case - # see microsoft/sarif-azuredevops-extension#4 - - task: PublishBuildArtifacts@1 - displayName: Publish SARIF files to CodeAnalysisLogs container - inputs: - pathToPublish: $(Build.SourcesDirectory)/CodeAnalysisLogs - artifactName: CodeAnalysisLogs - condition: succeededOrFailed() \ No newline at end of file diff --git a/eng/common/templates/steps/generate-sbom.yml b/eng/common/templates/steps/generate-sbom.yml deleted file mode 100644 index a06373f38..000000000 --- a/eng/common/templates/steps/generate-sbom.yml +++ /dev/null @@ -1,48 +0,0 @@ -# BuildDropPath - The root folder of the drop directory for which the manifest file will be generated. -# PackageName - The name of the package this SBOM represents. -# PackageVersion - The version of the package this SBOM represents. -# ManifestDirPath - The path of the directory where the generated manifest files will be placed -# IgnoreDirectories - Directories to ignore for SBOM generation. This will be passed through to the CG component detector. - -parameters: - PackageVersion: 7.0.0 - BuildDropPath: '$(Build.SourcesDirectory)/artifacts' - PackageName: '.NET' - ManifestDirPath: $(Build.ArtifactStagingDirectory)/sbom - IgnoreDirectories: '' - sbomContinueOnError: true - -steps: -- task: PowerShell@2 - displayName: Prep for SBOM generation in (Non-linux) - condition: or(eq(variables['Agent.Os'], 'Windows_NT'), eq(variables['Agent.Os'], 'Darwin')) - inputs: - filePath: ./eng/common/generate-sbom-prep.ps1 - arguments: ${{parameters.manifestDirPath}} - -# Chmodding is a workaround for https://github.com/dotnet/arcade/issues/8461 -- script: | - chmod +x ./eng/common/generate-sbom-prep.sh - ./eng/common/generate-sbom-prep.sh ${{parameters.manifestDirPath}} - displayName: Prep for SBOM generation in (Linux) - condition: eq(variables['Agent.Os'], 'Linux') - continueOnError: ${{ parameters.sbomContinueOnError }} - -- task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0 - displayName: 'Generate SBOM manifest' - continueOnError: ${{ parameters.sbomContinueOnError }} - inputs: - PackageName: ${{ parameters.packageName }} - BuildDropPath: ${{ parameters.buildDropPath }} - PackageVersion: ${{ parameters.packageVersion }} - ManifestDirPath: ${{ parameters.manifestDirPath }} - ${{ if ne(parameters.IgnoreDirectories, '') }}: - AdditionalComponentDetectorArgs: '--IgnoreDirectories ${{ parameters.IgnoreDirectories }}' - -- task: PublishPipelineArtifact@1 - displayName: Publish SBOM manifest - continueOnError: ${{parameters.sbomContinueOnError}} - inputs: - targetPath: '${{parameters.manifestDirPath}}' - artifactName: $(ARTIFACT_NAME) - diff --git a/eng/common/templates/steps/publish-logs.yml b/eng/common/templates/steps/publish-logs.yml deleted file mode 100644 index 88f238f36..000000000 --- a/eng/common/templates/steps/publish-logs.yml +++ /dev/null @@ -1,23 +0,0 @@ -parameters: - StageLabel: '' - JobLabel: '' - -steps: -- task: Powershell@2 - displayName: Prepare Binlogs to Upload - inputs: - targetType: inline - script: | - New-Item -ItemType Directory $(Build.SourcesDirectory)/PostBuildLogs/${{parameters.StageLabel}}/${{parameters.JobLabel}}/ - Move-Item -Path $(Build.SourcesDirectory)/artifacts/log/Debug/* $(Build.SourcesDirectory)/PostBuildLogs/${{parameters.StageLabel}}/${{parameters.JobLabel}}/ - continueOnError: true - condition: always() - -- task: PublishBuildArtifacts@1 - displayName: Publish Logs - inputs: - PathtoPublish: '$(Build.SourcesDirectory)/PostBuildLogs' - PublishLocation: Container - ArtifactName: PostBuildLogs - continueOnError: true - condition: always() diff --git a/eng/common/templates/steps/retain-build.yml b/eng/common/templates/steps/retain-build.yml deleted file mode 100644 index 83d97a26a..000000000 --- a/eng/common/templates/steps/retain-build.yml +++ /dev/null @@ -1,28 +0,0 @@ -parameters: - # Optional azure devops PAT with build execute permissions for the build's organization, - # only needed if the build that should be retained ran on a different organization than - # the pipeline where this template is executing from - Token: '' - # Optional BuildId to retain, defaults to the current running build - BuildId: '' - # Azure devops Organization URI for the build in the https://dev.azure.com/ format. - # Defaults to the organization the current pipeline is running on - AzdoOrgUri: '$(System.CollectionUri)' - # Azure devops project for the build. Defaults to the project the current pipeline is running on - AzdoProject: '$(System.TeamProject)' - -steps: - - task: powershell@2 - inputs: - targetType: 'filePath' - filePath: eng/common/retain-build.ps1 - pwsh: true - arguments: > - -AzdoOrgUri: ${{parameters.AzdoOrgUri}} - -AzdoProject ${{parameters.AzdoProject}} - -Token ${{coalesce(parameters.Token, '$env:SYSTEM_ACCESSTOKEN') }} - -BuildId ${{coalesce(parameters.BuildId, '$env:BUILD_ID')}} - displayName: Enable permanent build retention - env: - SYSTEM_ACCESSTOKEN: $(System.AccessToken) - BUILD_ID: $(Build.BuildId) \ No newline at end of file diff --git a/eng/common/templates/steps/run-on-unix.yml b/eng/common/templates/steps/run-on-unix.yml deleted file mode 100644 index e1733814f..000000000 --- a/eng/common/templates/steps/run-on-unix.yml +++ /dev/null @@ -1,7 +0,0 @@ -parameters: - agentOs: '' - steps: [] - -steps: -- ${{ if ne(parameters.agentOs, 'Windows_NT') }}: - - ${{ parameters.steps }} diff --git a/eng/common/templates/steps/run-on-windows.yml b/eng/common/templates/steps/run-on-windows.yml deleted file mode 100644 index 73e7e9c27..000000000 --- a/eng/common/templates/steps/run-on-windows.yml +++ /dev/null @@ -1,7 +0,0 @@ -parameters: - agentOs: '' - steps: [] - -steps: -- ${{ if eq(parameters.agentOs, 'Windows_NT') }}: - - ${{ parameters.steps }} diff --git a/eng/common/templates/steps/run-script-ifequalelse.yml b/eng/common/templates/steps/run-script-ifequalelse.yml deleted file mode 100644 index 3d1242f55..000000000 --- a/eng/common/templates/steps/run-script-ifequalelse.yml +++ /dev/null @@ -1,33 +0,0 @@ -parameters: - # if parameter1 equals parameter 2, run 'ifScript' command, else run 'elsescript' command - parameter1: '' - parameter2: '' - ifScript: '' - elseScript: '' - - # name of script step - name: Script - - # display name of script step - displayName: If-Equal-Else Script - - # environment - env: {} - - # conditional expression for step execution - condition: '' - -steps: -- ${{ if and(ne(parameters.ifScript, ''), eq(parameters.parameter1, parameters.parameter2)) }}: - - script: ${{ parameters.ifScript }} - name: ${{ parameters.name }} - displayName: ${{ parameters.displayName }} - env: ${{ parameters.env }} - condition: ${{ parameters.condition }} - -- ${{ if and(ne(parameters.elseScript, ''), ne(parameters.parameter1, parameters.parameter2)) }}: - - script: ${{ parameters.elseScript }} - name: ${{ parameters.name }} - displayName: ${{ parameters.displayName }} - env: ${{ parameters.env }} - condition: ${{ parameters.condition }} \ No newline at end of file diff --git a/eng/common/templates/steps/send-to-helix.yml b/eng/common/templates/steps/send-to-helix.yml deleted file mode 100644 index 3eb7e2d5f..000000000 --- a/eng/common/templates/steps/send-to-helix.yml +++ /dev/null @@ -1,91 +0,0 @@ -# Please remember to update the documentation if you make changes to these parameters! -parameters: - HelixSource: 'pr/default' # required -- sources must start with pr/, official/, prodcon/, or agent/ - HelixType: 'tests/default/' # required -- Helix telemetry which identifies what type of data this is; should include "test" for clarity and must end in '/' - HelixBuild: $(Build.BuildNumber) # required -- the build number Helix will use to identify this -- automatically set to the AzDO build number - HelixTargetQueues: '' # required -- semicolon-delimited list of Helix queues to test on; see https://helix.dot.net/ for a list of queues - HelixAccessToken: '' # required -- access token to make Helix API requests; should be provided by the appropriate variable group - HelixConfiguration: '' # optional -- additional property attached to a job - HelixPreCommands: '' # optional -- commands to run before Helix work item execution - HelixPostCommands: '' # optional -- commands to run after Helix work item execution - WorkItemDirectory: '' # optional -- a payload directory to zip up and send to Helix; requires WorkItemCommand; incompatible with XUnitProjects - WorkItemCommand: '' # optional -- a command to execute on the payload; requires WorkItemDirectory; incompatible with XUnitProjects - WorkItemTimeout: '' # optional -- a timeout in TimeSpan.Parse-ready value (e.g. 00:02:00) for the work item command; requires WorkItemDirectory; incompatible with XUnitProjects - CorrelationPayloadDirectory: '' # optional -- a directory to zip up and send to Helix as a correlation payload - XUnitProjects: '' # optional -- semicolon-delimited list of XUnitProjects to parse and send to Helix; requires XUnitRuntimeTargetFramework, XUnitPublishTargetFramework, XUnitRunnerVersion, and IncludeDotNetCli=true - XUnitWorkItemTimeout: '' # optional -- the workitem timeout in seconds for all workitems created from the xUnit projects specified by XUnitProjects - XUnitPublishTargetFramework: '' # optional -- framework to use to publish your xUnit projects - XUnitRuntimeTargetFramework: '' # optional -- framework to use for the xUnit console runner - XUnitRunnerVersion: '' # optional -- version of the xUnit nuget package you wish to use on Helix; required for XUnitProjects - IncludeDotNetCli: false # optional -- true will download a version of the .NET CLI onto the Helix machine as a correlation payload; requires DotNetCliPackageType and DotNetCliVersion - DotNetCliPackageType: '' # optional -- either 'sdk', 'runtime' or 'aspnetcore-runtime'; determines whether the sdk or runtime will be sent to Helix; see https://raw.githubusercontent.com/dotnet/core/main/release-notes/releases-index.json - DotNetCliVersion: '' # optional -- version of the CLI to send to Helix; based on this: https://raw.githubusercontent.com/dotnet/core/main/release-notes/releases-index.json - WaitForWorkItemCompletion: true # optional -- true will make the task wait until work items have been completed and fail the build if work items fail. False is "fire and forget." - IsExternal: false # [DEPRECATED] -- doesn't do anything, jobs are external if HelixAccessToken is empty and Creator is set - HelixBaseUri: 'https://helix.dot.net/' # optional -- sets the Helix API base URI (allows targeting https://helix.int-dot.net ) - Creator: '' # optional -- if the build is external, use this to specify who is sending the job - DisplayNamePrefix: 'Run Tests' # optional -- rename the beginning of the displayName of the steps in AzDO - condition: succeeded() # optional -- condition for step to execute; defaults to succeeded() - continueOnError: false # optional -- determines whether to continue the build if the step errors; defaults to false - -steps: - - powershell: 'powershell "$env:BUILD_SOURCESDIRECTORY\eng\common\msbuild.ps1 $env:BUILD_SOURCESDIRECTORY\eng\common\helixpublish.proj /restore /p:TreatWarningsAsErrors=false /t:Test /bl:$env:BUILD_SOURCESDIRECTORY\artifacts\log\$env:BuildConfig\SendToHelix.binlog"' - displayName: ${{ parameters.DisplayNamePrefix }} (Windows) - env: - BuildConfig: $(_BuildConfig) - HelixSource: ${{ parameters.HelixSource }} - HelixType: ${{ parameters.HelixType }} - HelixBuild: ${{ parameters.HelixBuild }} - HelixConfiguration: ${{ parameters.HelixConfiguration }} - HelixTargetQueues: ${{ parameters.HelixTargetQueues }} - HelixAccessToken: ${{ parameters.HelixAccessToken }} - HelixPreCommands: ${{ parameters.HelixPreCommands }} - HelixPostCommands: ${{ parameters.HelixPostCommands }} - WorkItemDirectory: ${{ parameters.WorkItemDirectory }} - WorkItemCommand: ${{ parameters.WorkItemCommand }} - WorkItemTimeout: ${{ parameters.WorkItemTimeout }} - CorrelationPayloadDirectory: ${{ parameters.CorrelationPayloadDirectory }} - XUnitProjects: ${{ parameters.XUnitProjects }} - XUnitWorkItemTimeout: ${{ parameters.XUnitWorkItemTimeout }} - XUnitPublishTargetFramework: ${{ parameters.XUnitPublishTargetFramework }} - XUnitRuntimeTargetFramework: ${{ parameters.XUnitRuntimeTargetFramework }} - XUnitRunnerVersion: ${{ parameters.XUnitRunnerVersion }} - IncludeDotNetCli: ${{ parameters.IncludeDotNetCli }} - DotNetCliPackageType: ${{ parameters.DotNetCliPackageType }} - DotNetCliVersion: ${{ parameters.DotNetCliVersion }} - WaitForWorkItemCompletion: ${{ parameters.WaitForWorkItemCompletion }} - HelixBaseUri: ${{ parameters.HelixBaseUri }} - Creator: ${{ parameters.Creator }} - SYSTEM_ACCESSTOKEN: $(System.AccessToken) - condition: and(${{ parameters.condition }}, eq(variables['Agent.Os'], 'Windows_NT')) - continueOnError: ${{ parameters.continueOnError }} - - script: $BUILD_SOURCESDIRECTORY/eng/common/msbuild.sh $BUILD_SOURCESDIRECTORY/eng/common/helixpublish.proj /restore /p:TreatWarningsAsErrors=false /t:Test /bl:$BUILD_SOURCESDIRECTORY/artifacts/log/$BuildConfig/SendToHelix.binlog - displayName: ${{ parameters.DisplayNamePrefix }} (Unix) - env: - BuildConfig: $(_BuildConfig) - HelixSource: ${{ parameters.HelixSource }} - HelixType: ${{ parameters.HelixType }} - HelixBuild: ${{ parameters.HelixBuild }} - HelixConfiguration: ${{ parameters.HelixConfiguration }} - HelixTargetQueues: ${{ parameters.HelixTargetQueues }} - HelixAccessToken: ${{ parameters.HelixAccessToken }} - HelixPreCommands: ${{ parameters.HelixPreCommands }} - HelixPostCommands: ${{ parameters.HelixPostCommands }} - WorkItemDirectory: ${{ parameters.WorkItemDirectory }} - WorkItemCommand: ${{ parameters.WorkItemCommand }} - WorkItemTimeout: ${{ parameters.WorkItemTimeout }} - CorrelationPayloadDirectory: ${{ parameters.CorrelationPayloadDirectory }} - XUnitProjects: ${{ parameters.XUnitProjects }} - XUnitWorkItemTimeout: ${{ parameters.XUnitWorkItemTimeout }} - XUnitPublishTargetFramework: ${{ parameters.XUnitPublishTargetFramework }} - XUnitRuntimeTargetFramework: ${{ parameters.XUnitRuntimeTargetFramework }} - XUnitRunnerVersion: ${{ parameters.XUnitRunnerVersion }} - IncludeDotNetCli: ${{ parameters.IncludeDotNetCli }} - DotNetCliPackageType: ${{ parameters.DotNetCliPackageType }} - DotNetCliVersion: ${{ parameters.DotNetCliVersion }} - WaitForWorkItemCompletion: ${{ parameters.WaitForWorkItemCompletion }} - HelixBaseUri: ${{ parameters.HelixBaseUri }} - Creator: ${{ parameters.Creator }} - SYSTEM_ACCESSTOKEN: $(System.AccessToken) - condition: and(${{ parameters.condition }}, ne(variables['Agent.Os'], 'Windows_NT')) - continueOnError: ${{ parameters.continueOnError }} diff --git a/eng/common/templates/steps/source-build.yml b/eng/common/templates/steps/source-build.yml deleted file mode 100644 index a97a185a3..000000000 --- a/eng/common/templates/steps/source-build.yml +++ /dev/null @@ -1,114 +0,0 @@ -parameters: - # This template adds arcade-powered source-build to CI. - - # This is a 'steps' template, and is intended for advanced scenarios where the existing build - # infra has a careful build methodology that must be followed. For example, a repo - # (dotnet/runtime) might choose to clone the GitHub repo only once and store it as a pipeline - # artifact for all subsequent jobs to use, to reduce dependence on a strong network connection to - # GitHub. Using this steps template leaves room for that infra to be included. - - # Defines the platform on which to run the steps. See 'eng/common/templates/job/source-build.yml' - # for details. The entire object is described in the 'job' template for simplicity, even though - # the usage of the properties on this object is split between the 'job' and 'steps' templates. - platform: {} - -steps: -# Build. Keep it self-contained for simple reusability. (No source-build-specific job variables.) -- script: | - set -x - df -h - - # If building on the internal project, the artifact feeds variable may be available (usually only if needed) - # In that case, call the feed setup script to add internal feeds corresponding to public ones. - # In addition, add an msbuild argument to copy the WIP from the repo to the target build location. - # This is because SetupNuGetSources.sh will alter the current NuGet.config file, and we need to preserve those - # changes. - internalRestoreArgs= - if [ '$(dn-bot-dnceng-artifact-feeds-rw)' != '$''(dn-bot-dnceng-artifact-feeds-rw)' ]; then - # Temporarily work around https://github.com/dotnet/arcade/issues/7709 - chmod +x $(Build.SourcesDirectory)/eng/common/SetupNugetSources.sh - $(Build.SourcesDirectory)/eng/common/SetupNugetSources.sh $(Build.SourcesDirectory)/NuGet.config $(dn-bot-dnceng-artifact-feeds-rw) - internalRestoreArgs='/p:CopyWipIntoInnerSourceBuildRepo=true' - - # The 'Copy WIP' feature of source build uses git stash to apply changes from the original repo. - # This only works if there is a username/email configured, which won't be the case in most CI runs. - git config --get user.email - if [ $? -ne 0 ]; then - git config user.email dn-bot@microsoft.com - git config user.name dn-bot - fi - fi - - # If building on the internal project, the internal storage variable may be available (usually only if needed) - # In that case, add variables to allow the download of internal runtimes if the specified versions are not found - # in the default public locations. - internalRuntimeDownloadArgs= - if [ '$(dotnetbuilds-internal-container-read-token-base64)' != '$''(dotnetbuilds-internal-container-read-token-base64)' ]; then - internalRuntimeDownloadArgs='/p:DotNetRuntimeSourceFeed=https://dotnetbuilds.blob.core.windows.net/internal /p:DotNetRuntimeSourceFeedKey=$(dotnetbuilds-internal-container-read-token-base64) --runtimesourcefeed https://dotnetbuilds.blob.core.windows.net/internal --runtimesourcefeedkey $(dotnetbuilds-internal-container-read-token-base64)' - fi - - buildConfig=Release - # Check if AzDO substitutes in a build config from a variable, and use it if so. - if [ '$(_BuildConfig)' != '$''(_BuildConfig)' ]; then - buildConfig='$(_BuildConfig)' - fi - - officialBuildArgs= - if [ '${{ and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}' = 'True' ]; then - officialBuildArgs='/p:DotNetPublishUsingPipelines=true /p:OfficialBuildId=$(BUILD.BUILDNUMBER)' - fi - - targetRidArgs= - if [ '${{ parameters.platform.targetRID }}' != '' ]; then - targetRidArgs='/p:TargetRid=${{ parameters.platform.targetRID }}' - fi - - runtimeOsArgs= - if [ '${{ parameters.platform.runtimeOS }}' != '' ]; then - runtimeOsArgs='/p:RuntimeOS=${{ parameters.platform.runtimeOS }}' - fi - - publishArgs= - if [ '${{ parameters.platform.skipPublishValidation }}' != 'true' ]; then - publishArgs='--publish' - fi - - assetManifestFileName=SourceBuild_RidSpecific.xml - if [ '${{ parameters.platform.name }}' != '' ]; then - assetManifestFileName=SourceBuild_${{ parameters.platform.name }}.xml - fi - - ${{ coalesce(parameters.platform.buildScript, './build.sh') }} --ci \ - --configuration $buildConfig \ - --restore --build --pack $publishArgs -bl \ - $officialBuildArgs \ - $internalRuntimeDownloadArgs \ - $internalRestoreArgs \ - $targetRidArgs \ - $runtimeOsArgs \ - /p:SourceBuildNonPortable=${{ parameters.platform.nonPortable }} \ - /p:ArcadeBuildFromSource=true \ - /p:AssetManifestFileName=$assetManifestFileName - displayName: Build - -# Upload build logs for diagnosis. -- task: CopyFiles@2 - displayName: Prepare BuildLogs staging directory - inputs: - SourceFolder: '$(Build.SourcesDirectory)' - Contents: | - **/*.log - **/*.binlog - artifacts/source-build/self/prebuilt-report/** - TargetFolder: '$(Build.StagingDirectory)/BuildLogs' - CleanTargetFolder: true - continueOnError: true - condition: succeededOrFailed() - -- task: PublishPipelineArtifact@1 - displayName: Publish BuildLogs - inputs: - targetPath: '$(Build.StagingDirectory)/BuildLogs' - artifactName: BuildLogs_SourceBuild_${{ parameters.platform.name }}_Attempt$(System.JobAttempt) - continueOnError: true - condition: succeededOrFailed() diff --git a/eng/common/templates/steps/telemetry-end.yml b/eng/common/templates/steps/telemetry-end.yml deleted file mode 100644 index fadc04ca1..000000000 --- a/eng/common/templates/steps/telemetry-end.yml +++ /dev/null @@ -1,102 +0,0 @@ -parameters: - maxRetries: 5 - retryDelay: 10 # in seconds - -steps: -- bash: | - if [ "$AGENT_JOBSTATUS" = "Succeeded" ] || [ "$AGENT_JOBSTATUS" = "PartiallySucceeded" ]; then - errorCount=0 - else - errorCount=1 - fi - warningCount=0 - - curlStatus=1 - retryCount=0 - # retry loop to harden against spotty telemetry connections - # we don't retry successes and 4xx client errors - until [[ $curlStatus -eq 0 || ( $curlStatus -ge 400 && $curlStatus -le 499 ) || $retryCount -ge $MaxRetries ]] - do - if [ $retryCount -gt 0 ]; then - echo "Failed to send telemetry to Helix; waiting $RetryDelay seconds before retrying..." - sleep $RetryDelay - fi - - # create a temporary file for curl output - res=`mktemp` - - curlResult=` - curl --verbose --output $res --write-out "%{http_code}"\ - -H 'Content-Type: application/json' \ - -H "X-Helix-Job-Token: $Helix_JobToken" \ - -H 'Content-Length: 0' \ - -X POST -G "https://helix.dot.net/api/2018-03-14/telemetry/job/build/$Helix_WorkItemId/finish" \ - --data-urlencode "errorCount=$errorCount" \ - --data-urlencode "warningCount=$warningCount"` - curlStatus=$? - - if [ $curlStatus -eq 0 ]; then - if [ $curlResult -gt 299 ] || [ $curlResult -lt 200 ]; then - curlStatus=$curlResult - fi - fi - - let retryCount++ - done - - if [ $curlStatus -ne 0 ]; then - echo "Failed to Send Build Finish information after $retryCount retries" - vstsLogOutput="vso[task.logissue type=error;sourcepath=templates/steps/telemetry-end.yml;code=1;]Failed to Send Build Finish information: $curlStatus" - echo "##$vstsLogOutput" - exit 1 - fi - displayName: Send Unix Build End Telemetry - env: - # defined via VSTS variables in start-job.sh - Helix_JobToken: $(Helix_JobToken) - Helix_WorkItemId: $(Helix_WorkItemId) - MaxRetries: ${{ parameters.maxRetries }} - RetryDelay: ${{ parameters.retryDelay }} - condition: and(always(), ne(variables['Agent.Os'], 'Windows_NT')) -- powershell: | - if (($env:Agent_JobStatus -eq 'Succeeded') -or ($env:Agent_JobStatus -eq 'PartiallySucceeded')) { - $ErrorCount = 0 - } else { - $ErrorCount = 1 - } - $WarningCount = 0 - - # Basic retry loop to harden against server flakiness - $retryCount = 0 - while ($retryCount -lt $env:MaxRetries) { - try { - Invoke-RestMethod -Uri "https://helix.dot.net/api/2018-03-14/telemetry/job/build/$env:Helix_WorkItemId/finish?errorCount=$ErrorCount&warningCount=$WarningCount" -Method Post -ContentType "application/json" -Body "" ` - -Headers @{ 'X-Helix-Job-Token'=$env:Helix_JobToken } - break - } - catch { - $statusCode = $_.Exception.Response.StatusCode.value__ - if ($statusCode -ge 400 -and $statusCode -le 499) { - Write-Host "##vso[task.logissue]error Failed to send telemetry to Helix (status code $statusCode); not retrying (4xx client error)" - Write-Host "##vso[task.logissue]error ", $_.Exception.GetType().FullName, $_.Exception.Message - exit 1 - } - Write-Host "Failed to send telemetry to Helix (status code $statusCode); waiting $env:RetryDelay seconds before retrying..." - $retryCount++ - sleep $env:RetryDelay - continue - } - } - - if ($retryCount -ge $env:MaxRetries) { - Write-Host "##vso[task.logissue]error Failed to send telemetry to Helix after $retryCount retries." - exit 1 - } - displayName: Send Windows Build End Telemetry - env: - # defined via VSTS variables in start-job.ps1 - Helix_JobToken: $(Helix_JobToken) - Helix_WorkItemId: $(Helix_WorkItemId) - MaxRetries: ${{ parameters.maxRetries }} - RetryDelay: ${{ parameters.retryDelay }} - condition: and(always(),eq(variables['Agent.Os'], 'Windows_NT')) diff --git a/eng/common/templates/steps/telemetry-start.yml b/eng/common/templates/steps/telemetry-start.yml deleted file mode 100644 index 32c01ef0b..000000000 --- a/eng/common/templates/steps/telemetry-start.yml +++ /dev/null @@ -1,241 +0,0 @@ -parameters: - helixSource: 'undefined_defaulted_in_telemetry.yml' - helixType: 'undefined_defaulted_in_telemetry.yml' - buildConfig: '' - runAsPublic: false - maxRetries: 5 - retryDelay: 10 # in seconds - -steps: -- ${{ if and(eq(parameters.runAsPublic, 'false'), not(eq(variables['System.TeamProject'], 'public'))) }}: - - task: AzureKeyVault@1 - inputs: - azureSubscription: 'HelixProd_KeyVault' - KeyVaultName: HelixProdKV - SecretsFilter: 'HelixApiAccessToken' - condition: always() -- bash: | - # create a temporary file - jobInfo=`mktemp` - - # write job info content to temporary file - cat > $jobInfo < Date: Wed, 31 Jul 2024 10:10:08 -0700 Subject: [PATCH 49/54] Create tsaoptions.json (#422) --- .config/tsaoptions.json | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .config/tsaoptions.json diff --git a/.config/tsaoptions.json b/.config/tsaoptions.json new file mode 100644 index 000000000..cb7d8b10a --- /dev/null +++ b/.config/tsaoptions.json @@ -0,0 +1,12 @@ +{ + "areaPath": "DevDiv\\ASP.NET Core\\Policy Violations", + "codebaseName": "AspNetWebStack", + "instanceUrl": "https://devdiv.visualstudio.com/", + "iterationPath": "DevDiv", + "notificationAliases": [ + "aspnetcore-build@microsoft.com" + ], + "projectName": "DEVDIV", + "repositoryName": "AspNetWebStack", + "template": "TFSDEVDIV" +} From a815d5d3566b99786c0db045697755d3bf867d8c Mon Sep 17 00:00:00 2001 From: Immo Landwerth Date: Tue, 10 Sep 2024 16:52:47 -0700 Subject: [PATCH 50/54] Add SECURITY.md --- SECURITY.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..8312d20e4 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,15 @@ +# Security Policy + +## Supported Versions + +The .NET Core and ASP.NET Core support policy, including supported versions can be found at the [.NET Core Support Policy Page](https://dotnet.microsoft.com/platform/support/policy/dotnet-core). + +## Reporting a Vulnerability + +Security issues and bugs should be reported privately to the Microsoft Security Response Center (MSRC), either by emailing secure@microsoft.com or via the portal at https://msrc.microsoft.com. +You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your +original message. Further information, including the MSRC PGP key, can be found in the [MSRC Report an Issue FAQ](https://www.microsoft.com/en-us/msrc/faqs-report-an-issue). + +Reports via MSRC may qualify for the .NET Core Bug Bounty. Details of the .NET Core Bug Bounty including terms and conditions are at [https://aka.ms/corebounty](https://aka.ms/corebounty). + +Please do not open issues for anything you think might have a security implication. From ac13758d837527a8f6e1909edb01d1086d59d28a Mon Sep 17 00:00:00 2001 From: Immo Landwerth Date: Thu, 12 Sep 2024 10:57:40 -0700 Subject: [PATCH 51/54] Update wording as this isn't a .NET Core related project --- SECURITY.md | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index 8312d20e4..edbf5411a 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,15 +1,9 @@ # Security Policy -## Supported Versions - -The .NET Core and ASP.NET Core support policy, including supported versions can be found at the [.NET Core Support Policy Page](https://dotnet.microsoft.com/platform/support/policy/dotnet-core). - ## Reporting a Vulnerability Security issues and bugs should be reported privately to the Microsoft Security Response Center (MSRC), either by emailing secure@microsoft.com or via the portal at https://msrc.microsoft.com. You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Further information, including the MSRC PGP key, can be found in the [MSRC Report an Issue FAQ](https://www.microsoft.com/en-us/msrc/faqs-report-an-issue). -Reports via MSRC may qualify for the .NET Core Bug Bounty. Details of the .NET Core Bug Bounty including terms and conditions are at [https://aka.ms/corebounty](https://aka.ms/corebounty). - -Please do not open issues for anything you think might have a security implication. +Please do not open issues for anything you think might have a security implication. \ No newline at end of file From 82979e88e7b115aa437c0fd484e91c3105217366 Mon Sep 17 00:00:00 2001 From: William Godbe Date: Thu, 19 Sep 2024 14:49:47 -0700 Subject: [PATCH 52/54] Stop using -pt images (#426) --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 8b8cf5324..9340f820d 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -36,7 +36,7 @@ extends: parameters: pool: name: NetCore1ESPool-Svc-Internal - image: 1es-windows-2019-pt + image: 1es-windows-2019 os: windows stages: - stage: build From a55e96a451393aa854556ac9feb2d80e81988a9c Mon Sep 17 00:00:00 2001 From: William Godbe Date: Fri, 27 Sep 2024 14:30:30 -0700 Subject: [PATCH 53/54] Enable TSA/Policheck (#427) --- azure-pipelines.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 9340f820d..f31f55af6 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -34,6 +34,11 @@ resources: extends: template: v1/1ES.Official.PipelineTemplate.yml@1esPipelines parameters: + sdl: + policheck: + enabled: true + tsa: + enabled: true pool: name: NetCore1ESPool-Svc-Internal image: 1es-windows-2019 From 71a542f502b6d2a59c23836ce0befe3d9525b3e7 Mon Sep 17 00:00:00 2001 From: William Godbe Date: Wed, 3 Sep 2025 13:36:10 -0700 Subject: [PATCH 54/54] Add CredScanSuppressions (#432) --- .config/CredScanSuppressions.json | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 .config/CredScanSuppressions.json diff --git a/.config/CredScanSuppressions.json b/.config/CredScanSuppressions.json new file mode 100644 index 000000000..8db08e538 --- /dev/null +++ b/.config/CredScanSuppressions.json @@ -0,0 +1,29 @@ +{ + "tool": "Credential Scanner", + "suppressions": [ + { + "placeholder": "abcdefg", + "_justification": "This is a fake password used in test code." + }, + { + "placeholder": "Pa$$AAECAw==", + "_justification": "This is a fake password used in test code." + }, + { + "placeholder": "ALyuoraY/cIWD1hjo+K81/pf83qo6Q6T+UBYcXN9P3A9WHLvEY10f+lwW5qPG6h9xw==", + "_justification": "This is a fake hashed password used in test code." + }, + { + "placeholder": "abcdefg123", + "_justification": "This is a fake password used in test code." + }, + { + "placeholder": "3e29b24f825e737d97aed5eb62df5076", + "_justification": "This is a fake password used in test code." + }, + { + "placeholder": "My Password", + "_justification": "This is a fake password used in test code." + } + ] +} \ No newline at end of file