diff options
author | dotnet-maestro[bot] <42748379+dotnet-maestro[bot]@users.noreply.github.com> | 2022-06-29 00:53:32 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-06-29 00:53:32 +0300 |
commit | 19a2bd0b050d543665b26c7e14872f6999315c43 (patch) | |
tree | a3ffbfde9e855a90b9ca6a2e322f0e21538b0db9 | |
parent | 32dfb4184730ac0015531a4f87dc6208057d55b3 (diff) |
[release/7.0-preview6] Update dependencies from dotnet/runtime dotnet/efcore (#42358)
* Update dependencies from https://github.com/dotnet/efcore build 20220622.4
dotnet-ef , Microsoft.EntityFrameworkCore , Microsoft.EntityFrameworkCore.Design , Microsoft.EntityFrameworkCore.InMemory , Microsoft.EntityFrameworkCore.Relational , Microsoft.EntityFrameworkCore.Sqlite , Microsoft.EntityFrameworkCore.SqlServer , Microsoft.EntityFrameworkCore.Tools
From Version 7.0.0-preview.6.22322.3 -> To Version 7.0.0-preview.6.22322.4
* Update dependencies from https://github.com/dotnet/runtime build 20220623.3
Microsoft.Extensions.Caching.Abstractions , Microsoft.Extensions.Caching.Memory , Microsoft.Extensions.Configuration , Microsoft.Extensions.Configuration.Abstractions , Microsoft.Extensions.Configuration.Binder , Microsoft.Extensions.Configuration.CommandLine , Microsoft.Extensions.Configuration.EnvironmentVariables , Microsoft.Extensions.Configuration.FileExtensions , Microsoft.Extensions.Configuration.Ini , Microsoft.Extensions.Configuration.Json , Microsoft.Extensions.Configuration.UserSecrets , Microsoft.Extensions.Configuration.Xml , Microsoft.Extensions.DependencyInjection , Microsoft.Extensions.DependencyInjection.Abstractions , Microsoft.Extensions.DependencyModel , Microsoft.Extensions.FileProviders.Abstractions , Microsoft.Extensions.FileProviders.Composite , Microsoft.Extensions.FileProviders.Physical , Microsoft.Extensions.FileSystemGlobbing , Microsoft.Extensions.HostFactoryResolver.Sources , Microsoft.Extensions.Hosting , Microsoft.Extensions.Hosting.Abstractions , Microsoft.Extensions.Http , Microsoft.Extensions.Logging , Microsoft.Extensions.Logging.Abstractions , Microsoft.Extensions.Logging.Configuration , Microsoft.Extensions.Logging.Console , Microsoft.Extensions.Logging.Debug , Microsoft.Extensions.Logging.EventLog , Microsoft.Extensions.Logging.EventSource , Microsoft.Extensions.Logging.TraceSource , Microsoft.Extensions.Options , Microsoft.Extensions.Options.ConfigurationExtensions , Microsoft.Extensions.Options.DataAnnotations , Microsoft.Extensions.Primitives , Microsoft.Internal.Runtime.AspNetCore.Transport , Microsoft.NET.Runtime.MonoAOTCompiler.Task , Microsoft.NET.Runtime.WebAssembly.Sdk , Microsoft.NETCore.App.Ref , Microsoft.NETCore.App.Runtime.AOT.win-x64.Cross.browser-wasm , Microsoft.NETCore.App.Runtime.win-x64 , Microsoft.NETCore.BrowserDebugHost.Transport , Microsoft.NETCore.Platforms , System.Configuration.ConfigurationManager , System.Diagnostics.DiagnosticSource , System.Diagnostics.EventLog , System.DirectoryServices.Protocols , System.IO.Pipelines , System.Net.Http.Json , System.Net.Http.WinHttpHandler , System.Reflection.Metadata , System.Resources.Extensions , System.Security.Cryptography.Pkcs , System.Security.Cryptography.Xml , System.Security.Permissions , System.ServiceProcess.ServiceController , System.Text.Encodings.Web , System.Text.Json , System.Threading.AccessControl , System.Threading.Channels , System.Threading.RateLimiting
From Version 7.0.0-preview.6.22321.8 -> To Version 7.0.0-preview.6.22323.3
* Update dependencies from https://github.com/dotnet/runtime build 20220623.6
Microsoft.Extensions.Caching.Abstractions , Microsoft.Extensions.Caching.Memory , Microsoft.Extensions.Configuration , Microsoft.Extensions.Configuration.Abstractions , Microsoft.Extensions.Configuration.Binder , Microsoft.Extensions.Configuration.CommandLine , Microsoft.Extensions.Configuration.EnvironmentVariables , Microsoft.Extensions.Configuration.FileExtensions , Microsoft.Extensions.Configuration.Ini , Microsoft.Extensions.Configuration.Json , Microsoft.Extensions.Configuration.UserSecrets , Microsoft.Extensions.Configuration.Xml , Microsoft.Extensions.DependencyInjection , Microsoft.Extensions.DependencyInjection.Abstractions , Microsoft.Extensions.DependencyModel , Microsoft.Extensions.FileProviders.Abstractions , Microsoft.Extensions.FileProviders.Composite , Microsoft.Extensions.FileProviders.Physical , Microsoft.Extensions.FileSystemGlobbing , Microsoft.Extensions.HostFactoryResolver.Sources , Microsoft.Extensions.Hosting , Microsoft.Extensions.Hosting.Abstractions , Microsoft.Extensions.Http , Microsoft.Extensions.Logging , Microsoft.Extensions.Logging.Abstractions , Microsoft.Extensions.Logging.Configuration , Microsoft.Extensions.Logging.Console , Microsoft.Extensions.Logging.Debug , Microsoft.Extensions.Logging.EventLog , Microsoft.Extensions.Logging.EventSource , Microsoft.Extensions.Logging.TraceSource , Microsoft.Extensions.Options , Microsoft.Extensions.Options.ConfigurationExtensions , Microsoft.Extensions.Options.DataAnnotations , Microsoft.Extensions.Primitives , Microsoft.Internal.Runtime.AspNetCore.Transport , Microsoft.NET.Runtime.MonoAOTCompiler.Task , Microsoft.NET.Runtime.WebAssembly.Sdk , Microsoft.NETCore.App.Ref , Microsoft.NETCore.App.Runtime.AOT.win-x64.Cross.browser-wasm , Microsoft.NETCore.App.Runtime.win-x64 , Microsoft.NETCore.BrowserDebugHost.Transport , Microsoft.NETCore.Platforms , System.Configuration.ConfigurationManager , System.Diagnostics.DiagnosticSource , System.Diagnostics.EventLog , System.DirectoryServices.Protocols , System.IO.Pipelines , System.Net.Http.Json , System.Net.Http.WinHttpHandler , System.Reflection.Metadata , System.Resources.Extensions , System.Security.Cryptography.Pkcs , System.Security.Cryptography.Xml , System.Security.Permissions , System.ServiceProcess.ServiceController , System.Text.Encodings.Web , System.Text.Json , System.Threading.AccessControl , System.Threading.Channels , System.Threading.RateLimiting
From Version 7.0.0-preview.6.22321.8 -> To Version 7.0.0-preview.6.22323.6
* Update dependencies from https://github.com/dotnet/efcore build 20220623.4
dotnet-ef , Microsoft.EntityFrameworkCore , Microsoft.EntityFrameworkCore.Design , Microsoft.EntityFrameworkCore.InMemory , Microsoft.EntityFrameworkCore.Relational , Microsoft.EntityFrameworkCore.Sqlite , Microsoft.EntityFrameworkCore.SqlServer , Microsoft.EntityFrameworkCore.Tools
From Version 7.0.0-preview.6.22322.3 -> To Version 7.0.0-preview.6.22323.4
Co-authored-by: dotnet-maestro[bot] <dotnet-maestro[bot]@users.noreply.github.com>
27 files changed, 1318 insertions, 340 deletions
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 6c3a14c54f..5f08da848d 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -9,288 +9,288 @@ --> <Dependencies> <ProductDependencies> - <Dependency Name="dotnet-ef" Version="7.0.0-preview.6.22322.3"> + <Dependency Name="dotnet-ef" Version="7.0.0-preview.6.22323.4"> <Uri>https://github.com/dotnet/efcore</Uri> - <Sha>5618bc6a0aa2e0dfed57c0f3cd64830733e7c924</Sha> + <Sha>380454af37a6c779763f2bd95360c0797ce980b6</Sha> </Dependency> - <Dependency Name="Microsoft.EntityFrameworkCore.InMemory" Version="7.0.0-preview.6.22322.3"> + <Dependency Name="Microsoft.EntityFrameworkCore.InMemory" Version="7.0.0-preview.6.22323.4"> <Uri>https://github.com/dotnet/efcore</Uri> - <Sha>5618bc6a0aa2e0dfed57c0f3cd64830733e7c924</Sha> + <Sha>380454af37a6c779763f2bd95360c0797ce980b6</Sha> </Dependency> - <Dependency Name="Microsoft.EntityFrameworkCore.Relational" Version="7.0.0-preview.6.22322.3"> + <Dependency Name="Microsoft.EntityFrameworkCore.Relational" Version="7.0.0-preview.6.22323.4"> <Uri>https://github.com/dotnet/efcore</Uri> - <Sha>5618bc6a0aa2e0dfed57c0f3cd64830733e7c924</Sha> + <Sha>380454af37a6c779763f2bd95360c0797ce980b6</Sha> </Dependency> - <Dependency Name="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.0-preview.6.22322.3"> + <Dependency Name="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.0-preview.6.22323.4"> <Uri>https://github.com/dotnet/efcore</Uri> - <Sha>5618bc6a0aa2e0dfed57c0f3cd64830733e7c924</Sha> + <Sha>380454af37a6c779763f2bd95360c0797ce980b6</Sha> </Dependency> - <Dependency Name="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.0-preview.6.22322.3"> + <Dependency Name="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.0-preview.6.22323.4"> <Uri>https://github.com/dotnet/efcore</Uri> - <Sha>5618bc6a0aa2e0dfed57c0f3cd64830733e7c924</Sha> + <Sha>380454af37a6c779763f2bd95360c0797ce980b6</Sha> </Dependency> - <Dependency Name="Microsoft.EntityFrameworkCore.Tools" Version="7.0.0-preview.6.22322.3"> + <Dependency Name="Microsoft.EntityFrameworkCore.Tools" Version="7.0.0-preview.6.22323.4"> <Uri>https://github.com/dotnet/efcore</Uri> - <Sha>5618bc6a0aa2e0dfed57c0f3cd64830733e7c924</Sha> + <Sha>380454af37a6c779763f2bd95360c0797ce980b6</Sha> </Dependency> - <Dependency Name="Microsoft.EntityFrameworkCore" Version="7.0.0-preview.6.22322.3"> + <Dependency Name="Microsoft.EntityFrameworkCore" Version="7.0.0-preview.6.22323.4"> <Uri>https://github.com/dotnet/efcore</Uri> - <Sha>5618bc6a0aa2e0dfed57c0f3cd64830733e7c924</Sha> + <Sha>380454af37a6c779763f2bd95360c0797ce980b6</Sha> </Dependency> - <Dependency Name="Microsoft.EntityFrameworkCore.Design" Version="7.0.0-preview.6.22322.3"> + <Dependency Name="Microsoft.EntityFrameworkCore.Design" Version="7.0.0-preview.6.22323.4"> <Uri>https://github.com/dotnet/efcore</Uri> - <Sha>5618bc6a0aa2e0dfed57c0f3cd64830733e7c924</Sha> + <Sha>380454af37a6c779763f2bd95360c0797ce980b6</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Caching.Abstractions" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="Microsoft.Extensions.Caching.Abstractions" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Caching.Memory" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="Microsoft.Extensions.Caching.Memory" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Configuration.Abstractions" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="Microsoft.Extensions.Configuration.Abstractions" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Configuration.Binder" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="Microsoft.Extensions.Configuration.Binder" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Configuration.CommandLine" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="Microsoft.Extensions.Configuration.CommandLine" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Configuration.FileExtensions" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="Microsoft.Extensions.Configuration.FileExtensions" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Configuration.Ini" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="Microsoft.Extensions.Configuration.Ini" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Configuration.Json" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="Microsoft.Extensions.Configuration.Json" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Configuration.UserSecrets" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="Microsoft.Extensions.Configuration.UserSecrets" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Configuration.Xml" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="Microsoft.Extensions.Configuration.Xml" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Configuration" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="Microsoft.Extensions.Configuration" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.DependencyInjection" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="Microsoft.Extensions.DependencyInjection" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.FileProviders.Abstractions" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="Microsoft.Extensions.FileProviders.Abstractions" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.FileProviders.Composite" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="Microsoft.Extensions.FileProviders.Composite" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.FileProviders.Physical" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="Microsoft.Extensions.FileProviders.Physical" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.FileSystemGlobbing" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="Microsoft.Extensions.FileSystemGlobbing" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.HostFactoryResolver.Sources" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="Microsoft.Extensions.HostFactoryResolver.Sources" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Hosting.Abstractions" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="Microsoft.Extensions.Hosting.Abstractions" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Hosting" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="Microsoft.Extensions.Hosting" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Http" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="Microsoft.Extensions.Http" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Logging.Abstractions" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="Microsoft.Extensions.Logging.Abstractions" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Logging.Configuration" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="Microsoft.Extensions.Logging.Configuration" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Logging.Console" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="Microsoft.Extensions.Logging.Console" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Logging.Debug" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="Microsoft.Extensions.Logging.Debug" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Logging.EventSource" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="Microsoft.Extensions.Logging.EventSource" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Logging.EventLog" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="Microsoft.Extensions.Logging.EventLog" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Logging.TraceSource" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="Microsoft.Extensions.Logging.TraceSource" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Logging" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="Microsoft.Extensions.Logging" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Options.ConfigurationExtensions" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="Microsoft.Extensions.Options.ConfigurationExtensions" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Options.DataAnnotations" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="Microsoft.Extensions.Options.DataAnnotations" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Options" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="Microsoft.Extensions.Options" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Primitives" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="Microsoft.Extensions.Primitives" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="Microsoft.Internal.Runtime.AspNetCore.Transport" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="Microsoft.Internal.Runtime.AspNetCore.Transport" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="System.Configuration.ConfigurationManager" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="System.Configuration.ConfigurationManager" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="System.Diagnostics.DiagnosticSource" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="System.Diagnostics.DiagnosticSource" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="System.Diagnostics.EventLog" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="System.Diagnostics.EventLog" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="System.DirectoryServices.Protocols" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="System.DirectoryServices.Protocols" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="System.IO.Pipelines" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="System.IO.Pipelines" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="System.Net.Http.Json" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="System.Net.Http.Json" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="System.Net.Http.WinHttpHandler" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="System.Net.Http.WinHttpHandler" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="System.Reflection.Metadata" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="System.Reflection.Metadata" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="System.Resources.Extensions" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="System.Resources.Extensions" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="System.Security.Cryptography.Pkcs" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="System.Security.Cryptography.Pkcs" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="System.Security.Cryptography.Xml" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="System.Security.Cryptography.Xml" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="System.Security.Permissions" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="System.Security.Permissions" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="System.ServiceProcess.ServiceController" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="System.ServiceProcess.ServiceController" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="System.Text.Encodings.Web" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="System.Text.Encodings.Web" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="System.Text.Json" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="System.Text.Json" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="System.Threading.AccessControl" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="System.Threading.AccessControl" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="System.Threading.Channels" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="System.Threading.Channels" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="System.Threading.RateLimiting" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="System.Threading.RateLimiting" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.DependencyModel" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="Microsoft.Extensions.DependencyModel" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="Microsoft.NETCore.App.Ref" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="Microsoft.NETCore.App.Ref" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="Microsoft.NET.Runtime.MonoAOTCompiler.Task" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="Microsoft.NET.Runtime.MonoAOTCompiler.Task" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="Microsoft.NET.Runtime.WebAssembly.Sdk" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="Microsoft.NET.Runtime.WebAssembly.Sdk" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> <!-- Win-x64 is used here because we have picked an arbitrary runtime identifier to flow the version of the latest NETCore.App runtime. All Runtime.$rid packages should have the same version. --> - <Dependency Name="Microsoft.NETCore.App.Runtime.win-x64" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="Microsoft.NETCore.App.Runtime.win-x64" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="Microsoft.NETCore.App.Runtime.AOT.win-x64.Cross.browser-wasm" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="Microsoft.NETCore.App.Runtime.AOT.win-x64.Cross.browser-wasm" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> - <Dependency Name="Microsoft.NETCore.BrowserDebugHost.Transport" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="Microsoft.NETCore.BrowserDebugHost.Transport" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> </ProductDependencies> <ToolsetDependencies> <!-- Listed explicitly to workaround https://github.com/dotnet/cli/issues/10528 --> - <Dependency Name="Microsoft.NETCore.Platforms" Version="7.0.0-preview.6.22321.8"> + <Dependency Name="Microsoft.NETCore.Platforms" Version="7.0.0-preview.6.22323.6"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>fdc3b51da075066a5da489be2c169be85dbc117f</Sha> + <Sha>e45c708c41a9fdec2545b2ae517739a122f7b66b</Sha> </Dependency> <Dependency Name="Microsoft.DotNet.Arcade.Sdk" Version="7.0.0-beta.22316.2"> <Uri>https://github.com/dotnet/arcade</Uri> diff --git a/eng/Versions.props b/eng/Versions.props index 995788c456..b70a0ee979 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -50,6 +50,8 @@ <UsingToolNetFrameworkReferenceAssemblies Condition="'$(OS)' != 'Windows_NT'">true</UsingToolNetFrameworkReferenceAssemblies> <!-- Disable XLIFF tasks --> <UsingToolXliff>false</UsingToolXliff> + <!-- Use custom version of Roslyn Compiler --> + <UsingToolMicrosoftNetCompilers>true</UsingToolMicrosoftNetCompilers> </PropertyGroup> <!-- @@ -63,77 +65,77 @@ --> <PropertyGroup Label="Automated"> <!-- Packages from dotnet/runtime --> - <MicrosoftExtensionsDependencyModelVersion>7.0.0-preview.6.22321.8</MicrosoftExtensionsDependencyModelVersion> - <MicrosoftNETCoreAppRefVersion>7.0.0-preview.6.22321.8</MicrosoftNETCoreAppRefVersion> - <MicrosoftNETCoreAppRuntimewinx64Version>7.0.0-preview.6.22321.8</MicrosoftNETCoreAppRuntimewinx64Version> - <MicrosoftNETRuntimeMonoAOTCompilerTaskVersion>7.0.0-preview.6.22321.8</MicrosoftNETRuntimeMonoAOTCompilerTaskVersion> - <MicrosoftNETRuntimeWebAssemblySdkVersion>7.0.0-preview.6.22321.8</MicrosoftNETRuntimeWebAssemblySdkVersion> - <MicrosoftNETCoreAppRuntimeAOTwinx64CrossbrowserwasmVersion>7.0.0-preview.6.22321.8</MicrosoftNETCoreAppRuntimeAOTwinx64CrossbrowserwasmVersion> - <MicrosoftNETCoreBrowserDebugHostTransportVersion>7.0.0-preview.6.22321.8</MicrosoftNETCoreBrowserDebugHostTransportVersion> - <MicrosoftExtensionsCachingAbstractionsVersion>7.0.0-preview.6.22321.8</MicrosoftExtensionsCachingAbstractionsVersion> - <MicrosoftExtensionsCachingMemoryVersion>7.0.0-preview.6.22321.8</MicrosoftExtensionsCachingMemoryVersion> - <MicrosoftExtensionsConfigurationAbstractionsVersion>7.0.0-preview.6.22321.8</MicrosoftExtensionsConfigurationAbstractionsVersion> - <MicrosoftExtensionsConfigurationBinderVersion>7.0.0-preview.6.22321.8</MicrosoftExtensionsConfigurationBinderVersion> - <MicrosoftExtensionsConfigurationCommandLineVersion>7.0.0-preview.6.22321.8</MicrosoftExtensionsConfigurationCommandLineVersion> - <MicrosoftExtensionsConfigurationEnvironmentVariablesVersion>7.0.0-preview.6.22321.8</MicrosoftExtensionsConfigurationEnvironmentVariablesVersion> - <MicrosoftExtensionsConfigurationFileExtensionsVersion>7.0.0-preview.6.22321.8</MicrosoftExtensionsConfigurationFileExtensionsVersion> - <MicrosoftExtensionsConfigurationIniVersion>7.0.0-preview.6.22321.8</MicrosoftExtensionsConfigurationIniVersion> - <MicrosoftExtensionsConfigurationJsonVersion>7.0.0-preview.6.22321.8</MicrosoftExtensionsConfigurationJsonVersion> - <MicrosoftExtensionsConfigurationVersion>7.0.0-preview.6.22321.8</MicrosoftExtensionsConfigurationVersion> - <MicrosoftExtensionsConfigurationUserSecretsVersion>7.0.0-preview.6.22321.8</MicrosoftExtensionsConfigurationUserSecretsVersion> - <MicrosoftExtensionsConfigurationXmlVersion>7.0.0-preview.6.22321.8</MicrosoftExtensionsConfigurationXmlVersion> - <MicrosoftExtensionsDependencyInjectionAbstractionsVersion>7.0.0-preview.6.22321.8</MicrosoftExtensionsDependencyInjectionAbstractionsVersion> - <MicrosoftExtensionsDependencyInjectionVersion>7.0.0-preview.6.22321.8</MicrosoftExtensionsDependencyInjectionVersion> - <MicrosoftExtensionsFileProvidersAbstractionsVersion>7.0.0-preview.6.22321.8</MicrosoftExtensionsFileProvidersAbstractionsVersion> - <MicrosoftExtensionsFileProvidersCompositeVersion>7.0.0-preview.6.22321.8</MicrosoftExtensionsFileProvidersCompositeVersion> - <MicrosoftExtensionsFileProvidersPhysicalVersion>7.0.0-preview.6.22321.8</MicrosoftExtensionsFileProvidersPhysicalVersion> - <MicrosoftExtensionsFileSystemGlobbingVersion>7.0.0-preview.6.22321.8</MicrosoftExtensionsFileSystemGlobbingVersion> - <MicrosoftExtensionsHostFactoryResolverSourcesVersion>7.0.0-preview.6.22321.8</MicrosoftExtensionsHostFactoryResolverSourcesVersion> - <MicrosoftExtensionsHostingAbstractionsVersion>7.0.0-preview.6.22321.8</MicrosoftExtensionsHostingAbstractionsVersion> - <MicrosoftExtensionsHostingVersion>7.0.0-preview.6.22321.8</MicrosoftExtensionsHostingVersion> - <MicrosoftExtensionsHttpVersion>7.0.0-preview.6.22321.8</MicrosoftExtensionsHttpVersion> - <MicrosoftExtensionsLoggingAbstractionsVersion>7.0.0-preview.6.22321.8</MicrosoftExtensionsLoggingAbstractionsVersion> - <MicrosoftExtensionsLoggingConfigurationVersion>7.0.0-preview.6.22321.8</MicrosoftExtensionsLoggingConfigurationVersion> - <MicrosoftExtensionsLoggingConsoleVersion>7.0.0-preview.6.22321.8</MicrosoftExtensionsLoggingConsoleVersion> - <MicrosoftExtensionsLoggingDebugVersion>7.0.0-preview.6.22321.8</MicrosoftExtensionsLoggingDebugVersion> - <MicrosoftExtensionsLoggingEventSourceVersion>7.0.0-preview.6.22321.8</MicrosoftExtensionsLoggingEventSourceVersion> - <MicrosoftExtensionsLoggingEventLogVersion>7.0.0-preview.6.22321.8</MicrosoftExtensionsLoggingEventLogVersion> - <MicrosoftExtensionsLoggingVersion>7.0.0-preview.6.22321.8</MicrosoftExtensionsLoggingVersion> - <MicrosoftExtensionsLoggingTraceSourceVersion>7.0.0-preview.6.22321.8</MicrosoftExtensionsLoggingTraceSourceVersion> - <MicrosoftExtensionsOptionsConfigurationExtensionsVersion>7.0.0-preview.6.22321.8</MicrosoftExtensionsOptionsConfigurationExtensionsVersion> - <MicrosoftExtensionsOptionsDataAnnotationsVersion>7.0.0-preview.6.22321.8</MicrosoftExtensionsOptionsDataAnnotationsVersion> - <MicrosoftExtensionsOptionsVersion>7.0.0-preview.6.22321.8</MicrosoftExtensionsOptionsVersion> - <MicrosoftExtensionsPrimitivesVersion>7.0.0-preview.6.22321.8</MicrosoftExtensionsPrimitivesVersion> - <MicrosoftInternalRuntimeAspNetCoreTransportVersion>7.0.0-preview.6.22321.8</MicrosoftInternalRuntimeAspNetCoreTransportVersion> - <SystemConfigurationConfigurationManagerVersion>7.0.0-preview.6.22321.8</SystemConfigurationConfigurationManagerVersion> - <SystemDiagnosticsDiagnosticSourceVersion>7.0.0-preview.6.22321.8</SystemDiagnosticsDiagnosticSourceVersion> - <SystemDiagnosticsEventLogVersion>7.0.0-preview.6.22321.8</SystemDiagnosticsEventLogVersion> - <SystemDirectoryServicesProtocolsVersion>7.0.0-preview.6.22321.8</SystemDirectoryServicesProtocolsVersion> - <SystemIOPipelinesVersion>7.0.0-preview.6.22321.8</SystemIOPipelinesVersion> - <SystemNetHttpJsonVersion>7.0.0-preview.6.22321.8</SystemNetHttpJsonVersion> - <SystemNetHttpWinHttpHandlerVersion>7.0.0-preview.6.22321.8</SystemNetHttpWinHttpHandlerVersion> - <SystemReflectionMetadataVersion>7.0.0-preview.6.22321.8</SystemReflectionMetadataVersion> - <SystemResourcesExtensionsVersion>7.0.0-preview.6.22321.8</SystemResourcesExtensionsVersion> - <SystemSecurityCryptographyPkcsVersion>7.0.0-preview.6.22321.8</SystemSecurityCryptographyPkcsVersion> - <SystemSecurityCryptographyXmlVersion>7.0.0-preview.6.22321.8</SystemSecurityCryptographyXmlVersion> - <SystemSecurityPermissionsVersion>7.0.0-preview.6.22321.8</SystemSecurityPermissionsVersion> - <SystemServiceProcessServiceControllerVersion>7.0.0-preview.6.22321.8</SystemServiceProcessServiceControllerVersion> - <SystemTextEncodingsWebVersion>7.0.0-preview.6.22321.8</SystemTextEncodingsWebVersion> - <SystemTextJsonVersion>7.0.0-preview.6.22321.8</SystemTextJsonVersion> - <SystemThreadingAccessControlVersion>7.0.0-preview.6.22321.8</SystemThreadingAccessControlVersion> - <SystemThreadingChannelsVersion>7.0.0-preview.6.22321.8</SystemThreadingChannelsVersion> - <SystemThreadingRateLimitingVersion>7.0.0-preview.6.22321.8</SystemThreadingRateLimitingVersion> + <MicrosoftExtensionsDependencyModelVersion>7.0.0-preview.6.22323.6</MicrosoftExtensionsDependencyModelVersion> + <MicrosoftNETCoreAppRefVersion>7.0.0-preview.6.22323.6</MicrosoftNETCoreAppRefVersion> + <MicrosoftNETCoreAppRuntimewinx64Version>7.0.0-preview.6.22323.6</MicrosoftNETCoreAppRuntimewinx64Version> + <MicrosoftNETRuntimeMonoAOTCompilerTaskVersion>7.0.0-preview.6.22323.6</MicrosoftNETRuntimeMonoAOTCompilerTaskVersion> + <MicrosoftNETRuntimeWebAssemblySdkVersion>7.0.0-preview.6.22323.6</MicrosoftNETRuntimeWebAssemblySdkVersion> + <MicrosoftNETCoreAppRuntimeAOTwinx64CrossbrowserwasmVersion>7.0.0-preview.6.22323.6</MicrosoftNETCoreAppRuntimeAOTwinx64CrossbrowserwasmVersion> + <MicrosoftNETCoreBrowserDebugHostTransportVersion>7.0.0-preview.6.22323.6</MicrosoftNETCoreBrowserDebugHostTransportVersion> + <MicrosoftExtensionsCachingAbstractionsVersion>7.0.0-preview.6.22323.6</MicrosoftExtensionsCachingAbstractionsVersion> + <MicrosoftExtensionsCachingMemoryVersion>7.0.0-preview.6.22323.6</MicrosoftExtensionsCachingMemoryVersion> + <MicrosoftExtensionsConfigurationAbstractionsVersion>7.0.0-preview.6.22323.6</MicrosoftExtensionsConfigurationAbstractionsVersion> + <MicrosoftExtensionsConfigurationBinderVersion>7.0.0-preview.6.22323.6</MicrosoftExtensionsConfigurationBinderVersion> + <MicrosoftExtensionsConfigurationCommandLineVersion>7.0.0-preview.6.22323.6</MicrosoftExtensionsConfigurationCommandLineVersion> + <MicrosoftExtensionsConfigurationEnvironmentVariablesVersion>7.0.0-preview.6.22323.6</MicrosoftExtensionsConfigurationEnvironmentVariablesVersion> + <MicrosoftExtensionsConfigurationFileExtensionsVersion>7.0.0-preview.6.22323.6</MicrosoftExtensionsConfigurationFileExtensionsVersion> + <MicrosoftExtensionsConfigurationIniVersion>7.0.0-preview.6.22323.6</MicrosoftExtensionsConfigurationIniVersion> + <MicrosoftExtensionsConfigurationJsonVersion>7.0.0-preview.6.22323.6</MicrosoftExtensionsConfigurationJsonVersion> + <MicrosoftExtensionsConfigurationVersion>7.0.0-preview.6.22323.6</MicrosoftExtensionsConfigurationVersion> + <MicrosoftExtensionsConfigurationUserSecretsVersion>7.0.0-preview.6.22323.6</MicrosoftExtensionsConfigurationUserSecretsVersion> + <MicrosoftExtensionsConfigurationXmlVersion>7.0.0-preview.6.22323.6</MicrosoftExtensionsConfigurationXmlVersion> + <MicrosoftExtensionsDependencyInjectionAbstractionsVersion>7.0.0-preview.6.22323.6</MicrosoftExtensionsDependencyInjectionAbstractionsVersion> + <MicrosoftExtensionsDependencyInjectionVersion>7.0.0-preview.6.22323.6</MicrosoftExtensionsDependencyInjectionVersion> + <MicrosoftExtensionsFileProvidersAbstractionsVersion>7.0.0-preview.6.22323.6</MicrosoftExtensionsFileProvidersAbstractionsVersion> + <MicrosoftExtensionsFileProvidersCompositeVersion>7.0.0-preview.6.22323.6</MicrosoftExtensionsFileProvidersCompositeVersion> + <MicrosoftExtensionsFileProvidersPhysicalVersion>7.0.0-preview.6.22323.6</MicrosoftExtensionsFileProvidersPhysicalVersion> + <MicrosoftExtensionsFileSystemGlobbingVersion>7.0.0-preview.6.22323.6</MicrosoftExtensionsFileSystemGlobbingVersion> + <MicrosoftExtensionsHostFactoryResolverSourcesVersion>7.0.0-preview.6.22323.6</MicrosoftExtensionsHostFactoryResolverSourcesVersion> + <MicrosoftExtensionsHostingAbstractionsVersion>7.0.0-preview.6.22323.6</MicrosoftExtensionsHostingAbstractionsVersion> + <MicrosoftExtensionsHostingVersion>7.0.0-preview.6.22323.6</MicrosoftExtensionsHostingVersion> + <MicrosoftExtensionsHttpVersion>7.0.0-preview.6.22323.6</MicrosoftExtensionsHttpVersion> + <MicrosoftExtensionsLoggingAbstractionsVersion>7.0.0-preview.6.22323.6</MicrosoftExtensionsLoggingAbstractionsVersion> + <MicrosoftExtensionsLoggingConfigurationVersion>7.0.0-preview.6.22323.6</MicrosoftExtensionsLoggingConfigurationVersion> + <MicrosoftExtensionsLoggingConsoleVersion>7.0.0-preview.6.22323.6</MicrosoftExtensionsLoggingConsoleVersion> + <MicrosoftExtensionsLoggingDebugVersion>7.0.0-preview.6.22323.6</MicrosoftExtensionsLoggingDebugVersion> + <MicrosoftExtensionsLoggingEventSourceVersion>7.0.0-preview.6.22323.6</MicrosoftExtensionsLoggingEventSourceVersion> + <MicrosoftExtensionsLoggingEventLogVersion>7.0.0-preview.6.22323.6</MicrosoftExtensionsLoggingEventLogVersion> + <MicrosoftExtensionsLoggingVersion>7.0.0-preview.6.22323.6</MicrosoftExtensionsLoggingVersion> + <MicrosoftExtensionsLoggingTraceSourceVersion>7.0.0-preview.6.22323.6</MicrosoftExtensionsLoggingTraceSourceVersion> + <MicrosoftExtensionsOptionsConfigurationExtensionsVersion>7.0.0-preview.6.22323.6</MicrosoftExtensionsOptionsConfigurationExtensionsVersion> + <MicrosoftExtensionsOptionsDataAnnotationsVersion>7.0.0-preview.6.22323.6</MicrosoftExtensionsOptionsDataAnnotationsVersion> + <MicrosoftExtensionsOptionsVersion>7.0.0-preview.6.22323.6</MicrosoftExtensionsOptionsVersion> + <MicrosoftExtensionsPrimitivesVersion>7.0.0-preview.6.22323.6</MicrosoftExtensionsPrimitivesVersion> + <MicrosoftInternalRuntimeAspNetCoreTransportVersion>7.0.0-preview.6.22323.6</MicrosoftInternalRuntimeAspNetCoreTransportVersion> + <SystemConfigurationConfigurationManagerVersion>7.0.0-preview.6.22323.6</SystemConfigurationConfigurationManagerVersion> + <SystemDiagnosticsDiagnosticSourceVersion>7.0.0-preview.6.22323.6</SystemDiagnosticsDiagnosticSourceVersion> + <SystemDiagnosticsEventLogVersion>7.0.0-preview.6.22323.6</SystemDiagnosticsEventLogVersion> + <SystemDirectoryServicesProtocolsVersion>7.0.0-preview.6.22323.6</SystemDirectoryServicesProtocolsVersion> + <SystemIOPipelinesVersion>7.0.0-preview.6.22323.6</SystemIOPipelinesVersion> + <SystemNetHttpJsonVersion>7.0.0-preview.6.22323.6</SystemNetHttpJsonVersion> + <SystemNetHttpWinHttpHandlerVersion>7.0.0-preview.6.22323.6</SystemNetHttpWinHttpHandlerVersion> + <SystemReflectionMetadataVersion>7.0.0-preview.6.22323.6</SystemReflectionMetadataVersion> + <SystemResourcesExtensionsVersion>7.0.0-preview.6.22323.6</SystemResourcesExtensionsVersion> + <SystemSecurityCryptographyPkcsVersion>7.0.0-preview.6.22323.6</SystemSecurityCryptographyPkcsVersion> + <SystemSecurityCryptographyXmlVersion>7.0.0-preview.6.22323.6</SystemSecurityCryptographyXmlVersion> + <SystemSecurityPermissionsVersion>7.0.0-preview.6.22323.6</SystemSecurityPermissionsVersion> + <SystemServiceProcessServiceControllerVersion>7.0.0-preview.6.22323.6</SystemServiceProcessServiceControllerVersion> + <SystemTextEncodingsWebVersion>7.0.0-preview.6.22323.6</SystemTextEncodingsWebVersion> + <SystemTextJsonVersion>7.0.0-preview.6.22323.6</SystemTextJsonVersion> + <SystemThreadingAccessControlVersion>7.0.0-preview.6.22323.6</SystemThreadingAccessControlVersion> + <SystemThreadingChannelsVersion>7.0.0-preview.6.22323.6</SystemThreadingChannelsVersion> + <SystemThreadingRateLimitingVersion>7.0.0-preview.6.22323.6</SystemThreadingRateLimitingVersion> <!-- Only listed explicitly to workaround https://github.com/dotnet/cli/issues/10528 --> - <MicrosoftNETCorePlatformsVersion>7.0.0-preview.6.22321.8</MicrosoftNETCorePlatformsVersion> + <MicrosoftNETCorePlatformsVersion>7.0.0-preview.6.22323.6</MicrosoftNETCorePlatformsVersion> <!-- Packages from dotnet/efcore --> - <dotnetefVersion>7.0.0-preview.6.22322.3</dotnetefVersion> - <MicrosoftEntityFrameworkCoreInMemoryVersion>7.0.0-preview.6.22322.3</MicrosoftEntityFrameworkCoreInMemoryVersion> - <MicrosoftEntityFrameworkCoreRelationalVersion>7.0.0-preview.6.22322.3</MicrosoftEntityFrameworkCoreRelationalVersion> - <MicrosoftEntityFrameworkCoreSqliteVersion>7.0.0-preview.6.22322.3</MicrosoftEntityFrameworkCoreSqliteVersion> - <MicrosoftEntityFrameworkCoreSqlServerVersion>7.0.0-preview.6.22322.3</MicrosoftEntityFrameworkCoreSqlServerVersion> - <MicrosoftEntityFrameworkCoreToolsVersion>7.0.0-preview.6.22322.3</MicrosoftEntityFrameworkCoreToolsVersion> - <MicrosoftEntityFrameworkCoreVersion>7.0.0-preview.6.22322.3</MicrosoftEntityFrameworkCoreVersion> - <MicrosoftEntityFrameworkCoreDesignVersion>7.0.0-preview.6.22322.3</MicrosoftEntityFrameworkCoreDesignVersion> + <dotnetefVersion>7.0.0-preview.6.22323.4</dotnetefVersion> + <MicrosoftEntityFrameworkCoreInMemoryVersion>7.0.0-preview.6.22323.4</MicrosoftEntityFrameworkCoreInMemoryVersion> + <MicrosoftEntityFrameworkCoreRelationalVersion>7.0.0-preview.6.22323.4</MicrosoftEntityFrameworkCoreRelationalVersion> + <MicrosoftEntityFrameworkCoreSqliteVersion>7.0.0-preview.6.22323.4</MicrosoftEntityFrameworkCoreSqliteVersion> + <MicrosoftEntityFrameworkCoreSqlServerVersion>7.0.0-preview.6.22323.4</MicrosoftEntityFrameworkCoreSqlServerVersion> + <MicrosoftEntityFrameworkCoreToolsVersion>7.0.0-preview.6.22323.4</MicrosoftEntityFrameworkCoreToolsVersion> + <MicrosoftEntityFrameworkCoreVersion>7.0.0-preview.6.22323.4</MicrosoftEntityFrameworkCoreVersion> + <MicrosoftEntityFrameworkCoreDesignVersion>7.0.0-preview.6.22323.4</MicrosoftEntityFrameworkCoreDesignVersion> <!-- Packages from dotnet/arcade --> <MicrosoftDotNetBuildTasksInstallersVersion>7.0.0-beta.22316.2</MicrosoftDotNetBuildTasksInstallersVersion> <MicrosoftDotNetBuildTasksTemplatingVersion>7.0.0-beta.22316.2</MicrosoftDotNetBuildTasksTemplatingVersion> @@ -195,6 +197,10 @@ --> <MicrosoftNETTestSdkVersion>17.1.0-preview-20211109-03</MicrosoftNETTestSdkVersion> <!-- + Use a compiler new enough to use required keyword + --> + <MicrosoftNetCompilersToolsetVersion>4.4.0-1.22315.13</MicrosoftNetCompilersToolsetVersion> + <!-- Versions of Microsoft.CodeAnalysis packages referenced by analyzers shipped in the SDK. This need to be pinned since they're used in 3.1 apps and need to be loadable in VS 2019. --> diff --git a/src/Middleware/OutputCaching/test/MemoryOutputCacheStoreTests.cs b/src/Middleware/OutputCaching/test/MemoryOutputCacheStoreTests.cs index 1b1158c662..c3a8d48388 100644 --- a/src/Middleware/OutputCaching/test/MemoryOutputCacheStoreTests.cs +++ b/src/Middleware/OutputCaching/test/MemoryOutputCacheStoreTests.cs @@ -16,7 +16,7 @@ public class MemoryOutputCacheStoreTests public async Task StoreAndGetValue_Succeeds() { var store = new MemoryOutputCacheStore(new MemoryCache(new MemoryCacheOptions())); - var value = "abc"u8; + var value = "abc"u8.ToArray(); var key = "abc"; await store.SetAsync(key, value, null, TimeSpan.FromMinutes(1), default); @@ -31,7 +31,7 @@ public class MemoryOutputCacheStoreTests { var testClock = new TestMemoryOptionsClock { UtcNow = DateTimeOffset.UtcNow }; var store = new MemoryOutputCacheStore(new MemoryCache(new MemoryCacheOptions { Clock = testClock })); - var value = "abc"u8; + var value = "abc"u8.ToArray(); var key = "abc"; await store.SetAsync(key, value, null, TimeSpan.FromMilliseconds(5), default); @@ -46,7 +46,7 @@ public class MemoryOutputCacheStoreTests public async Task StoreNullKey_ThrowsException() { var store = new MemoryOutputCacheStore(new MemoryCache(new MemoryCacheOptions())); - var value = "abc"u8; + var value = "abc"u8.ToArray(); string key = null; _ = await Assert.ThrowsAsync<ArgumentNullException>("key", () => store.SetAsync(key, value, null, TimeSpan.FromMilliseconds(5), default).AsTask()); @@ -67,7 +67,7 @@ public class MemoryOutputCacheStoreTests { var testClock = new TestMemoryOptionsClock { UtcNow = DateTimeOffset.UtcNow }; var store = new MemoryOutputCacheStore(new MemoryCache(new MemoryCacheOptions { Clock = testClock })); - var value = "abc"u8; + var value = "abc"u8.ToArray(); var key = "abc"; var tags = new string[] { "tag1" }; @@ -83,7 +83,7 @@ public class MemoryOutputCacheStoreTests { var testClock = new TestMemoryOptionsClock { UtcNow = DateTimeOffset.UtcNow }; var store = new MemoryOutputCacheStore(new MemoryCache(new MemoryCacheOptions { Clock = testClock })); - var value = "abc"u8; + var value = "abc"u8.ToArray(); var key1 = "abc"; var key2 = "def"; var tags = new string[] { "tag1" }; @@ -103,7 +103,7 @@ public class MemoryOutputCacheStoreTests { var testClock = new TestMemoryOptionsClock { UtcNow = DateTimeOffset.UtcNow }; var store = new MemoryOutputCacheStore(new MemoryCache(new MemoryCacheOptions { Clock = testClock })); - var value = "abc"u8; + var value = "abc"u8.ToArray(); var key = "abc"; var tags = new string[] { "tag1", "tag2" }; @@ -119,7 +119,7 @@ public class MemoryOutputCacheStoreTests { var testClock = new TestMemoryOptionsClock { UtcNow = DateTimeOffset.UtcNow }; var store = new MemoryOutputCacheStore(new MemoryCache(new MemoryCacheOptions { Clock = testClock })); - var value = "abc"u8; + var value = "abc"u8.ToArray(); var key1 = "abc"; var key2 = "def"; var tags1 = new string[] { "tag1", "tag2" }; diff --git a/src/Middleware/OutputCaching/test/OutputCacheEntryFormatterTests.cs b/src/Middleware/OutputCaching/test/OutputCacheEntryFormatterTests.cs index e6610141b2..a0de533fc0 100644 --- a/src/Middleware/OutputCaching/test/OutputCacheEntryFormatterTests.cs +++ b/src/Middleware/OutputCaching/test/OutputCacheEntryFormatterTests.cs @@ -38,7 +38,7 @@ public class OutputCacheEntryFormatterTests var key = "abc"; var entry = new OutputCacheEntry() { - Body = new CachedResponseBody(new List<byte[]>() { "lorem"u8, "ipsum"u8 }, 10), + Body = new CachedResponseBody(new List<byte[]>() { "lorem"u8.ToArray(), "ipsum"u8.ToArray() }, 10), Created = DateTimeOffset.UtcNow, Headers = new HeaderDictionary { [HeaderNames.Accept] = "text/plain", [HeaderNames.AcceptCharset] = "utf8" }, StatusCode = StatusCodes.Status201Created, diff --git a/src/Middleware/RateLimiting/src/DefaultCombinedLease.cs b/src/Middleware/RateLimiting/src/DefaultCombinedLease.cs new file mode 100644 index 0000000000..3fb05bae64 --- /dev/null +++ b/src/Middleware/RateLimiting/src/DefaultCombinedLease.cs @@ -0,0 +1,98 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Threading.RateLimiting; + +namespace Microsoft.AspNetCore.RateLimiting; + +internal sealed class DefaultCombinedLease : RateLimitLease +{ + private readonly RateLimitLease? _globalLease; + private readonly RateLimitLease _endpointLease; + private HashSet<string>? _metadataNames; + + public DefaultCombinedLease(RateLimitLease? globalLease, RateLimitLease endpointLease) + { + _globalLease = globalLease; + _endpointLease = endpointLease; + } + + public override bool IsAcquired => true; + + public override IEnumerable<string> MetadataNames + { + get + { + if (_metadataNames is null) + { + _metadataNames = new HashSet<string>(); + if (_globalLease is not null) + { + foreach (string metadataName in _globalLease.MetadataNames) + { + _metadataNames.Add(metadataName); + } + } + foreach (string metadataName in _endpointLease.MetadataNames) + { + _metadataNames.Add(metadataName); + } + } + return _metadataNames; + } + } + + public override bool TryGetMetadata(string metadataName, out object? metadata) + { + // Use the first metadata item of a given name, ignore duplicates, we can't reliably merge arbitrary metadata + // Creating an object[] if there are multiple of the same metadataName could work, but makes consumption of metadata messy + // and makes MetadataName.Create<T>(...) uses no longer work + if (_endpointLease.TryGetMetadata(metadataName, out metadata)) + { + return true; + } + if (_globalLease is not null) + { + if (_globalLease.TryGetMetadata(metadataName, out metadata)) + { + return true; + } + } + + metadata = null; + return false; + } + + protected override void Dispose(bool disposing) + { + List<Exception>? exceptions = null; + + // Dispose endpoint lease first, then global lease (reverse order of when they were acquired) + // Avoids issues where dispose might unblock a queued acquire and then the acquire fails when acquiring the next limiter. + // When disposing in reverse order there wont be any issues of unblocking an acquire that affects acquires on limiters in the chain after it + try + { + _endpointLease.Dispose(); + } + catch (Exception ex) + { + exceptions ??= new List<Exception>(); + exceptions.Add(ex); + } + + try + { + _globalLease?.Dispose(); + } + catch (Exception ex) + { + exceptions ??= new List<Exception>(); + exceptions.Add(ex); + } + + if (exceptions is not null) + { + throw new AggregateException(exceptions); + } + } +} diff --git a/src/Middleware/RateLimiting/src/DefaultKeyType.T.cs b/src/Middleware/RateLimiting/src/DefaultKeyType.T.cs new file mode 100644 index 0000000000..1718794021 --- /dev/null +++ b/src/Middleware/RateLimiting/src/DefaultKeyType.T.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.AspNetCore.RateLimiting; + +internal sealed class DefaultKeyType<TKey>: DefaultKeyType +{ + private readonly TKey _key; + + public DefaultKeyType(TKey key) + { + _key = key; + } + + public override object? GetKey() + { + return _key; + } +} diff --git a/src/Middleware/RateLimiting/src/DefaultKeyType.cs b/src/Middleware/RateLimiting/src/DefaultKeyType.cs new file mode 100644 index 0000000000..6ca39099c9 --- /dev/null +++ b/src/Middleware/RateLimiting/src/DefaultKeyType.cs @@ -0,0 +1,9 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.AspNetCore.RateLimiting; + +internal abstract class DefaultKeyType +{ + public abstract object? GetKey(); +} diff --git a/src/Middleware/RateLimiting/src/DefaultKeyTypeEqualityComparer.cs b/src/Middleware/RateLimiting/src/DefaultKeyTypeEqualityComparer.cs new file mode 100644 index 0000000000..c2e63f4700 --- /dev/null +++ b/src/Middleware/RateLimiting/src/DefaultKeyTypeEqualityComparer.cs @@ -0,0 +1,44 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics.CodeAnalysis; + +namespace Microsoft.AspNetCore.RateLimiting; +internal class DefaultKeyTypeEqualityComparer : IEqualityComparer<DefaultKeyType> +{ + public bool Equals(DefaultKeyType? x, DefaultKeyType? y) + { + if (x == null && y == null) + { + return true; + } + else if (x == null || y == null) + { + return false; + } + + var xKey = x.GetKey(); + var yKey = y.GetKey(); + if (xKey == null && yKey == null) + { + return true; + } + else if (xKey == null || yKey == null) + { + return false; + } + + return xKey.Equals(yKey); + } + + public int GetHashCode([DisallowNull] DefaultKeyType obj) + { + var key = obj.GetKey(); + if (key is not null) + { + return key.GetHashCode(); + } + // REVIEW - is this reasonable? + return default; + } +} diff --git a/src/Middleware/RateLimiting/src/DefaultRateLimiterPolicy.cs b/src/Middleware/RateLimiting/src/DefaultRateLimiterPolicy.cs new file mode 100644 index 0000000000..7a32df215f --- /dev/null +++ b/src/Middleware/RateLimiting/src/DefaultRateLimiterPolicy.cs @@ -0,0 +1,25 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Threading.RateLimiting; +using Microsoft.AspNetCore.Http; + +namespace Microsoft.AspNetCore.RateLimiting; +internal sealed class DefaultRateLimiterPolicy : IRateLimiterPolicy<DefaultKeyType> +{ + private readonly Func<HttpContext, RateLimitPartition<DefaultKeyType>> _partitioner; + private readonly Func<OnRejectedContext, CancellationToken, ValueTask>? _onRejected; + + public DefaultRateLimiterPolicy(Func<HttpContext, RateLimitPartition<DefaultKeyType>> partitioner, Func<OnRejectedContext, CancellationToken, ValueTask>? onRejected) + { + _partitioner = partitioner; + _onRejected = onRejected; + } + + public Func<OnRejectedContext, CancellationToken, ValueTask>? OnRejected => _onRejected; + + public RateLimitPartition<DefaultKeyType> GetPartition(HttpContext httpContext) + { + return _partitioner(httpContext); + } +} diff --git a/src/Middleware/RateLimiting/src/IRateLimiterMetadata.cs b/src/Middleware/RateLimiting/src/IRateLimiterMetadata.cs new file mode 100644 index 0000000000..6cb096d4ff --- /dev/null +++ b/src/Middleware/RateLimiting/src/IRateLimiterMetadata.cs @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.AspNetCore.RateLimiting; + +/// <summary> +/// An interface which can be used to identify a type which provides metadata needed for enabling request rate limiting support. +/// </summary> +internal interface IRateLimiterMetadata +{ + /// <summary> + /// The name of the limiter which needs to be applied. + /// </summary> + string PolicyName { get; } +} diff --git a/src/Middleware/RateLimiting/src/IRateLimiterPolicy.cs b/src/Middleware/RateLimiting/src/IRateLimiterPolicy.cs new file mode 100644 index 0000000000..7487253858 --- /dev/null +++ b/src/Middleware/RateLimiting/src/IRateLimiterPolicy.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Threading.RateLimiting; +using Microsoft.AspNetCore.Http; + +namespace Microsoft.AspNetCore.RateLimiting; + +/// <summary> +/// An interface which is used to represent a RateLimiter policy. +/// </summary> +public interface IRateLimiterPolicy<TPartitionKey> +{ + /// <summary> + /// Gets the <see cref="Func{OnRejectedContext, CancellationToken, ValueTask}"/> that handles requests rejected by this middleware. + /// </summary> + Func<OnRejectedContext, CancellationToken, ValueTask>? OnRejected { get; } + + /// <summary> + /// Gets the <see cref="RateLimitPartition{TPartitionKey}"/> that applies to the given <see cref="HttpContext"/>. + /// </summary> + /// <param name="httpContext">The <see cref="HttpContext"/> to get the partition for.</param> + RateLimitPartition<TPartitionKey> GetPartition(HttpContext httpContext); +} diff --git a/src/Middleware/RateLimiting/src/LeaseContext.cs b/src/Middleware/RateLimiting/src/LeaseContext.cs new file mode 100644 index 0000000000..5a508b245d --- /dev/null +++ b/src/Middleware/RateLimiting/src/LeaseContext.cs @@ -0,0 +1,17 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Threading.RateLimiting; + +namespace Microsoft.AspNetCore.RateLimiting; +internal struct LeaseContext : IDisposable +{ + public bool? GlobalRejected { get; init; } + + public required RateLimitLease Lease { get; init; } + + public void Dispose() + { + Lease.Dispose(); + } +} diff --git a/src/Middleware/RateLimiting/src/NoLimiter.cs b/src/Middleware/RateLimiting/src/NoLimiter.cs deleted file mode 100644 index e663b1f160..0000000000 --- a/src/Middleware/RateLimiting/src/NoLimiter.cs +++ /dev/null @@ -1,36 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Threading.RateLimiting; - -namespace Microsoft.AspNetCore.RateLimiting; -internal sealed class NoLimiter<TResource> : PartitionedRateLimiter<TResource> -{ - public override int GetAvailablePermits(TResource resourceID) - { - return 1; - } - - protected override RateLimitLease AcquireCore(TResource resourceID, int permitCount) - { - return new NoLimiterLease(); - } - - protected override ValueTask<RateLimitLease> WaitAsyncCore(TResource resourceID, int permitCount, CancellationToken cancellationToken) - { - return new ValueTask<RateLimitLease>(new NoLimiterLease()); - } -} - -internal sealed class NoLimiterLease : RateLimitLease -{ - public override bool IsAcquired => true; - - public override IEnumerable<string> MetadataNames => new List<string>(); - - public override bool TryGetMetadata(string metadataName, out object? metadata) - { - metadata = null; - return false; - } -} diff --git a/src/Middleware/RateLimiting/src/OnRejectedContext.cs b/src/Middleware/RateLimiting/src/OnRejectedContext.cs new file mode 100644 index 0000000000..0570955568 --- /dev/null +++ b/src/Middleware/RateLimiting/src/OnRejectedContext.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Threading.RateLimiting; +using Microsoft.AspNetCore.Http; + +namespace Microsoft.AspNetCore.RateLimiting; + +/// <summary> +/// Holds state needed for the OnRejected callback in the RateLimitingMiddleware. +/// </summary> +public sealed class OnRejectedContext +{ + /// <summary> + /// Gets or sets the <see cref="HttpContext"/> that the OnRejected callback will have access to + /// </summary> + public required HttpContext HttpContext { get; init; } + + /// <summary> + /// Gets or sets the failed <see cref="RateLimitLease"/> that the OnRejected callback will have access to + /// </summary> + public required RateLimitLease Lease { get; init; } +} diff --git a/src/Middleware/RateLimiting/src/PolicyNameKey.cs b/src/Middleware/RateLimiting/src/PolicyNameKey.cs new file mode 100644 index 0000000000..bc34d23129 --- /dev/null +++ b/src/Middleware/RateLimiting/src/PolicyNameKey.cs @@ -0,0 +1,22 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.AspNetCore.RateLimiting; +internal sealed class PolicyNameKey +{ + public required string PolicyName { get; init; } + + public override bool Equals(object? obj) + { + if (obj is PolicyNameKey key) + { + return PolicyName.Equals(key.PolicyName); + } + return false; + } + + public override int GetHashCode() + { + return PolicyName.GetHashCode(); + } +} diff --git a/src/Middleware/RateLimiting/src/PolicyTypeInfo.cs b/src/Middleware/RateLimiting/src/PolicyTypeInfo.cs new file mode 100644 index 0000000000..f71aa1302a --- /dev/null +++ b/src/Middleware/RateLimiting/src/PolicyTypeInfo.cs @@ -0,0 +1,12 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics.CodeAnalysis; + +namespace Microsoft.AspNetCore.RateLimiting; +internal sealed class PolicyTypeInfo +{ + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] + public required Type PolicyType { get; init; } + public required Type PartitionKeyType { get; init; } +} diff --git a/src/Middleware/RateLimiting/src/PublicAPI.Unshipped.txt b/src/Middleware/RateLimiting/src/PublicAPI.Unshipped.txt index b62cec89b1..3bbcc5cb4c 100644 --- a/src/Middleware/RateLimiting/src/PublicAPI.Unshipped.txt +++ b/src/Middleware/RateLimiting/src/PublicAPI.Unshipped.txt @@ -1,11 +1,31 @@ +Microsoft.AspNetCore.Builder.RateLimiterApplicationBuilderExtensions +Microsoft.AspNetCore.Builder.RateLimiterEndpointConventionBuilderExtensions +Microsoft.AspNetCore.RateLimiting.IRateLimiterPolicy<TPartitionKey> +Microsoft.AspNetCore.RateLimiting.IRateLimiterPolicy<TPartitionKey>.GetPartition(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.RateLimiting.RateLimitPartition<TPartitionKey> +Microsoft.AspNetCore.RateLimiting.IRateLimiterPolicy<TPartitionKey>.OnRejected.get -> System.Func<Microsoft.AspNetCore.RateLimiting.OnRejectedContext!, System.Threading.CancellationToken, System.Threading.Tasks.ValueTask>? +Microsoft.AspNetCore.RateLimiting.OnRejectedContext +Microsoft.AspNetCore.RateLimiting.OnRejectedContext.HttpContext.get -> Microsoft.AspNetCore.Http.HttpContext! +Microsoft.AspNetCore.RateLimiting.OnRejectedContext.HttpContext.init -> void +Microsoft.AspNetCore.RateLimiting.OnRejectedContext.Lease.get -> System.Threading.RateLimiting.RateLimitLease! +Microsoft.AspNetCore.RateLimiting.OnRejectedContext.Lease.init -> void +Microsoft.AspNetCore.RateLimiting.OnRejectedContext.OnRejectedContext() -> void Microsoft.AspNetCore.RateLimiting.RateLimiterOptions -Microsoft.AspNetCore.RateLimiting.RateLimiterOptions.DefaultRejectionStatusCode.get -> int -Microsoft.AspNetCore.RateLimiting.RateLimiterOptions.DefaultRejectionStatusCode.set -> void -Microsoft.AspNetCore.RateLimiting.RateLimiterOptions.Limiter.get -> System.Threading.RateLimiting.PartitionedRateLimiter<Microsoft.AspNetCore.Http.HttpContext!>! -Microsoft.AspNetCore.RateLimiting.RateLimiterOptions.Limiter.set -> void -Microsoft.AspNetCore.RateLimiting.RateLimiterOptions.OnRejected.get -> System.Func<Microsoft.AspNetCore.Http.HttpContext!, System.Threading.RateLimiting.RateLimitLease!, System.Threading.Tasks.Task!>! +Microsoft.AspNetCore.RateLimiting.RateLimiterOptions.AddPolicy<TPartitionKey, TPolicy>(string! policyName) -> Microsoft.AspNetCore.RateLimiting.RateLimiterOptions! +Microsoft.AspNetCore.RateLimiting.RateLimiterOptions.AddPolicy<TPartitionKey>(string! policyName, Microsoft.AspNetCore.RateLimiting.IRateLimiterPolicy<TPartitionKey>! policy) -> Microsoft.AspNetCore.RateLimiting.RateLimiterOptions! +Microsoft.AspNetCore.RateLimiting.RateLimiterOptions.AddPolicy<TPartitionKey>(string! policyName, System.Func<Microsoft.AspNetCore.Http.HttpContext!, System.Threading.RateLimiting.RateLimitPartition<TPartitionKey>>! partitioner) -> Microsoft.AspNetCore.RateLimiting.RateLimiterOptions! +Microsoft.AspNetCore.RateLimiting.RateLimiterOptions.GlobalLimiter.get -> System.Threading.RateLimiting.PartitionedRateLimiter<Microsoft.AspNetCore.Http.HttpContext!>? +Microsoft.AspNetCore.RateLimiting.RateLimiterOptions.GlobalLimiter.set -> void +Microsoft.AspNetCore.RateLimiting.RateLimiterOptions.OnRejected.get -> System.Func<Microsoft.AspNetCore.RateLimiting.OnRejectedContext!, System.Threading.CancellationToken, System.Threading.Tasks.ValueTask>? Microsoft.AspNetCore.RateLimiting.RateLimiterOptions.OnRejected.set -> void Microsoft.AspNetCore.RateLimiting.RateLimiterOptions.RateLimiterOptions() -> void -Microsoft.AspNetCore.RateLimiting.RateLimitingApplicationBuilderExtensions -static Microsoft.AspNetCore.RateLimiting.RateLimitingApplicationBuilderExtensions.UseRateLimiter(this Microsoft.AspNetCore.Builder.IApplicationBuilder! app) -> Microsoft.AspNetCore.Builder.IApplicationBuilder! -static Microsoft.AspNetCore.RateLimiting.RateLimitingApplicationBuilderExtensions.UseRateLimiter(this Microsoft.AspNetCore.Builder.IApplicationBuilder! app, Microsoft.AspNetCore.RateLimiting.RateLimiterOptions! options) -> Microsoft.AspNetCore.Builder.IApplicationBuilder! +Microsoft.AspNetCore.RateLimiting.RateLimiterOptions.RejectionStatusCode.get -> int +Microsoft.AspNetCore.RateLimiting.RateLimiterOptions.RejectionStatusCode.set -> void +Microsoft.AspNetCore.RateLimiting.RateLimiterOptionsExtensions +static Microsoft.AspNetCore.Builder.RateLimiterApplicationBuilderExtensions.UseRateLimiter(this Microsoft.AspNetCore.Builder.IApplicationBuilder! app) -> Microsoft.AspNetCore.Builder.IApplicationBuilder! +static Microsoft.AspNetCore.Builder.RateLimiterApplicationBuilderExtensions.UseRateLimiter(this Microsoft.AspNetCore.Builder.IApplicationBuilder! app, Microsoft.AspNetCore.RateLimiting.RateLimiterOptions! options) -> Microsoft.AspNetCore.Builder.IApplicationBuilder! +static Microsoft.AspNetCore.Builder.RateLimiterEndpointConventionBuilderExtensions.RequireRateLimiting<TBuilder>(this TBuilder builder, string! policyName) -> TBuilder +static Microsoft.AspNetCore.RateLimiting.RateLimiterOptionsExtensions.AddConcurrencyLimiter(this Microsoft.AspNetCore.RateLimiting.RateLimiterOptions! options, string! policyName, System.Threading.RateLimiting.ConcurrencyLimiterOptions! concurrencyLimiterOptions) -> Microsoft.AspNetCore.RateLimiting.RateLimiterOptions! +static Microsoft.AspNetCore.RateLimiting.RateLimiterOptionsExtensions.AddFixedWindowLimiter(this Microsoft.AspNetCore.RateLimiting.RateLimiterOptions! options, string! policyName, System.Threading.RateLimiting.FixedWindowRateLimiterOptions! fixedWindowRateLimiterOptions) -> Microsoft.AspNetCore.RateLimiting.RateLimiterOptions! +static Microsoft.AspNetCore.RateLimiting.RateLimiterOptionsExtensions.AddNoLimiter(this Microsoft.AspNetCore.RateLimiting.RateLimiterOptions! options, string! policyName) -> Microsoft.AspNetCore.RateLimiting.RateLimiterOptions! +static Microsoft.AspNetCore.RateLimiting.RateLimiterOptionsExtensions.AddSlidingWindowLimiter(this Microsoft.AspNetCore.RateLimiting.RateLimiterOptions! options, string! policyName, System.Threading.RateLimiting.SlidingWindowRateLimiterOptions! slidingWindowRateLimiterOptions) -> Microsoft.AspNetCore.RateLimiting.RateLimiterOptions! +static Microsoft.AspNetCore.RateLimiting.RateLimiterOptionsExtensions.AddTokenBucketLimiter(this Microsoft.AspNetCore.RateLimiting.RateLimiterOptions! options, string! policyName, System.Threading.RateLimiting.TokenBucketRateLimiterOptions! tokenBucketRateLimiterOptions) -> Microsoft.AspNetCore.RateLimiting.RateLimiterOptions! diff --git a/src/Middleware/RateLimiting/src/RateLimitingApplicationBuilderExtensions.cs b/src/Middleware/RateLimiting/src/RateLimiterApplicationBuilderExtensions.cs index 64dddf417d..cd1ec7b826 100644 --- a/src/Middleware/RateLimiting/src/RateLimitingApplicationBuilderExtensions.cs +++ b/src/Middleware/RateLimiting/src/RateLimiterApplicationBuilderExtensions.cs @@ -1,15 +1,15 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.RateLimiting; using Microsoft.Extensions.Options; -namespace Microsoft.AspNetCore.RateLimiting; +namespace Microsoft.AspNetCore.Builder; /// <summary> /// Extension methods for the RateLimiting middleware. /// </summary> -public static class RateLimitingApplicationBuilderExtensions +public static class RateLimiterApplicationBuilderExtensions { /// <summary> /// Enables rate limiting for the application. diff --git a/src/Middleware/RateLimiting/src/RateLimiterEndpointConventionBuilderExtensions.cs b/src/Middleware/RateLimiting/src/RateLimiterEndpointConventionBuilderExtensions.cs new file mode 100644 index 0000000000..27096dfd7a --- /dev/null +++ b/src/Middleware/RateLimiting/src/RateLimiterEndpointConventionBuilderExtensions.cs @@ -0,0 +1,38 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.AspNetCore.RateLimiting; + +namespace Microsoft.AspNetCore.Builder; + +/// <summary> +/// Rate limiter extension methods for <see cref="IEndpointConventionBuilder"/>. +/// </summary> +public static class RateLimiterEndpointConventionBuilderExtensions +{ + /// <summary> + /// Adds the specified rate limiter to the endpoint(s). + /// </summary> + /// <param name="builder">The endpoint convention builder.</param> + /// <param name="policyName">The name of the rate limiter to add to the endpoint.</param> + /// <returns>The original convention builder parameter.</returns> + public static TBuilder RequireRateLimiting<TBuilder>(this TBuilder builder, string policyName) where TBuilder : IEndpointConventionBuilder + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + if (policyName == null) + { + throw new ArgumentNullException(nameof(policyName)); + } + + builder.Add(endpointBuilder => + { + endpointBuilder.Metadata.Add(new RateLimiterMetadata(policyName)); + }); + + return builder; + } +} diff --git a/src/Middleware/RateLimiting/src/RateLimiterMetadata.cs b/src/Middleware/RateLimiting/src/RateLimiterMetadata.cs new file mode 100644 index 0000000000..31acb7ce82 --- /dev/null +++ b/src/Middleware/RateLimiting/src/RateLimiterMetadata.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.AspNetCore.RateLimiting; + +/// <summary> +/// Metadata that provides endpoint-specific request rate limiting. +/// </summary> +internal class RateLimiterMetadata : IRateLimiterMetadata +{ + /// <summary> + /// Creates a new instance of <see cref="RateLimiterMetadata"/> using the specified limiter. + /// </summary> + /// <param name="policyName">The name of the limiter which needs to be applied.</param> + public RateLimiterMetadata(string policyName) + { + PolicyName = policyName; + } + + /// <summary> + /// The name of the limiter which needs to be applied. + /// </summary> + public string PolicyName { get; } +} diff --git a/src/Middleware/RateLimiting/src/RateLimiterOptions.cs b/src/Middleware/RateLimiting/src/RateLimiterOptions.cs index bc1ab30b7a..d232e93bac 100644 --- a/src/Middleware/RateLimiting/src/RateLimiterOptions.cs +++ b/src/Middleware/RateLimiting/src/RateLimiterOptions.cs @@ -1,8 +1,10 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics.CodeAnalysis; using System.Threading.RateLimiting; using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; namespace Microsoft.AspNetCore.RateLimiting; @@ -11,30 +13,22 @@ namespace Microsoft.AspNetCore.RateLimiting; /// </summary> public sealed class RateLimiterOptions { - // TODO - Provide a default? - private PartitionedRateLimiter<HttpContext> _limiter = new NoLimiter<HttpContext>(); - private Func<HttpContext, RateLimitLease, Task> _onRejected = (context, lease) => - { - return Task.CompletedTask; - }; + internal IDictionary<string, DefaultRateLimiterPolicy> PolicyMap { get; } + = new Dictionary<string, DefaultRateLimiterPolicy>(StringComparer.Ordinal); + + internal IDictionary<string, Func<IServiceProvider, DefaultRateLimiterPolicy>> UnactivatedPolicyMap { get; } + = new Dictionary<string, Func<IServiceProvider, DefaultRateLimiterPolicy>>(StringComparer.Ordinal); /// <summary> - /// Gets or sets the <see cref="PartitionedRateLimiter{TResource}"/> + /// Gets or sets the global <see cref="PartitionedRateLimiter{HttpContext}"/> that will be applied on all requests. + /// The global limiter will be executed first, followed by the endpoint-specific limiter, if one exists. /// </summary> - public PartitionedRateLimiter<HttpContext> Limiter - { - get => _limiter; - set => _limiter = value ?? throw new ArgumentNullException(nameof(value)); - } + public PartitionedRateLimiter<HttpContext>? GlobalLimiter { get; set; } /// <summary> - /// Gets or sets a <see cref="Func{HttpContext, RateLimitLease, Task}"/> that handles requests rejected by this middleware. + /// Gets or sets a <see cref="Func{OnRejectedContext, CancellationToken, ValueTask}"/> that handles requests rejected by this middleware. /// </summary> - public Func<HttpContext, RateLimitLease, Task> OnRejected - { - get => _onRejected; - set => _onRejected = value ?? throw new ArgumentNullException(nameof(value)); - } + public Func<OnRejectedContext, CancellationToken, ValueTask>? OnRejected { get; set; } /// <summary> /// Gets or sets the default status code to set on the response when a request is rejected. @@ -44,5 +38,108 @@ public sealed class RateLimiterOptions /// This status code will be set before <see cref="OnRejected"/> is called, so any status code set by /// <see cref="OnRejected"/> will "win" over this default. /// </remarks> - public int DefaultRejectionStatusCode { get; set; } = StatusCodes.Status503ServiceUnavailable; + public int RejectionStatusCode { get; set; } = StatusCodes.Status503ServiceUnavailable; + + /// <summary> + /// Adds a new rate limiting policy with the given policyName. + /// </summary> + /// <param name="policyName">The name to be associated with the given <see cref="RateLimiter"/>.</param> + /// <param name="partitioner">Method called every time an Acquire or WaitAsync call is made to figure out what rate limiter to apply to the request.</param> + public RateLimiterOptions AddPolicy<TPartitionKey>(string policyName, Func<HttpContext, RateLimitPartition<TPartitionKey>> partitioner) + { + ArgumentNullException.ThrowIfNull(policyName); + ArgumentNullException.ThrowIfNull(partitioner); + + if (PolicyMap.ContainsKey(policyName) || UnactivatedPolicyMap.ContainsKey(policyName)) + { + throw new ArgumentException($"There already exists a policy with the name {policyName}"); + } + + PolicyMap.Add(policyName, new DefaultRateLimiterPolicy(ConvertPartitioner<TPartitionKey>(partitioner), null)); + + return this; + } + + /// <summary> + /// Adds a new rate limiting policy with the given policyName. + /// </summary> + /// <param name="policyName">The name to be associated with the given TPolicy.</param> + public RateLimiterOptions AddPolicy<TPartitionKey, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TPolicy>(string policyName) where TPolicy : IRateLimiterPolicy<TPartitionKey> + { + ArgumentNullException.ThrowIfNull(policyName); + + if (PolicyMap.ContainsKey(policyName) || UnactivatedPolicyMap.ContainsKey(policyName)) + { + throw new ArgumentException($"There already exists a policy with the name {policyName}"); + } + + var policyType = new PolicyTypeState(typeof(TPolicy)); + Func <IServiceProvider, DefaultRateLimiterPolicy> policyFunc = serviceProvider => + { + var instance = (IRateLimiterPolicy<TPartitionKey>)ActivatorUtilities.CreateInstance(serviceProvider, policyType.PolicyType); + return new DefaultRateLimiterPolicy(ConvertPartitioner<TPartitionKey>(instance.GetPartition), instance.OnRejected); + }; + + UnactivatedPolicyMap.Add(policyName, policyFunc); + + return this; + } + + /// <summary> + /// Adds a new rate limiting policy with the given policyName. + /// </summary> + /// <param name="policyName">The name to be associated with the given <see cref="IRateLimiterPolicy{TPartitionKey}"/>.</param> + /// <param name="policy">The <see cref="IRateLimiterPolicy{TPartitionKey}"/> to be applied.</param> + public RateLimiterOptions AddPolicy<TPartitionKey>(string policyName, IRateLimiterPolicy<TPartitionKey> policy) + { + ArgumentNullException.ThrowIfNull(policyName); + + if (PolicyMap.ContainsKey(policyName) || UnactivatedPolicyMap.ContainsKey(policyName)) + { + throw new ArgumentException($"There already exists a policy with the name {policyName}"); + } + + ArgumentNullException.ThrowIfNull(policy); + + PolicyMap.Add(policyName, new DefaultRateLimiterPolicy(ConvertPartitioner<TPartitionKey>(policy.GetPartition), policy.OnRejected)); + + return this; + } + + internal RateLimiterOptions InternalAddPolicy(string policyName, Func<HttpContext, RateLimitPartition<DefaultKeyType>> partitioner) + { + ArgumentNullException.ThrowIfNull(policyName); + ArgumentNullException.ThrowIfNull(partitioner); + + if (PolicyMap.ContainsKey(policyName) || UnactivatedPolicyMap.ContainsKey(policyName)) + { + throw new ArgumentException($"There already exists a policy with the name {policyName}"); + } + + PolicyMap.Add(policyName, new DefaultRateLimiterPolicy(partitioner, null)); + + return this; + } + + // Converts a Partition<TKey> to a Partition<DefaultKeyType<TKey>> to prevent accidental collisions with the keys we create in the the RateLimiterOptionsExtensions. + private static Func<HttpContext, RateLimitPartition<DefaultKeyType>> ConvertPartitioner<TPartitionKey>(Func<HttpContext, RateLimitPartition<TPartitionKey>> partitioner) + { + return (context => + { + RateLimitPartition<TPartitionKey> partition = partitioner(context); + return new RateLimitPartition<DefaultKeyType>(new DefaultKeyType<TPartitionKey>(partition.PartitionKey), key => partition.Factory(partition.PartitionKey)); + }); + } + + // Workaround for linker bug: https://github.com/dotnet/linker/issues/1981 + private readonly struct PolicyTypeState + { + public PolicyTypeState([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type policyType) + { + PolicyType = policyType; + } + + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] + public Type PolicyType { get; } + } } diff --git a/src/Middleware/RateLimiting/src/RateLimiterOptionsExtensions.cs b/src/Middleware/RateLimiting/src/RateLimiterOptionsExtensions.cs new file mode 100644 index 0000000000..4d8c26cc35 --- /dev/null +++ b/src/Middleware/RateLimiting/src/RateLimiterOptionsExtensions.cs @@ -0,0 +1,90 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Threading.RateLimiting; + +namespace Microsoft.AspNetCore.RateLimiting; + +/// <summary> +/// Extension methods for the RateLimiting middleware options. +/// </summary> +public static class RateLimiterOptionsExtensions +{ + /// <summary> + /// Adds a new <see cref="TokenBucketRateLimiter"/> with the given <see cref="TokenBucketRateLimiterOptions"/> to the <see cref="RateLimiterOptions"/>. + /// </summary> + /// <param name="options">The <see cref="RateLimiterOptions"/> to add a limiter to.</param> + /// <param name="policyName">The name that will be associated with the limiter.</param> + /// <param name="tokenBucketRateLimiterOptions">The <see cref="TokenBucketRateLimiterOptions"/> to be used for the limiter.</param> + /// <returns>This <see cref="RateLimiterOptions"/>.</returns> + public static RateLimiterOptions AddTokenBucketLimiter(this RateLimiterOptions options, string policyName, TokenBucketRateLimiterOptions tokenBucketRateLimiterOptions) + { + return options.InternalAddPolicy(policyName, context => + { + return RateLimitPartition.CreateTokenBucketLimiter((DefaultKeyType)new DefaultKeyType<PolicyNameKey>(new PolicyNameKey() { PolicyName = policyName }), + _ => tokenBucketRateLimiterOptions); + }); + } + + /// <summary> + /// Adds a new <see cref="FixedWindowRateLimiter"/> with the given <see cref="FixedWindowRateLimiterOptions"/> to the <see cref="RateLimiterOptions"/>. + /// </summary> + /// <param name="options">The <see cref="RateLimiterOptions"/> to add a limiter to.</param> + /// <param name="policyName">The name that will be associated with the limiter.</param> + /// <param name="fixedWindowRateLimiterOptions">The <see cref="FixedWindowRateLimiterOptions"/> to be used for the limiter.</param> + /// <returns>This <see cref="RateLimiterOptions"/>.</returns> + public static RateLimiterOptions AddFixedWindowLimiter(this RateLimiterOptions options, string policyName, FixedWindowRateLimiterOptions fixedWindowRateLimiterOptions) + { + return options.InternalAddPolicy(policyName, context => + { + return RateLimitPartition.CreateFixedWindowLimiter((DefaultKeyType)new DefaultKeyType<PolicyNameKey>(new PolicyNameKey() { PolicyName = policyName }), + _ => fixedWindowRateLimiterOptions); + }); + } + + /// <summary> + /// Adds a new <see cref="SlidingWindowRateLimiter"/> with the given <see cref="SlidingWindowRateLimiterOptions"/> to the <see cref="RateLimiterOptions"/>. + /// </summary> + /// <param name="options">The <see cref="RateLimiterOptions"/> to add a limiter to.</param> + /// <param name="policyName">The name that will be associated with the limiter.</param> + /// <param name="slidingWindowRateLimiterOptions">The <see cref="SlidingWindowRateLimiterOptions"/> to be used for the limiter.</param> + /// <returns>This <see cref="RateLimiterOptions"/>.</returns> + public static RateLimiterOptions AddSlidingWindowLimiter(this RateLimiterOptions options, string policyName, SlidingWindowRateLimiterOptions slidingWindowRateLimiterOptions) + { + return options.InternalAddPolicy(policyName, context => + { + return RateLimitPartition.CreateSlidingWindowLimiter((DefaultKeyType)new DefaultKeyType<PolicyNameKey>(new PolicyNameKey() { PolicyName = policyName }), + _ => slidingWindowRateLimiterOptions); + }); + } + + /// <summary> + /// Adds a new <see cref="ConcurrencyLimiter"/> with the given <see cref="ConcurrencyLimiterOptions"/> to the <see cref="RateLimiterOptions"/>. + /// </summary> + /// <param name="options">The <see cref="RateLimiterOptions"/> to add a limiter to.</param> + /// <param name="policyName">The name that will be associated with the limiter.</param> + /// <param name="concurrencyLimiterOptions">The <see cref="ConcurrencyLimiterOptions"/> to be used for the limiter.</param> + /// <returns>This <see cref="RateLimiterOptions"/>.</returns> + public static RateLimiterOptions AddConcurrencyLimiter(this RateLimiterOptions options, string policyName, ConcurrencyLimiterOptions concurrencyLimiterOptions) + { + return options.InternalAddPolicy(policyName, context => + { + return RateLimitPartition.CreateConcurrencyLimiter((DefaultKeyType)new DefaultKeyType<PolicyNameKey>(new PolicyNameKey() { PolicyName = policyName }), + _ => concurrencyLimiterOptions); + }); + } + + /// <summary> + /// Adds a new no-op <see cref="RateLimiter"/> to the <see cref="RateLimiterOptions"/>. + /// </summary> + /// <param name="options">The <see cref="RateLimiterOptions"/> to add a limiter to.</param> + /// <param name="policyName">The name that will be associated with the limiter.</param> + /// <returns>This <see cref="RateLimiterOptions"/>.</returns> + public static RateLimiterOptions AddNoLimiter(this RateLimiterOptions options, string policyName) + { + return options.InternalAddPolicy(policyName, context => + { + return RateLimitPartition.CreateNoLimiter((DefaultKeyType)new DefaultKeyType<PolicyNameKey>(new PolicyNameKey() { PolicyName = policyName })); + }); + } +} diff --git a/src/Middleware/RateLimiting/src/RateLimitingMiddleware.cs b/src/Middleware/RateLimiting/src/RateLimitingMiddleware.cs index a97aa7c9ee..e4a170e0f2 100644 --- a/src/Middleware/RateLimiting/src/RateLimitingMiddleware.cs +++ b/src/Middleware/RateLimiting/src/RateLimitingMiddleware.cs @@ -14,10 +14,14 @@ namespace Microsoft.AspNetCore.RateLimiting; internal sealed partial class RateLimitingMiddleware { private readonly RequestDelegate _next; - private readonly Func<HttpContext, RateLimitLease, Task> _onRejected; + private readonly Func<OnRejectedContext, CancellationToken, ValueTask>? _defaultOnRejected; private readonly ILogger _logger; - private readonly PartitionedRateLimiter<HttpContext> _limiter; + private readonly PartitionedRateLimiter<HttpContext>? _globalLimiter; + private readonly PartitionedRateLimiter<HttpContext> _endpointLimiter; private readonly int _rejectionStatusCode; + private readonly IDictionary<string, DefaultRateLimiterPolicy> _policyMap; + private readonly DefaultKeyType _defaultPolicyKey = new DefaultKeyType<PolicyNameKey>(new PolicyNameKey { PolicyName = "__defaultPolicyKey" }); + private readonly IServiceProvider _serviceProvider; /// <summary> /// Creates a new <see cref="RateLimitingMiddleware"/>. @@ -25,15 +29,29 @@ internal sealed partial class RateLimitingMiddleware /// <param name="next">The <see cref="RequestDelegate"/> representing the next middleware in the pipeline.</param> /// <param name="logger">The <see cref="ILogger"/> used for logging.</param> /// <param name="options">The options for the middleware.</param> - public RateLimitingMiddleware(RequestDelegate next, ILogger<RateLimitingMiddleware> logger, IOptions<RateLimiterOptions> options) + /// <param name="serviceProvider">The service provider.</param> + public RateLimitingMiddleware(RequestDelegate next, ILogger<RateLimitingMiddleware> logger, IOptions<RateLimiterOptions> options, IServiceProvider serviceProvider) { _next = next ?? throw new ArgumentNullException(nameof(next)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _limiter = options.Value.Limiter; - _onRejected = options.Value.OnRejected; - _rejectionStatusCode = options.Value.DefaultRejectionStatusCode; + _serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider)); + + _defaultOnRejected = options.Value.OnRejected; + _rejectionStatusCode = options.Value.RejectionStatusCode; + _policyMap = options.Value.PolicyMap; + + // Use reflection to activate policies passed to AddPolicy<TPartitionKey, TPolicy> + + foreach (var unactivatedPolicy in options.Value.UnactivatedPolicyMap) + { + _policyMap.Add(unactivatedPolicy.Key, unactivatedPolicy.Value(_serviceProvider)); + } + + _globalLimiter = options.Value.GlobalLimiter; + _endpointLimiter = CreateEndpointLimiter(); + } // TODO - EventSource? @@ -44,30 +62,126 @@ internal sealed partial class RateLimitingMiddleware /// <returns>A <see cref="Task"/> that completes when the request leaves.</returns> public async Task Invoke(HttpContext context) { - using var lease = await TryAcquireAsync(context); - if (lease.IsAcquired) + using var leaseContext = await TryAcquireAsync(context); + if (leaseContext.Lease.IsAcquired) { await _next(context); } else { + var thisRequestOnRejected = _defaultOnRejected; RateLimiterLog.RequestRejectedLimitsExceeded(_logger); // OnRejected "wins" over DefaultRejectionStatusCode - we set DefaultRejectionStatusCode first, // then call OnRejected in case it wants to do any further modification of the status code. context.Response.StatusCode = _rejectionStatusCode; - await _onRejected(context, lease); + + // If this request was rejected by the endpoint limiter, use its OnRejected if available. Else + if (leaseContext.GlobalRejected == false) + { + DefaultRateLimiterPolicy? policy; + var policyName = context.GetEndpoint()?.Metadata.GetMetadata<IRateLimiterMetadata>()?.PolicyName; + // Use custom policy OnRejected if available, else use OnRejected from the Options if available. + if (policyName is not null && _policyMap.TryGetValue(policyName, out policy) && policy.OnRejected is not null) + { + thisRequestOnRejected = policy.OnRejected; + } + } + if (thisRequestOnRejected is not null) + { + await thisRequestOnRejected(new OnRejectedContext() { HttpContext = context, Lease = leaseContext.Lease }, context.RequestAborted); + } } } - private ValueTask<RateLimitLease> TryAcquireAsync(HttpContext context) + private ValueTask<LeaseContext> TryAcquireAsync(HttpContext context) { - var lease = _limiter.Acquire(context); - if (lease.IsAcquired) + var leaseContext = CombinedAcquire(context); + if (leaseContext.Lease.IsAcquired) { - return ValueTask.FromResult(lease); + return ValueTask.FromResult(leaseContext); } - return _limiter.WaitAsync(context, cancellationToken: context.RequestAborted); + return CombinedWaitAsync(context, context.RequestAborted); + } + + private LeaseContext CombinedAcquire(HttpContext context) + { + RateLimitLease? globalLease = null; + RateLimitLease? endpointLease = null; + + try + { + if (_globalLimiter is not null) + { + globalLease = _globalLimiter.Acquire(context); + if (!globalLease.IsAcquired) + { + return new LeaseContext() { GlobalRejected = true, Lease = globalLease }; + } + } + endpointLease = _endpointLimiter.Acquire(context); + if (!endpointLease.IsAcquired) + { + globalLease?.Dispose(); + return new LeaseContext() { GlobalRejected = false, Lease = endpointLease }; + } + } + catch (Exception) + { + endpointLease?.Dispose(); + globalLease?.Dispose(); + throw; + } + + return new LeaseContext() { Lease = new DefaultCombinedLease(globalLease, endpointLease)}; + } + + private async ValueTask<LeaseContext> CombinedWaitAsync(HttpContext context, CancellationToken cancellationToken) + { + RateLimitLease? globalLease = null; + RateLimitLease? endpointLease = null; + + try + { + if (_globalLimiter is not null) + { + globalLease = await _globalLimiter.WaitAsync(context, cancellationToken: cancellationToken).ConfigureAwait(false); + if (!globalLease.IsAcquired) + { + return new LeaseContext() { GlobalRejected = true, Lease = globalLease }; + } + } + endpointLease = await _endpointLimiter.WaitAsync(context, cancellationToken: cancellationToken).ConfigureAwait(false); + if (!endpointLease.IsAcquired) + { + globalLease?.Dispose(); + return new LeaseContext() { GlobalRejected = false, Lease = endpointLease }; + } + } + catch (Exception) + { + endpointLease?.Dispose(); + globalLease?.Dispose(); + throw; + } + + return new LeaseContext() { Lease = new DefaultCombinedLease(globalLease, endpointLease) }; + } + + // Create the endpoint-specific PartitionedRateLimiter + private PartitionedRateLimiter<HttpContext> CreateEndpointLimiter() + { + // If we have a policy for this endpoint, use its partitioner. Else use a NoLimiter. + return PartitionedRateLimiter.Create<HttpContext, DefaultKeyType>(context => + { + DefaultRateLimiterPolicy? policy; + var name = context.GetEndpoint()?.Metadata.GetMetadata<IRateLimiterMetadata>()?.PolicyName; + if (name is not null && _policyMap.TryGetValue(name, out policy)) + { + return policy.GetPartition(context); + } + return RateLimitPartition.CreateNoLimiter<DefaultKeyType>(_defaultPolicyKey); + }, new DefaultKeyTypeEqualityComparer()); } private static partial class RateLimiterLog diff --git a/src/Middleware/RateLimiting/test/RateLimitingApplicationBuilderExtensionsTests.cs b/src/Middleware/RateLimiting/test/RateLimitingApplicationBuilderExtensionsTests.cs index 37d6d5bc4c..45afd2182a 100644 --- a/src/Middleware/RateLimiting/test/RateLimitingApplicationBuilderExtensionsTests.cs +++ b/src/Middleware/RateLimiting/test/RateLimitingApplicationBuilderExtensionsTests.cs @@ -14,7 +14,7 @@ public class RateLimitingApplicationBuilderExtensionsTests : LoggedTest [Fact] public void UseRateLimiter_ThrowsOnNullAppBuilder() { - Assert.Throws<ArgumentNullException>(() => RateLimitingApplicationBuilderExtensions.UseRateLimiter(null)); + Assert.Throws<ArgumentNullException>(() => RateLimiterApplicationBuilderExtensions.UseRateLimiter(null)); } [Fact] @@ -29,15 +29,15 @@ public class RateLimitingApplicationBuilderExtensionsTests : LoggedTest { // These are the options that should get used var options = new RateLimiterOptions(); - options.DefaultRejectionStatusCode = 429; - options.Limiter = new TestPartitionedRateLimiter<HttpContext>(new TestRateLimiter(false)); + options.RejectionStatusCode = 429; + options.GlobalLimiter = new TestPartitionedRateLimiter<HttpContext>(new TestRateLimiter(false)); // These should not get used var services = new ServiceCollection(); services.Configure<RateLimiterOptions>(options => { - options.Limiter = new TestPartitionedRateLimiter<HttpContext>(new TestRateLimiter(false)); - options.DefaultRejectionStatusCode = 404; + options.GlobalLimiter = new TestPartitionedRateLimiter<HttpContext>(new TestRateLimiter(false)); + options.RejectionStatusCode = 404; }); services.AddLogging(); var serviceProvider = services.BuildServiceProvider(); diff --git a/src/Middleware/RateLimiting/test/RateLimitingMiddlewareTests.cs b/src/Middleware/RateLimiting/test/RateLimitingMiddlewareTests.cs index 903b225ed4..f14d0fa0ab 100644 --- a/src/Middleware/RateLimiting/test/RateLimitingMiddlewareTests.cs +++ b/src/Middleware/RateLimiting/test/RateLimitingMiddlewareTests.cs @@ -1,11 +1,13 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Threading.RateLimiting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Testing; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; +using Moq; namespace Microsoft.AspNetCore.RateLimiting; @@ -15,19 +17,29 @@ public class RateLimitingMiddlewareTests : LoggedTest public void Ctor_ThrowsExceptionsWhenNullArgs() { var options = CreateOptionsAccessor(); - options.Value.Limiter = new TestPartitionedRateLimiter<HttpContext>(); + options.Value.GlobalLimiter = new TestPartitionedRateLimiter<HttpContext>(); Assert.Throws<ArgumentNullException>(() => new RateLimitingMiddleware( null, new NullLoggerFactory().CreateLogger<RateLimitingMiddleware>(), - options)); + options, + Mock.Of<IServiceProvider>())); Assert.Throws<ArgumentNullException>(() => new RateLimitingMiddleware(c => - { - return Task.CompletedTask; - }, - null, - options)); + { + return Task.CompletedTask; + }, + null, + options, + Mock.Of<IServiceProvider>())); + + Assert.Throws<ArgumentNullException>(() => new RateLimitingMiddleware(c => + { + return Task.CompletedTask; + }, + new NullLoggerFactory().CreateLogger<RateLimitingMiddleware>(), + options, + null)); } [Fact] @@ -35,14 +47,15 @@ public class RateLimitingMiddlewareTests : LoggedTest { var flag = false; var options = CreateOptionsAccessor(); - options.Value.Limiter = new TestPartitionedRateLimiter<HttpContext>(new TestRateLimiter(true)); + options.Value.GlobalLimiter = new TestPartitionedRateLimiter<HttpContext>(new TestRateLimiter(true)); var middleware = new RateLimitingMiddleware(c => - { - flag = true; - return Task.CompletedTask; - }, - new NullLoggerFactory().CreateLogger<RateLimitingMiddleware>(), - options); + { + flag = true; + return Task.CompletedTask; + }, + new NullLoggerFactory().CreateLogger<RateLimitingMiddleware>(), + options, + Mock.Of<IServiceProvider>()); await middleware.Invoke(new DefaultHttpContext()); Assert.True(flag); @@ -53,19 +66,20 @@ public class RateLimitingMiddlewareTests : LoggedTest { var onRejectedInvoked = false; var options = CreateOptionsAccessor(); - options.Value.Limiter = new TestPartitionedRateLimiter<HttpContext>(new TestRateLimiter(false)); - options.Value.OnRejected = (httpContext, lease) => + options.Value.GlobalLimiter = new TestPartitionedRateLimiter<HttpContext>(new TestRateLimiter(false)); + options.Value.OnRejected = (context, token) => { onRejectedInvoked = true; - return Task.CompletedTask; + return ValueTask.CompletedTask; }; var middleware = new RateLimitingMiddleware(c => - { - return Task.CompletedTask; - }, - new NullLoggerFactory().CreateLogger<RateLimitingMiddleware>(), - options); + { + return Task.CompletedTask; + }, + new NullLoggerFactory().CreateLogger<RateLimitingMiddleware>(), + options, + Mock.Of<IServiceProvider>()); var context = new DefaultHttpContext(); await middleware.Invoke(context).DefaultTimeout(); @@ -78,20 +92,21 @@ public class RateLimitingMiddlewareTests : LoggedTest { var onRejectedInvoked = false; var options = CreateOptionsAccessor(); - options.Value.Limiter = new TestPartitionedRateLimiter<HttpContext>(new TestRateLimiter(false)); - options.Value.OnRejected = (httpContext, lease) => + options.Value.GlobalLimiter = new TestPartitionedRateLimiter<HttpContext>(new TestRateLimiter(false)); + options.Value.OnRejected = (context, token) => { onRejectedInvoked = true; - httpContext.Response.StatusCode = 429; - return Task.CompletedTask; + context.HttpContext.Response.StatusCode = 429; + return ValueTask.CompletedTask; }; var middleware = new RateLimitingMiddleware(c => - { - return Task.CompletedTask; - }, - new NullLoggerFactory().CreateLogger<RateLimitingMiddleware>(), - options); + { + return Task.CompletedTask; + }, + new NullLoggerFactory().CreateLogger<RateLimitingMiddleware>(), + options, + Mock.Of<IServiceProvider>()); var context = new DefaultHttpContext(); await middleware.Invoke(context).DefaultTimeout(); @@ -103,18 +118,260 @@ public class RateLimitingMiddlewareTests : LoggedTest public async Task RequestAborted_ThrowsTaskCanceledException() { var options = CreateOptionsAccessor(); - options.Value.Limiter = new TestPartitionedRateLimiter<HttpContext>(new TestRateLimiter(false)); + options.Value.GlobalLimiter = new TestPartitionedRateLimiter<HttpContext>(new TestRateLimiter(false)); + + var middleware = new RateLimitingMiddleware(c => + { + return Task.CompletedTask; + }, + new NullLoggerFactory().CreateLogger<RateLimitingMiddleware>(), + options, + Mock.Of<IServiceProvider>()); + + var context = new DefaultHttpContext(); + context.RequestAborted = new CancellationToken(true); + await Assert.ThrowsAsync<TaskCanceledException>(() => middleware.Invoke(context)).DefaultTimeout(); + } + + [Fact] + public async Task EndpointLimiter_Rejects() + { + var onRejectedInvoked = false; + var options = CreateOptionsAccessor(); + var name = "myEndpoint"; + options.Value.AddPolicy<string>(name, (context => + { + return RateLimitPartition.Create<string>("myLimiter", (key => + { + return new TestRateLimiter(false); + })); + })); + options.Value.OnRejected = (context, token) => + { + onRejectedInvoked = true; + context.HttpContext.Response.StatusCode = 429; + return ValueTask.CompletedTask; + }; + + var middleware = new RateLimitingMiddleware(c => + { + return Task.CompletedTask; + }, + new NullLoggerFactory().CreateLogger<RateLimitingMiddleware>(), + options, + Mock.Of<IServiceProvider>()); + + var context = new DefaultHttpContext(); + context.SetEndpoint(new Endpoint(c => Task.CompletedTask, new EndpointMetadataCollection(new RateLimiterMetadata(name)), "Test endpoint")); + await middleware.Invoke(context).DefaultTimeout(); + Assert.True(onRejectedInvoked); + Assert.Equal(StatusCodes.Status429TooManyRequests, context.Response.StatusCode); + } + + [Fact] + public async Task EndpointLimiterConvenienceMethod_Rejects() + { + var onRejectedInvoked = false; + var options = CreateOptionsAccessor(); + var name = "myEndpoint"; + options.Value.AddFixedWindowLimiter(name, new FixedWindowRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 0, TimeSpan.Zero, autoReplenishment: false)); + options.Value.OnRejected = (context, token) => + { + onRejectedInvoked = true; + context.HttpContext.Response.StatusCode = 429; + return ValueTask.CompletedTask; + }; + + var middleware = new RateLimitingMiddleware(c => + { + return Task.CompletedTask; + }, + new NullLoggerFactory().CreateLogger<RateLimitingMiddleware>(), + options, + Mock.Of<IServiceProvider>()); + + var context = new DefaultHttpContext(); + context.SetEndpoint(new Endpoint(c => Task.CompletedTask, new EndpointMetadataCollection(new RateLimiterMetadata(name)), "Test endpoint")); + await middleware.Invoke(context).DefaultTimeout(); + Assert.False(onRejectedInvoked); + await middleware.Invoke(context).DefaultTimeout(); + Assert.True(onRejectedInvoked); + Assert.Equal(StatusCodes.Status429TooManyRequests, context.Response.StatusCode); + } + + [Fact] + public async Task EndpointLimiterRejects_EndpointOnRejectedFires() + { + var globalOnRejectedInvoked = false; + var options = CreateOptionsAccessor(); + var name = "myEndpoint"; + // This is the policy that should get used + options.Value.AddPolicy<string>(name, new TestRateLimiterPolicy("myKey", 404, false)); + // This OnRejected should be ignored in favor of the one on the policy + options.Value.OnRejected = (context, token) => + { + globalOnRejectedInvoked = true; + context.HttpContext.Response.StatusCode = 429; + return ValueTask.CompletedTask; + }; + + var middleware = new RateLimitingMiddleware(c => + { + return Task.CompletedTask; + }, + new NullLoggerFactory().CreateLogger<RateLimitingMiddleware>(), + options, + Mock.Of<IServiceProvider>()); + + var context = new DefaultHttpContext(); + context.SetEndpoint(new Endpoint(c => Task.CompletedTask, new EndpointMetadataCollection(new RateLimiterMetadata(name)), "Test endpoint")); + await middleware.Invoke(context).DefaultTimeout(); + Assert.False(globalOnRejectedInvoked); + + Assert.Equal(StatusCodes.Status404NotFound, context.Response.StatusCode); + } + + [Fact] + public async Task GlobalAndEndpoint_GlobalRejects_GlobalWins() + { + var globalOnRejectedInvoked = false; + var options = CreateOptionsAccessor(); + var name = "myEndpoint"; + // Endpoint always allows - it should not fire + options.Value.AddPolicy<string>(name, new TestRateLimiterPolicy("myKey", 404, true)); + // Global never allows - it should fire + options.Value.GlobalLimiter = new TestPartitionedRateLimiter<HttpContext>(new TestRateLimiter(false)); + options.Value.OnRejected = (context, token) => + { + globalOnRejectedInvoked = true; + context.HttpContext.Response.StatusCode = 429; + return ValueTask.CompletedTask; + }; + + var middleware = new RateLimitingMiddleware(c => + { + return Task.CompletedTask; + }, + new NullLoggerFactory().CreateLogger<RateLimitingMiddleware>(), + options, + Mock.Of<IServiceProvider>()); + + var context = new DefaultHttpContext(); + context.SetEndpoint(new Endpoint(c => Task.CompletedTask, new EndpointMetadataCollection(new RateLimiterMetadata(name)), "Test endpoint")); + await middleware.Invoke(context).DefaultTimeout(); + Assert.True(globalOnRejectedInvoked); + + Assert.Equal(StatusCodes.Status429TooManyRequests, context.Response.StatusCode); + } + + [Fact] + public async Task GlobalAndEndpoint_EndpointRejects_EndpointWins() + { + var globalOnRejectedInvoked = false; + var options = CreateOptionsAccessor(); + var name = "myEndpoint"; + // Endpoint never allows - it should fire + options.Value.AddPolicy<string>(name, new TestRateLimiterPolicy("myKey", 404, false)); + // Global always allows - it should not fire + options.Value.GlobalLimiter = new TestPartitionedRateLimiter<HttpContext>(new TestRateLimiter(true)); + options.Value.OnRejected = (context, token) => + { + globalOnRejectedInvoked = true; + context.HttpContext.Response.StatusCode = 429; + return ValueTask.CompletedTask; + }; + + var middleware = new RateLimitingMiddleware(c => + { + return Task.CompletedTask; + }, + new NullLoggerFactory().CreateLogger<RateLimitingMiddleware>(), + options, + Mock.Of<IServiceProvider>()); + + var context = new DefaultHttpContext(); + context.SetEndpoint(new Endpoint(c => Task.CompletedTask, new EndpointMetadataCollection(new RateLimiterMetadata(name)), "Test endpoint")); + await middleware.Invoke(context).DefaultTimeout(); + Assert.False(globalOnRejectedInvoked); + + Assert.Equal(StatusCodes.Status404NotFound, context.Response.StatusCode); + } + + [Fact] + public async Task GlobalAndEndpoint_BothReject_GlobalWins() + { + var globalOnRejectedInvoked = false; + var options = CreateOptionsAccessor(); + var name = "myEndpoint"; + // Endpoint never allows - it should not fire + options.Value.AddPolicy<string>(name, new TestRateLimiterPolicy("myKey", 404, false)); + // Global never allows - it should fire + options.Value.GlobalLimiter = new TestPartitionedRateLimiter<HttpContext>(new TestRateLimiter(false)); + options.Value.OnRejected = (context, token) => + { + globalOnRejectedInvoked = true; + context.HttpContext.Response.StatusCode = 429; + return ValueTask.CompletedTask; + }; + + var middleware = new RateLimitingMiddleware(c => + { + return Task.CompletedTask; + }, + new NullLoggerFactory().CreateLogger<RateLimitingMiddleware>(), + options, + Mock.Of<IServiceProvider>()); + + var context = new DefaultHttpContext(); + context.SetEndpoint(new Endpoint(c => Task.CompletedTask, new EndpointMetadataCollection(new RateLimiterMetadata(name)), "Test endpoint")); + await middleware.Invoke(context).DefaultTimeout(); + Assert.True(globalOnRejectedInvoked); + + Assert.Equal(StatusCodes.Status429TooManyRequests, context.Response.StatusCode); + } + + [Fact] + public async Task EndpointLimiterRejects_EndpointOnRejectedFires_WithIRateLimiterPolicy() + { + var globalOnRejectedInvoked = false; + var options = CreateOptionsAccessor(); + var name = "myEndpoint"; + // This is the policy that should get used + options.Value.AddPolicy<string, TestRateLimiterPolicy>(name); + // This OnRejected should be ignored in favor of the one on the policy + options.Value.OnRejected = (context, token) => + { + globalOnRejectedInvoked = true; + context.HttpContext.Response.StatusCode = 429; + return ValueTask.CompletedTask; + }; + + // Configure the service provider with the args to the TestRateLimiterPolicy ctor + var mockServiceProvider = new Mock<IServiceProvider>(); + mockServiceProvider + .Setup(sp => sp.GetService(typeof(string))) + .Returns("myKey"); + mockServiceProvider + .Setup(sp => sp.GetService(typeof(int))) + .Returns(404); + mockServiceProvider + .Setup(sp => sp.GetService(typeof(bool))) + .Returns(false); var middleware = new RateLimitingMiddleware(c => { return Task.CompletedTask; }, - new NullLoggerFactory().CreateLogger<RateLimitingMiddleware>(), - options); + new NullLoggerFactory().CreateLogger<RateLimitingMiddleware>(), + options, + mockServiceProvider.Object); var context = new DefaultHttpContext(); - context.RequestAborted = new CancellationToken(true); - await Assert.ThrowsAsync<TaskCanceledException>(() => middleware.Invoke(context)).DefaultTimeout(); + context.SetEndpoint(new Endpoint(c => Task.CompletedTask, new EndpointMetadataCollection(new RateLimiterMetadata(name)), "Test endpoint")); + await middleware.Invoke(context).DefaultTimeout(); + Assert.False(globalOnRejectedInvoked); + + Assert.Equal(StatusCodes.Status404NotFound, context.Response.StatusCode); } private IOptions<RateLimiterOptions> CreateOptionsAccessor() => Options.Create(new RateLimiterOptions()); diff --git a/src/Middleware/RateLimiting/test/RateLimitingOptionsTests.cs b/src/Middleware/RateLimiting/test/RateLimitingOptionsTests.cs index 839a9d2da0..a58512e28f 100644 --- a/src/Middleware/RateLimiting/test/RateLimitingOptionsTests.cs +++ b/src/Middleware/RateLimiting/test/RateLimitingOptionsTests.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Threading.RateLimiting; +using Castle.DynamicProxy.Generators.Emitters.SimpleAST; using Microsoft.AspNetCore.Http; namespace Microsoft.AspNetCore.RateLimiting; @@ -8,16 +10,39 @@ namespace Microsoft.AspNetCore.RateLimiting; public class RateLimitingOptionsTests { [Fact] - public void ThrowsOnNullLimiter() + public void AddPolicy_ThrowsOnNullPolicyName() { var options = new RateLimiterOptions(); - Assert.Throws<ArgumentNullException>(() => options.Limiter = null); + Assert.Throws<ArgumentNullException>(() => options.AddPolicy<string>(null, context => RateLimitPartition.CreateNoLimiter<string>("myKey"))); } [Fact] - public void ThrowsOnNullOnRejected() + public void AddPolicy_ThrowsOnNullPartitioner() { var options = new RateLimiterOptions(); - Assert.Throws<ArgumentNullException>(() => options.OnRejected = null); + Assert.Throws<ArgumentNullException>(() => options.AddPolicy<string>("myKey", partitioner: null)); + } + + [Fact] + public void AddPolicy_ThrowsOnNullPolicy() + { + var options = new RateLimiterOptions(); + Assert.Throws<ArgumentNullException>(() => options.AddPolicy<string>("myKey", policy: null)); + } + + [Fact] + public void AddPolicy_ThrowsOnDuplicateName() + { + var options = new RateLimiterOptions(); + options.AddPolicy<string>("myKey", context => RateLimitPartition.CreateNoLimiter<string>("myKey")); + Assert.Throws<ArgumentException>(() => options.AddPolicy<string>("myKey", context => RateLimitPartition.CreateNoLimiter<string>("yourKey"))); + } + + [Fact] + public void AddPolicy_Generic_ThrowsOnDuplicateName() + { + var options = new RateLimiterOptions(); + options.AddPolicy<string>("myKey", context => RateLimitPartition.CreateNoLimiter<string>("myKey")); + Assert.Throws<ArgumentException>(() => options.AddPolicy<string, TestRateLimiterPolicy>("myKey")); } } diff --git a/src/Middleware/RateLimiting/test/TestRateLimiterPolicy.cs b/src/Middleware/RateLimiting/test/TestRateLimiterPolicy.cs new file mode 100644 index 0000000000..777935a092 --- /dev/null +++ b/src/Middleware/RateLimiting/test/TestRateLimiterPolicy.cs @@ -0,0 +1,35 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Threading.RateLimiting; +using Microsoft.AspNetCore.Http; + +namespace Microsoft.AspNetCore.RateLimiting; +internal class TestRateLimiterPolicy : IRateLimiterPolicy<string> +{ + private readonly string _key; + private readonly bool _alwaysAccept; + private readonly Func<OnRejectedContext, CancellationToken, ValueTask> _onRejected; + + public TestRateLimiterPolicy(string key, int statusCode, bool alwaysAccept) + { + _key = key; + _alwaysAccept = alwaysAccept; + + _onRejected = (context, token) => + { + context.HttpContext.Response.StatusCode = statusCode; + return ValueTask.CompletedTask; + }; + } + + public Func<OnRejectedContext, CancellationToken, ValueTask> OnRejected { get => _onRejected; } + + public RateLimitPartition<string> GetPartition(HttpContext httpContext) + { + return RateLimitPartition.Create<string>(_key, (key => + { + return new TestRateLimiter(_alwaysAccept); + })); + } +} |