diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 6119eb0b4849..ed91f5bc69a4 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -9,325 +9,325 @@ --> - + https://github.com/dotnet/efcore - 66fc2aa66ae1167cc4bccc748a5c128278d8c869 + 8b6956d731cff085ccb91767a74987db5a9e3b93 - + https://github.com/dotnet/efcore - 66fc2aa66ae1167cc4bccc748a5c128278d8c869 + 8b6956d731cff085ccb91767a74987db5a9e3b93 - + https://github.com/dotnet/efcore - 66fc2aa66ae1167cc4bccc748a5c128278d8c869 + 8b6956d731cff085ccb91767a74987db5a9e3b93 - + https://github.com/dotnet/efcore - 66fc2aa66ae1167cc4bccc748a5c128278d8c869 + 8b6956d731cff085ccb91767a74987db5a9e3b93 - + https://github.com/dotnet/efcore - 66fc2aa66ae1167cc4bccc748a5c128278d8c869 + 8b6956d731cff085ccb91767a74987db5a9e3b93 - + https://github.com/dotnet/efcore - 66fc2aa66ae1167cc4bccc748a5c128278d8c869 + 8b6956d731cff085ccb91767a74987db5a9e3b93 - + https://github.com/dotnet/efcore - 66fc2aa66ae1167cc4bccc748a5c128278d8c869 + 8b6956d731cff085ccb91767a74987db5a9e3b93 - + https://github.com/dotnet/efcore - 66fc2aa66ae1167cc4bccc748a5c128278d8c869 + 8b6956d731cff085ccb91767a74987db5a9e3b93 - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a https://github.com/dotnet/xdt @@ -367,9 +367,9 @@ afa1eb6821f62183651ab017b2f5c3fbeb934904 - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a @@ -380,9 +380,9 @@ - + https://github.com/dotnet/runtime - e1ab2243b27da4aa8a76372e4384bcd2b5894b3b + 4072e7377aa84559e725e450ddf1bf10d6fdf00a https://github.com/dotnet/winforms diff --git a/eng/Versions.props b/eng/Versions.props index bdbd592c6614..ce6ef55e55f2 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -67,92 +67,92 @@ --> - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 - 9.0.0-preview.7.24365.2 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 + 9.0.0-rc.1.24374.13 9.0.0-preview.7.24360.1 9.0.0-preview.7.24360.1 - 9.0.0-preview.7.24366.2 - 9.0.0-preview.7.24366.2 - 9.0.0-preview.7.24366.2 - 9.0.0-preview.7.24366.2 - 9.0.0-preview.7.24366.2 - 9.0.0-preview.7.24366.2 - 9.0.0-preview.7.24366.2 - 9.0.0-preview.7.24366.2 + 9.0.0-rc.1.24374.2 + 9.0.0-rc.1.24374.2 + 9.0.0-rc.1.24374.2 + 9.0.0-rc.1.24374.2 + 9.0.0-rc.1.24374.2 + 9.0.0-rc.1.24374.2 + 9.0.0-rc.1.24374.2 + 9.0.0-rc.1.24374.2 4.11.0-1.24218.5 4.11.0-1.24218.5 diff --git a/eng/testing/linker/project.csproj.template b/eng/testing/linker/project.csproj.template index 8efde8d4b648..35df91db4f05 100644 --- a/eng/testing/linker/project.csproj.template +++ b/eng/testing/linker/project.csproj.template @@ -8,6 +8,8 @@ {MicrosoftNETCoreAppRuntimeVersion} {MicrosoftNETCoreAppRefVersion} {RepoRoot} + + $(NoWarn);IL2119 99.9 <_ExtraTrimmerArgs>{ExtraTrimmerArgs} $(_ExtraTrimmerArgs) diff --git a/src/Caching/Hybrid/src/Internal/DefaultHybridCache.L2.cs b/src/Caching/Hybrid/src/Internal/DefaultHybridCache.L2.cs index 578528e9d4be..e0480abff5b8 100644 --- a/src/Caching/Hybrid/src/Internal/DefaultHybridCache.L2.cs +++ b/src/Caching/Hybrid/src/Internal/DefaultHybridCache.L2.cs @@ -106,9 +106,19 @@ private DistributedCacheEntryOptions GetOptions(HybridCacheEntryOptions? options DistributedCacheEntryOptions? result = null; if (options is not null && options.Expiration.HasValue && options.Expiration.GetValueOrDefault() != _defaultExpiration) { - result = options.ToDistributedCacheEntryOptions(); + result = ToDistributedCacheEntryOptions(options); } return result ?? _defaultDistributedCacheExpiration; + +#if NET8_0_OR_GREATER + // internal method memoizes this allocation; since it is "init", it is immutable (outside reflection) + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = nameof(ToDistributedCacheEntryOptions))] + extern static DistributedCacheEntryOptions? ToDistributedCacheEntryOptions(HybridCacheEntryOptions options); +#else + // withoug that helper method, we'll just eat the alloc (down-level TFMs) + static DistributedCacheEntryOptions ToDistributedCacheEntryOptions(HybridCacheEntryOptions options) + => new() { AbsoluteExpirationRelativeToNow = options.Expiration }; +#endif } internal void SetL1(string key, CacheItem value, HybridCacheEntryOptions? options) diff --git a/src/Caching/Hybrid/src/Internal/DefaultHybridCache.cs b/src/Caching/Hybrid/src/Internal/DefaultHybridCache.cs index a41c42ba635b..3dc98e55ef3b 100644 --- a/src/Caching/Hybrid/src/Internal/DefaultHybridCache.cs +++ b/src/Caching/Hybrid/src/Internal/DefaultHybridCache.cs @@ -108,12 +108,12 @@ public DefaultHybridCache(IOptions options, IServiceProvider private HybridCacheEntryFlags GetEffectiveFlags(HybridCacheEntryOptions? options) => (options?.Flags | _hardFlags) ?? _defaultFlags; - public override ValueTask GetOrCreateAsync(string key, TState state, Func> underlyingDataCallback, HybridCacheEntryOptions? options = null, IReadOnlyCollection? tags = null, CancellationToken token = default) + public override ValueTask GetOrCreateAsync(string key, TState state, Func> underlyingDataCallback, HybridCacheEntryOptions? options = null, IEnumerable? tags = null, CancellationToken cancellationToken = default) { - var canBeCanceled = token.CanBeCanceled; + var canBeCanceled = cancellationToken.CanBeCanceled; if (canBeCanceled) { - token.ThrowIfCancellationRequested(); + cancellationToken.ThrowIfCancellationRequested(); } var flags = GetEffectiveFlags(options); @@ -141,7 +141,7 @@ public override ValueTask GetOrCreateAsync(string key, TState stat } } - return stampede.JoinAsync(token); + return stampede.JoinAsync(cancellationToken); } public override ValueTask RemoveAsync(string key, CancellationToken token = default) @@ -153,7 +153,7 @@ public override ValueTask RemoveAsync(string key, CancellationToken token = defa public override ValueTask RemoveByTagAsync(string tag, CancellationToken token = default) => default; // tags not yet implemented - public override ValueTask SetAsync(string key, T value, HybridCacheEntryOptions? options = null, IReadOnlyCollection? tags = null, CancellationToken token = default) + public override ValueTask SetAsync(string key, T value, HybridCacheEntryOptions? options = null, IEnumerable? tags = null, CancellationToken token = default) { // since we're forcing a write: disable L1+L2 read; we'll use a direct pass-thru of the value as the callback, to reuse all the code; // note also that stampede token is not shared with anyone else diff --git a/src/Caching/Hybrid/src/PublicAPI.Unshipped.txt b/src/Caching/Hybrid/src/PublicAPI.Unshipped.txt index 19682fb4a0f2..abe172bda56a 100644 --- a/src/Caching/Hybrid/src/PublicAPI.Unshipped.txt +++ b/src/Caching/Hybrid/src/PublicAPI.Unshipped.txt @@ -1,34 +1,4 @@ #nullable enable -abstract Microsoft.Extensions.Caching.Hybrid.HybridCache.GetOrCreateAsync(string! key, TState state, System.Func>! factory, Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryOptions? options = null, System.Collections.Generic.IReadOnlyCollection? tags = null, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.ValueTask -abstract Microsoft.Extensions.Caching.Hybrid.HybridCache.RemoveAsync(string! key, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.ValueTask -abstract Microsoft.Extensions.Caching.Hybrid.HybridCache.RemoveByTagAsync(string! tag, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.ValueTask -abstract Microsoft.Extensions.Caching.Hybrid.HybridCache.SetAsync(string! key, T value, Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryOptions? options = null, System.Collections.Generic.IReadOnlyCollection? tags = null, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.ValueTask -Microsoft.Extensions.Caching.Distributed.IBufferDistributedCache -Microsoft.Extensions.Caching.Distributed.IBufferDistributedCache.Set(string! key, System.Buffers.ReadOnlySequence value, Microsoft.Extensions.Caching.Distributed.DistributedCacheEntryOptions! options) -> void -Microsoft.Extensions.Caching.Distributed.IBufferDistributedCache.SetAsync(string! key, System.Buffers.ReadOnlySequence value, Microsoft.Extensions.Caching.Distributed.DistributedCacheEntryOptions! options, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.ValueTask -Microsoft.Extensions.Caching.Distributed.IBufferDistributedCache.TryGet(string! key, System.Buffers.IBufferWriter! destination) -> bool -Microsoft.Extensions.Caching.Distributed.IBufferDistributedCache.TryGetAsync(string! key, System.Buffers.IBufferWriter! destination, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.ValueTask -Microsoft.Extensions.Caching.Hybrid.HybridCache -Microsoft.Extensions.Caching.Hybrid.HybridCache.GetOrCreateAsync(string! key, System.Func>! factory, Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryOptions? options = null, System.Collections.Generic.IReadOnlyCollection? tags = null, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.ValueTask -Microsoft.Extensions.Caching.Hybrid.HybridCache.HybridCache() -> void -Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags -Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags.DisableCompression = 32 -> Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags -Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags.DisableDistributedCache = Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags.DisableDistributedCacheRead | Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags.DisableDistributedCacheWrite -> Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags -Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags.DisableDistributedCacheRead = 4 -> Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags -Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags.DisableDistributedCacheWrite = 8 -> Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags -Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags.DisableLocalCache = Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags.DisableLocalCacheRead | Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags.DisableLocalCacheWrite -> Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags -Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags.DisableLocalCacheRead = 1 -> Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags -Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags.DisableLocalCacheWrite = 2 -> Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags -Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags.DisableUnderlyingData = 16 -> Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags -Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags.None = 0 -> Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags -Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryOptions -Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryOptions.Expiration.get -> System.TimeSpan? -Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryOptions.Expiration.init -> void -Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryOptions.Flags.get -> Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags? -Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryOptions.Flags.init -> void -Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryOptions.HybridCacheEntryOptions() -> void -Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryOptions.LocalCacheExpiration.get -> System.TimeSpan? -Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryOptions.LocalCacheExpiration.init -> void Microsoft.Extensions.Caching.Hybrid.HybridCacheOptions Microsoft.Extensions.Caching.Hybrid.HybridCacheOptions.DefaultEntryOptions.get -> Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryOptions? Microsoft.Extensions.Caching.Hybrid.HybridCacheOptions.DefaultEntryOptions.set -> void @@ -43,11 +13,6 @@ Microsoft.Extensions.Caching.Hybrid.HybridCacheOptions.ReportTagMetrics.get -> b Microsoft.Extensions.Caching.Hybrid.HybridCacheOptions.ReportTagMetrics.set -> void Microsoft.Extensions.Caching.Hybrid.IHybridCacheBuilder Microsoft.Extensions.Caching.Hybrid.IHybridCacheBuilder.Services.get -> Microsoft.Extensions.DependencyInjection.IServiceCollection! -Microsoft.Extensions.Caching.Hybrid.IHybridCacheSerializer -Microsoft.Extensions.Caching.Hybrid.IHybridCacheSerializer.Deserialize(System.Buffers.ReadOnlySequence source) -> T -Microsoft.Extensions.Caching.Hybrid.IHybridCacheSerializer.Serialize(T value, System.Buffers.IBufferWriter! target) -> void -Microsoft.Extensions.Caching.Hybrid.IHybridCacheSerializerFactory -Microsoft.Extensions.Caching.Hybrid.IHybridCacheSerializerFactory.TryCreateSerializer(out Microsoft.Extensions.Caching.Hybrid.IHybridCacheSerializer? serializer) -> bool Microsoft.Extensions.DependencyInjection.HybridCacheBuilderExtensions Microsoft.Extensions.DependencyInjection.HybridCacheServiceExtensions static Microsoft.Extensions.DependencyInjection.HybridCacheBuilderExtensions.AddSerializer(this Microsoft.Extensions.Caching.Hybrid.IHybridCacheBuilder! builder) -> Microsoft.Extensions.Caching.Hybrid.IHybridCacheBuilder! @@ -56,5 +21,3 @@ static Microsoft.Extensions.DependencyInjection.HybridCacheBuilderExtensions.Add static Microsoft.Extensions.DependencyInjection.HybridCacheBuilderExtensions.AddSerializerFactory(this Microsoft.Extensions.Caching.Hybrid.IHybridCacheBuilder! builder) -> Microsoft.Extensions.Caching.Hybrid.IHybridCacheBuilder! static Microsoft.Extensions.DependencyInjection.HybridCacheServiceExtensions.AddHybridCache(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.Caching.Hybrid.IHybridCacheBuilder! static Microsoft.Extensions.DependencyInjection.HybridCacheServiceExtensions.AddHybridCache(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action! setupAction) -> Microsoft.Extensions.Caching.Hybrid.IHybridCacheBuilder! -virtual Microsoft.Extensions.Caching.Hybrid.HybridCache.RemoveAsync(System.Collections.Generic.IEnumerable! keys, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.ValueTask -virtual Microsoft.Extensions.Caching.Hybrid.HybridCache.RemoveByTagAsync(System.Collections.Generic.IEnumerable! tags, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.ValueTask diff --git a/src/Caching/Hybrid/src/Runtime/HybridCache.cs b/src/Caching/Hybrid/src/Runtime/HybridCache.cs deleted file mode 100644 index 8c239c82106d..000000000000 --- a/src/Caching/Hybrid/src/Runtime/HybridCache.cs +++ /dev/null @@ -1,128 +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; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Extensions.Caching.Distributed; - -namespace Microsoft.Extensions.Caching.Hybrid; - -/// -/// Provides multi-tier caching services building on backends. -/// -public abstract class HybridCache -{ - /// - /// Asynchronously gets the value associated with the key if it exists, or generates a new entry using the provided key and a value from the given factory if the key is not found. - /// - /// The type of the data being considered. - /// The type of additional state required by . - /// The key of the entry to look for or create. - /// Provides the underlying data service is the data is not available in the cache. - /// Additional state required for . - /// Additional options for this cache entry. - /// The tags to associate with this cache item. - /// The used to propagate notifications that the operation should be canceled. - /// The data, either from cache or the underlying data service. - [System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "Delegate differences make this unambiguous")] - public abstract ValueTask GetOrCreateAsync(string key, TState state, Func> factory, - HybridCacheEntryOptions? options = null, IReadOnlyCollection? tags = null, CancellationToken token = default); - - /// - /// Asynchronously gets the value associated with the key if it exists, or generates a new entry using the provided key and a value from the given factory if the key is not found. - /// - /// The type of the data being considered. - /// The key of the entry to look for or create. - /// Provides the underlying data service is the data is not available in the cache. - /// Additional options for this cache entry. - /// The tags to associate with this cache item. - /// The used to propagate notifications that the operation should be canceled. - /// The data, either from cache or the underlying data service. - [System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "Delegate differences make this unambiguous")] - public ValueTask GetOrCreateAsync(string key, Func> factory, - HybridCacheEntryOptions? options = null, IReadOnlyCollection? tags = null, CancellationToken token = default) - => GetOrCreateAsync(key, factory, WrappedCallbackCache.Instance, options, tags, token); - - private static class WrappedCallbackCache // per-T memoized helper that allows GetOrCreateAsync and GetOrCreateAsync to share an implementation - { - // for the simple usage scenario (no TState), pack the original callback as the "state", and use a wrapper function that just unrolls and invokes from the state - public static readonly Func>, CancellationToken, ValueTask> Instance = static (callback, ct) => callback(ct); - } - - /// - /// Asynchronously sets or overwrites the value associated with the key. - /// - /// The type of the data being considered. - /// The key of the entry to create. - /// The value to assign for this cache entry. - /// Additional options for this cache entry. - /// The tags to associate with this cache entry. - /// The used to propagate notifications that the operation should be canceled. - public abstract ValueTask SetAsync(string key, T value, HybridCacheEntryOptions? options = null, IReadOnlyCollection? tags = null, CancellationToken token = default); - - /// - /// Asynchronously removes the value associated with the key if it exists. - /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "Not ambiguous in context")] - public abstract ValueTask RemoveAsync(string key, CancellationToken token = default); - - /// - /// Asynchronously removes the value associated with the key if it exists. - /// - /// Implementors should treat null as empty - [System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "Not ambiguous in context")] - public virtual ValueTask RemoveAsync(IEnumerable keys, CancellationToken token = default) - { - return keys switch - { - // for consistency with GetOrCreate/Set: interpret null as "none" - null or ICollection { Count: 0 } => default, - ICollection { Count: 1 } => RemoveAsync(keys.Single(), token), - _ => ForEachAsync(this, keys, token), - }; - - // default implementation is to call RemoveKeyAsync for each key in turn - static async ValueTask ForEachAsync(HybridCache @this, IEnumerable keys, CancellationToken token) - { - foreach (var key in keys) - { - await @this.RemoveAsync(key, token).ConfigureAwait(false); - } - } - } - - /// - /// Asynchronously removes all values associated with the specified tags. - /// - /// Implementors should treat null as empty - [System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "Not ambiguous in context")] - public virtual ValueTask RemoveByTagAsync(IEnumerable tags, CancellationToken token = default) - { - return tags switch - { - // for consistency with GetOrCreate/Set: interpret null as "none" - null or ICollection { Count: 0 } => default, - ICollection { Count: 1 } => RemoveByTagAsync(tags.Single(), token), - _ => ForEachAsync(this, tags, token), - }; - - // default implementation is to call RemoveTagAsync for each key in turn - static async ValueTask ForEachAsync(HybridCache @this, IEnumerable keys, CancellationToken token) - { - foreach (var key in keys) - { - await @this.RemoveByTagAsync(key, token).ConfigureAwait(false); - } - } - } - - /// - /// Asynchronously removes all values associated with the specified tag. - /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "Not ambiguous in context")] - public abstract ValueTask RemoveByTagAsync(string tag, CancellationToken token = default); -} diff --git a/src/Caching/Hybrid/src/Runtime/HybridCacheEntryFlags.cs b/src/Caching/Hybrid/src/Runtime/HybridCacheEntryFlags.cs deleted file mode 100644 index b6a51b11691f..000000000000 --- a/src/Caching/Hybrid/src/Runtime/HybridCacheEntryFlags.cs +++ /dev/null @@ -1,50 +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; - -namespace Microsoft.Extensions.Caching.Hybrid; - -/// -/// Additional flags that apply to a operation. -/// -[Flags] -public enum HybridCacheEntryFlags -{ - /// - /// No additional flags. - /// - None = 0, - /// - /// Disables reading from the local in-process cache. - /// - DisableLocalCacheRead = 1 << 0, - /// - /// Disables writing to the local in-process cache. - /// - DisableLocalCacheWrite = 1 << 1, - /// - /// Disables both reading from and writing to the local in-process cache. - /// - DisableLocalCache = DisableLocalCacheRead | DisableLocalCacheWrite, - /// - /// Disables reading from the secondary distributed cache. - /// - DisableDistributedCacheRead = 1 << 2, - /// - /// Disables writing to the secondary distributed cache. - /// - DisableDistributedCacheWrite = 1 << 3, - /// - /// Disables both reading from and writing to the secondary distributed cache. - /// - DisableDistributedCache = DisableDistributedCacheRead | DisableDistributedCacheWrite, - /// - /// Only fetches the value from cache; does not attempt to access the underlying data store. - /// - DisableUnderlyingData = 1 << 4, - /// - /// Disables compression for this payload. - /// - DisableCompression = 1 << 5, -} diff --git a/src/Caching/Hybrid/src/Runtime/HybridCacheEntryOptions.cs b/src/Caching/Hybrid/src/Runtime/HybridCacheEntryOptions.cs deleted file mode 100644 index e5fd18b00699..000000000000 --- a/src/Caching/Hybrid/src/Runtime/HybridCacheEntryOptions.cs +++ /dev/null @@ -1,38 +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; -using Microsoft.Extensions.Caching.Distributed; - -namespace Microsoft.Extensions.Caching.Hybrid; - -/// -/// Additional options (expiration, etc.) that apply to a operation. When options -/// can be specified at multiple levels (for example, globally and per-call), the values are composed; the -/// most granular non-null value is used, with null values being inherited. If no value is specified at -/// any level, the implementation may choose a reasonable default. -/// -public sealed class HybridCacheEntryOptions -{ - /// - /// Overall cache duration of this entry, passed to the backend distributed cache. - /// - public TimeSpan? Expiration { get; init; } // overall cache duration - - /// - /// Cache duration in local cache; when retrieving a cached value - /// from an external cache store, this value will be used to calculate the local - /// cache expiration, not exceeding the remaining overall cache lifetime. - /// - public TimeSpan? LocalCacheExpiration { get; init; } // TTL in L1 - - /// - /// Additional flags that apply to this usage. - /// - public HybridCacheEntryFlags? Flags { get; init; } - - // memoize when possible - private DistributedCacheEntryOptions? _dc; - internal DistributedCacheEntryOptions? ToDistributedCacheEntryOptions() - => Expiration is null ? null : (_dc ??= new() { AbsoluteExpirationRelativeToNow = Expiration }); -} diff --git a/src/Caching/Hybrid/src/Runtime/IBufferDistributedCache.cs b/src/Caching/Hybrid/src/Runtime/IBufferDistributedCache.cs deleted file mode 100644 index 994d52766a9d..000000000000 --- a/src/Caching/Hybrid/src/Runtime/IBufferDistributedCache.cs +++ /dev/null @@ -1,52 +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.Buffers; -using System.Threading; -using System.Threading.Tasks; - -namespace Microsoft.Extensions.Caching.Distributed; // intentional for parity with IDistributedCache - -/// -/// Represents a distributed cache of serialized values, with support for low allocation data transfer. -/// -public interface IBufferDistributedCache : IDistributedCache -{ - /// - /// Attempt to retrieve an existing cache item. - /// - /// The unique key for the cache item. - /// The target to write the cache contents on success. - /// true if the cache item is found, false otherwise. - /// This is functionally similar to , but avoids the array allocation. - bool TryGet(string key, IBufferWriter destination); - - /// - /// Asynchronously attempt to retrieve an existing cache entry. - /// - /// The unique key for the cache entry. - /// The target to write the cache contents on success. - /// The used to propagate notifications that the operation should be canceled. - /// true if the cache entry is found, false otherwise. - /// This is functionally similar to , but avoids the array allocation. - ValueTask TryGetAsync(string key, IBufferWriter destination, CancellationToken token = default); - - /// - /// Sets or overwrites a cache item. - /// - /// The key of the entry to create. - /// The value for this cache entry. - /// The cache options for the entry. - /// This is functionally similar to , but avoids the array allocation. - void Set(string key, ReadOnlySequence value, DistributedCacheEntryOptions options); - - /// - /// Asynchronously sets or overwrites a cache entry. - /// - /// The key of the entry to create. - /// The value for this cache entry. - /// The cache options for the value. - /// The used to propagate notifications that the operation should be canceled. - /// This is functionally similar to , but avoids the array allocation. - ValueTask SetAsync(string key, ReadOnlySequence value, DistributedCacheEntryOptions options, CancellationToken token = default); -} diff --git a/src/Caching/Hybrid/src/Runtime/IHybridCacheSerializer.cs b/src/Caching/Hybrid/src/Runtime/IHybridCacheSerializer.cs deleted file mode 100644 index f5c869a71772..000000000000 --- a/src/Caching/Hybrid/src/Runtime/IHybridCacheSerializer.cs +++ /dev/null @@ -1,24 +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.Buffers; - -namespace Microsoft.Extensions.Caching.Hybrid; - -/// -/// Per-type serialization/deserialization support for . -/// -/// The type being serialized/deserialized. -public interface IHybridCacheSerializer -{ - /// - /// Deserialize a value from the provided . - /// - T Deserialize(ReadOnlySequence source); - - /// - /// Serialize , writing to the provided . - /// - void Serialize(T value, IBufferWriter target); -} - diff --git a/src/Caching/Hybrid/src/Runtime/IHybridCacheSerializerFactory.cs b/src/Caching/Hybrid/src/Runtime/IHybridCacheSerializerFactory.cs deleted file mode 100644 index d500ddfb2ba9..000000000000 --- a/src/Caching/Hybrid/src/Runtime/IHybridCacheSerializerFactory.cs +++ /dev/null @@ -1,20 +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.Diagnostics.CodeAnalysis; - -namespace Microsoft.Extensions.Caching.Hybrid; - -/// -/// Factory provider for per-type instances. -/// -public interface IHybridCacheSerializerFactory -{ - /// - /// Request a serializer for the provided type, if possible. - /// - /// The type being serialized/deserialized. - /// The serializer. - /// true if the factory supports this type, false otherwise. - bool TryCreateSerializer([NotNullWhen(true)] out IHybridCacheSerializer? serializer); -} diff --git a/src/Caching/Hybrid/src/Runtime/readme.md b/src/Caching/Hybrid/src/Runtime/readme.md deleted file mode 100644 index 1e2289449f0b..000000000000 --- a/src/Caching/Hybrid/src/Runtime/readme.md +++ /dev/null @@ -1,2 +0,0 @@ -These types are intended to be added to be relocated to `Microsoft.Extensions.Caching.Abstractions`; their inclusion -here is a preview placeholder diff --git a/src/Caching/Hybrid/test/L2Tests.cs b/src/Caching/Hybrid/test/L2Tests.cs index 6fd77c0707a6..378e5c8ed4ba 100644 --- a/src/Caching/Hybrid/test/L2Tests.cs +++ b/src/Caching/Hybrid/test/L2Tests.cs @@ -38,7 +38,9 @@ static string CreateString(bool work = false) return Guid.NewGuid().ToString(); } - static readonly HybridCacheEntryOptions _noL1 = new() { Flags = HybridCacheEntryFlags.DisableLocalCache }; + private static readonly HybridCacheEntryOptions Expiry = new() { Expiration = TimeSpan.FromMinutes(3.5) }; + + private static readonly HybridCacheEntryOptions ExpiryNoL1 = new() { Flags = HybridCacheEntryFlags.DisableLocalCache, Expiration = TimeSpan.FromMinutes(3.5) }; [Theory] [InlineData(true)] @@ -63,7 +65,7 @@ public async Task AssertL2Operations_Immutable(bool buffers) Log.WriteLine("Reading without L1..."); for (var i = 0; i < 5; i++) { - var x = await cache.GetOrCreateAsync(Me(), ct => new ValueTask(CreateString()), _noL1); + var x = await cache.GetOrCreateAsync(Me(), ct => new ValueTask(CreateString()), ExpiryNoL1); Assert.Equal(s, x); Assert.NotSame(s, x); } @@ -103,13 +105,13 @@ public async Task AssertL2Operations_Mutable(bool buffers) using var provider = GetDefaultCache(buffers, out var cache); var backend = Assert.IsAssignableFrom(cache.BackendCache); Log.WriteLine("Inventing key..."); - var s = await cache.GetOrCreateAsync(Me(), ct => new ValueTask(new Foo { Value = CreateString(true) })); + var s = await cache.GetOrCreateAsync(Me(), ct => new ValueTask(new Foo { Value = CreateString(true) }), Expiry); Assert.Equal(2, backend.OpCount); // GET, SET Log.WriteLine("Reading with L1..."); for (var i = 0; i < 5; i++) { - var x = await cache.GetOrCreateAsync(Me(), ct => new ValueTask(new Foo { Value = CreateString() })); + var x = await cache.GetOrCreateAsync(Me(), ct => new ValueTask(new Foo { Value = CreateString() }), Expiry); Assert.Equal(s.Value, x.Value); Assert.NotSame(s, x); } @@ -118,7 +120,7 @@ public async Task AssertL2Operations_Mutable(bool buffers) Log.WriteLine("Reading without L1..."); for (var i = 0; i < 5; i++) { - var x = await cache.GetOrCreateAsync(Me(), ct => new ValueTask(new Foo { Value = CreateString() }), _noL1); + var x = await cache.GetOrCreateAsync(Me(), ct => new ValueTask(new Foo { Value = CreateString() }), ExpiryNoL1); Assert.Equal(s.Value, x.Value); Assert.NotSame(s, x); } @@ -129,7 +131,7 @@ public async Task AssertL2Operations_Mutable(bool buffers) await cache.SetAsync(Me(), s); for (var i = 0; i < 5; i++) { - var x = await cache.GetOrCreateAsync(Me(), ct => new ValueTask(new Foo { Value = CreateString() })); + var x = await cache.GetOrCreateAsync(Me(), ct => new ValueTask(new Foo { Value = CreateString() }), Expiry); Assert.Equal(s.Value, x.Value); Assert.NotSame(s, x); } @@ -140,7 +142,7 @@ public async Task AssertL2Operations_Mutable(bool buffers) Assert.Equal(9, backend.OpCount); // DEL Log.WriteLine("Fetching new..."); - var t = await cache.GetOrCreateAsync(Me(), ct => new ValueTask(new Foo { Value = CreateString(true) })); + var t = await cache.GetOrCreateAsync(Me(), ct => new ValueTask(new Foo { Value = CreateString(true) }), Expiry); Assert.NotEqual(s.Value, t.Value); Assert.Equal(11, backend.OpCount); // GET, SET } diff --git a/src/Caching/Hybrid/test/Microsoft.Extensions.Caching.Hybrid.Tests.csproj b/src/Caching/Hybrid/test/Microsoft.Extensions.Caching.Hybrid.Tests.csproj index 54c0de3adf67..4b862961ffa3 100644 --- a/src/Caching/Hybrid/test/Microsoft.Extensions.Caching.Hybrid.Tests.csproj +++ b/src/Caching/Hybrid/test/Microsoft.Extensions.Caching.Hybrid.Tests.csproj @@ -7,6 +7,7 @@ + diff --git a/src/Caching/Hybrid/test/SampleUsage.cs b/src/Caching/Hybrid/test/SampleUsage.cs index 8d65d5aeff9f..78786a8b8877 100644 --- a/src/Caching/Hybrid/test/SampleUsage.cs +++ b/src/Caching/Hybrid/test/SampleUsage.cs @@ -121,7 +121,7 @@ public async Task GetSomeInformationAsync(string name, int id, return await cache.GetOrCreateAsync( $"someinfo:{name}:{id}", // unique key for this combination async ct => await SomeExpensiveOperationAsync(name, id, ct), - token: token + cancellationToken: token ); } } @@ -147,7 +147,7 @@ public async Task GetSomeInformationAsync(string name, int id, (name, id), // all of the state we need for the final call, if needed static async (state, token) => await SomeExpensiveOperationAsync(state.name, state.id, token), - token: token + cancellationToken: token ); } } @@ -161,7 +161,7 @@ public async Task GetSomeInformationAsync(string name, int (name, id), // all of the state we need for the final call, if needed static async (state, token) => await SomeExpensiveOperationReuseAsync(state.name, state.id, token), - token: token + cancellationToken: token ); } } diff --git a/src/Caching/Hybrid/test/StampedeTests.cs b/src/Caching/Hybrid/test/StampedeTests.cs index 6fd4bab51f91..bfd777954566 100644 --- a/src/Caching/Hybrid/test/StampedeTests.cs +++ b/src/Caching/Hybrid/test/StampedeTests.cs @@ -87,7 +87,7 @@ public async Task MultipleCallsShareExecution_NoCancellation(int callerCount, bo Interlocked.Increment(ref executeCount); ct.ThrowIfCancellationRequested(); // assert not cancelled return Guid.NewGuid(); - }, token: token).AsTask(); + }, cancellationToken: token).AsTask(); } Assert.Equal(callerCount, cache.DebugGetCallerCount(Me())); @@ -121,7 +121,7 @@ public async Task MultipleCallsShareExecution_NoCancellation(int callerCount, bo Interlocked.Increment(ref executeCount); ct.ThrowIfCancellationRequested(); // assert not cancelled return Guid.NewGuid(); - }, token: token).AsTask(); + }, cancellationToken: token).AsTask(); } Assert.Equal(callerCount, cache.DebugGetCallerCount(Me())); @@ -178,7 +178,7 @@ public async Task MultipleCallsShareExecution_EveryoneCancels(int callerCount) { semaphore.Release(); // handshake so we can check when available again } - }, token: cancels[i].Token).AsTask(); + }, cancellationToken: cancels[i].Token).AsTask(); } Assert.Equal(callerCount, cache.DebugGetCallerCount(Me())); @@ -250,7 +250,7 @@ public async Task MultipleCallsShareExecution_MostCancel(int callerCount, int re { semaphore.Release(); // handshake so we can check when available again } - }, token: cancels[i].Token).AsTask(); + }, cancellationToken: cancels[i].Token).AsTask(); } Assert.Equal(callerCount, cache.DebugGetCallerCount(Me())); @@ -299,8 +299,8 @@ public async Task ImmutableTypesShareFinalTask(bool withCancelation) using var semaphore = new SemaphoreSlim(0); // note AsTask *in this scenario* fetches the underlying incomplete task - var first = cache.GetOrCreateAsync(Me(), async ct => { await semaphore.WaitAsync(CancellationToken.None); semaphore.Release(); return Guid.NewGuid(); }, token: token).AsTask(); - var second = cache.GetOrCreateAsync(Me(), async ct => { await semaphore.WaitAsync(CancellationToken.None); semaphore.Release(); return Guid.NewGuid(); }, token: token).AsTask(); + var first = cache.GetOrCreateAsync(Me(), async ct => { await semaphore.WaitAsync(CancellationToken.None); semaphore.Release(); return Guid.NewGuid(); }, cancellationToken: token).AsTask(); + var second = cache.GetOrCreateAsync(Me(), async ct => { await semaphore.WaitAsync(CancellationToken.None); semaphore.Release(); return Guid.NewGuid(); }, cancellationToken: token).AsTask(); if (withCancelation) { @@ -325,8 +325,8 @@ public async Task ImmutableCustomTypesShareFinalTask(bool withCancelation) using var semaphore = new SemaphoreSlim(0); // AsTask *in this scenario* fetches the underlying incomplete task - var first = cache.GetOrCreateAsync(Me(), async ct => { await semaphore.WaitAsync(CancellationToken.None); semaphore.Release(); return new Immutable(Guid.NewGuid()); }, token: token).AsTask(); - var second = cache.GetOrCreateAsync(Me(), async ct => { await semaphore.WaitAsync(CancellationToken.None); semaphore.Release(); return new Immutable(Guid.NewGuid()); }, token: token).AsTask(); + var first = cache.GetOrCreateAsync(Me(), async ct => { await semaphore.WaitAsync(CancellationToken.None); semaphore.Release(); return new Immutable(Guid.NewGuid()); }, cancellationToken: token).AsTask(); + var second = cache.GetOrCreateAsync(Me(), async ct => { await semaphore.WaitAsync(CancellationToken.None); semaphore.Release(); return new Immutable(Guid.NewGuid()); }, cancellationToken: token).AsTask(); if (withCancelation) { @@ -355,8 +355,8 @@ public async Task MutableTypesNeverShareFinalTask(bool withCancelation) using var semaphore = new SemaphoreSlim(0); // AsTask *in this scenario* fetches the underlying incomplete task - var first = cache.GetOrCreateAsync(Me(), async ct => { await semaphore.WaitAsync(CancellationToken.None); semaphore.Release(); return new Mutable(Guid.NewGuid()); }, token: token).AsTask(); - var second = cache.GetOrCreateAsync(Me(), async ct => { await semaphore.WaitAsync(CancellationToken.None); semaphore.Release(); return new Mutable(Guid.NewGuid()); }, token: token).AsTask(); + var first = cache.GetOrCreateAsync(Me(), async ct => { await semaphore.WaitAsync(CancellationToken.None); semaphore.Release(); return new Mutable(Guid.NewGuid()); }, cancellationToken: token).AsTask(); + var second = cache.GetOrCreateAsync(Me(), async ct => { await semaphore.WaitAsync(CancellationToken.None); semaphore.Release(); return new Mutable(Guid.NewGuid()); }, cancellationToken: token).AsTask(); Assert.NotSame(first, second); semaphore.Release(); diff --git a/src/Caching/SqlServer/src/Microsoft.Extensions.Caching.SqlServer.csproj b/src/Caching/SqlServer/src/Microsoft.Extensions.Caching.SqlServer.csproj index 21c98b778833..3088ff699532 100644 --- a/src/Caching/SqlServer/src/Microsoft.Extensions.Caching.SqlServer.csproj +++ b/src/Caching/SqlServer/src/Microsoft.Extensions.Caching.SqlServer.csproj @@ -20,9 +20,6 @@ - - - diff --git a/src/Caching/StackExchangeRedis/src/Microsoft.Extensions.Caching.StackExchangeRedis.csproj b/src/Caching/StackExchangeRedis/src/Microsoft.Extensions.Caching.StackExchangeRedis.csproj index 3a3faeaf9f40..c3f7de250341 100644 --- a/src/Caching/StackExchangeRedis/src/Microsoft.Extensions.Caching.StackExchangeRedis.csproj +++ b/src/Caching/StackExchangeRedis/src/Microsoft.Extensions.Caching.StackExchangeRedis.csproj @@ -15,9 +15,6 @@ - - - diff --git a/src/Caching/perf/MicroBenchmarks/Microsoft.Extensions.Caching.MicroBenchmarks/Microsoft.Extensions.Caching.MicroBenchmarks.csproj b/src/Caching/perf/MicroBenchmarks/Microsoft.Extensions.Caching.MicroBenchmarks/Microsoft.Extensions.Caching.MicroBenchmarks.csproj index 50b8df19317e..f58d80e677d6 100644 --- a/src/Caching/perf/MicroBenchmarks/Microsoft.Extensions.Caching.MicroBenchmarks/Microsoft.Extensions.Caching.MicroBenchmarks.csproj +++ b/src/Caching/perf/MicroBenchmarks/Microsoft.Extensions.Caching.MicroBenchmarks/Microsoft.Extensions.Caching.MicroBenchmarks.csproj @@ -12,6 +12,7 @@ + @@ -23,4 +24,4 @@ - \ No newline at end of file + diff --git a/src/Components/Components/src/BindConverter.cs b/src/Components/Components/src/BindConverter.cs index 4ef49ba91a05..06a03a05f390 100644 --- a/src/Components/Components/src/BindConverter.cs +++ b/src/Components/Components/src/BindConverter.cs @@ -1677,6 +1677,10 @@ private static class FormatterDelegateCache "ReflectionAnalysis", "IL2075:MakeGenericMethod", Justification = "The referenced methods don't have any DynamicallyAccessedMembers annotations. See https://github.com/mono/linker/issues/1727")] + [UnconditionalSuppressMessage( + "ReflectionAnalysis", + "IL2076:MakeGenericMethod", + Justification = "The referenced methods don't have any DynamicallyAccessedMembers annotations. See https://github.com/mono/linker/issues/1727")] public static BindFormatter Get<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>() { if (!_cache.TryGetValue(typeof(T), out var formatter)) @@ -1864,6 +1868,10 @@ internal static class ParserDelegateCache "ReflectionAnalysis", "IL2075:MakeGenericMethod", Justification = "The referenced methods don't have any DynamicallyAccessedMembers annotations. See https://github.com/mono/linker/issues/1727")] + [UnconditionalSuppressMessage( + "ReflectionAnalysis", + "IL2076:MakeGenericMethod", + Justification = "The referenced methods don't have any DynamicallyAccessedMembers annotations. See https://github.com/mono/linker/issues/1727")] public static BindParser Get<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>() { if (!_cache.TryGetValue(typeof(T), out var parser)) diff --git a/src/Components/test/E2ETest/Tests/BootResourceCachingTest.cs b/src/Components/test/E2ETest/Tests/BootResourceCachingTest.cs index c22f3217a37b..544e588d5f4c 100644 --- a/src/Components/test/E2ETest/Tests/BootResourceCachingTest.cs +++ b/src/Components/test/E2ETest/Tests/BootResourceCachingTest.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.RegularExpressions; using HostedInAspNet.Server; using Microsoft.AspNetCore.Components.E2ETest.Infrastructure; using Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures; @@ -15,7 +16,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests; // Disabling parallelism for these tests because of flakiness [CollectionDefinition(nameof(BootResourceCachingTest), DisableParallelization = true)] [Collection(nameof(BootResourceCachingTest))] -public class BootResourceCachingTest +public partial class BootResourceCachingTest : ServerTestBase { // The cache name is derived from the application's base href value (in this case, '/') @@ -43,21 +44,29 @@ public void CachesResourcesAfterFirstLoad() WaitUntilLoaded(); var initialResourcesRequested = GetAndClearRequestedPaths(); Assert.NotEmpty(initialResourcesRequested.Where(path => path.EndsWith("/blazor.boot.json", StringComparison.Ordinal))); - Assert.NotEmpty(initialResourcesRequested.Where(path => path.EndsWith("/dotnet.native.wasm", StringComparison.Ordinal))); + Assert.NotEmpty(initialResourcesRequested.Where(path => + path.Contains("/dotnet.native.", StringComparison.Ordinal) && + path.EndsWith(".wasm", StringComparison.Ordinal))); Assert.NotEmpty(initialResourcesRequested.Where(path => path.EndsWith(".js", StringComparison.Ordinal))); - Assert.NotEmpty(initialResourcesRequested.Where(path => path.EndsWith(".wasm", StringComparison.Ordinal))); + Assert.NotEmpty(initialResourcesRequested.Where(path => + !path.Contains("/dotnet.native.", StringComparison.Ordinal) && + path.EndsWith(".wasm", StringComparison.Ordinal))); // On subsequent loads, we skip the items referenced from blazor.boot.json - // which includes .wasm (original .dll) files and dotnet.native.wasm + // which includes .wasm (original .dll) files and dotnet.native.[fingerprint].wasm Navigate("about:blank"); Browser.Equal(string.Empty, () => Browser.Title); Navigate("/"); WaitUntilLoaded(); var subsequentResourcesRequested = GetAndClearRequestedPaths(); Assert.NotEmpty(initialResourcesRequested.Where(path => path.EndsWith("/blazor.boot.json", StringComparison.Ordinal))); - Assert.Empty(subsequentResourcesRequested.Where(path => path.EndsWith("/dotnet.native.wasm", StringComparison.Ordinal))); + Assert.Empty(subsequentResourcesRequested.Where(path => + path.Contains("/dotnet.native.", StringComparison.Ordinal) && + path.EndsWith(".wasm", StringComparison.Ordinal))); Assert.NotEmpty(subsequentResourcesRequested.Where(path => path.EndsWith(".js", StringComparison.Ordinal))); - Assert.Empty(subsequentResourcesRequested.Where(path => path.EndsWith(".wasm", StringComparison.Ordinal) && !path.EndsWith("/dotnet.native.wasm", StringComparison.Ordinal))); + Assert.Empty(subsequentResourcesRequested.Where(path => + !path.Contains("/dotnet.native.", StringComparison.Ordinal) && + path.EndsWith(".wasm", StringComparison.Ordinal))); } [Fact] @@ -67,8 +76,8 @@ public async Task IncrementallyUpdatesCache() Navigate("/"); WaitUntilLoaded(); var cacheEntryUrls1 = GetCacheEntryUrls(); - var cacheEntryForComponentsDll = cacheEntryUrls1.Single(url => url.Contains("/Microsoft.AspNetCore.Components.wasm")); - var cacheEntryForDotNetWasm = cacheEntryUrls1.Single(url => url.Contains("/dotnet.native.wasm")); + var cacheEntryForComponentsDll = cacheEntryUrls1.Single(IsFingerprintedComponentsEntry); + var cacheEntryForDotNetWasm = cacheEntryUrls1.Single(IsFingerprintedDotNetWasmEntry); var cacheEntryForDotNetWasmWithChangedHash = cacheEntryForDotNetWasm.Replace(".sha256-", ".sha256-different"); // Remove some items we do need, and add an item we don't need @@ -88,8 +97,8 @@ public async Task IncrementallyUpdatesCache() WaitUntilLoaded(); var subsequentResourcesRequested = GetAndClearRequestedPaths(); Assert.Collection(subsequentResourcesRequested.Where(url => url.Contains(".wasm")), - requestedDll => Assert.Contains("/Microsoft.AspNetCore.Components.wasm", requestedDll), - requestedDll => Assert.Contains("/dotnet.native.wasm", requestedDll)); + requestedDll => Assert.True(IsFingerprintedComponentsEntry(requestedDll)), + requestedDll => Assert.True(IsFingerprintedDotNetWasmEntry(requestedDll))); var cacheEntryUrls3 = GetCacheEntryUrls(); // wait until the cache was cleaned, max 500ms @@ -107,6 +116,18 @@ public async Task IncrementallyUpdatesCache() Assert.DoesNotContain(cacheEntryForDotNetWasmWithChangedHash, cacheEntryUrls3); } + [GeneratedRegex("/Microsoft\\.AspNetCore\\.Components\\.\\w*\\.wasm")] + private static partial Regex GetFingerprintedComponentsEntryRegex(); + + [GeneratedRegex("/dotnet\\.native\\.\\w*\\.wasm")] + private static partial Regex GetFingerprintedDotNetWasmEntryRegex(); + + private static bool IsFingerprintedComponentsEntry(string url) + => GetFingerprintedComponentsEntryRegex().IsMatch(url); + + private static bool IsFingerprintedDotNetWasmEntry(string url) + => GetFingerprintedDotNetWasmEntryRegex().IsMatch(url); + private IReadOnlyCollection GetCacheEntryUrls() { var js = @" diff --git a/src/Components/test/E2ETest/Tests/WebAssemblyLazyLoadTest.cs b/src/Components/test/E2ETest/Tests/WebAssemblyLazyLoadTest.cs index 52366ae76f7b..9d3a67d48eba 100644 --- a/src/Components/test/E2ETest/Tests/WebAssemblyLazyLoadTest.cs +++ b/src/Components/test/E2ETest/Tests/WebAssemblyLazyLoadTest.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.RegularExpressions; using BasicTestApp; using BasicTestApp.RouterTest; using Microsoft.AspNetCore.Components.E2ETest.Infrastructure; @@ -46,7 +47,7 @@ public void CanLazyLoadOnRouteChange() var app = Browser.MountTestComponent(); // Ensure that we haven't requested the lazy loaded assembly - Assert.False(HasLoadedAssembly("Newtonsoft.Json.wasm")); + Assert.False(HasLoadedFingerprintedAssembly("Newtonsoft.Json", ".wasm")); CleanPerfEntries(); @@ -56,7 +57,7 @@ public void CanLazyLoadOnRouteChange() var button = Browser.Exists(By.Id("use-package-button")); // Now we should have requested the DLL - Assert.True(HasLoadedAssembly("Newtonsoft.Json.wasm")); + Assert.True(HasLoadedFingerprintedAssembly("Newtonsoft.Json", ".wasm")); button.Click(); @@ -75,7 +76,7 @@ public void CanLazyLoadOnFirstVisit() var button = Browser.Exists(By.Id("use-package-button")); // We should have requested the DLL - Assert.True(HasLoadedAssembly("Newtonsoft.Json.wasm")); + Assert.True(HasLoadedFingerprintedAssembly("Newtonsoft.Json", ".wasm")); button.Click(); @@ -91,8 +92,8 @@ public void CanLazyLoadAssemblyWithRoutes() var app = Browser.MountTestComponent(); // Ensure that we haven't requested the lazy loaded assembly or its PDB - Assert.False(HasLoadedAssembly("LazyTestContentPackage.wasm")); - Assert.False(HasLoadedAssembly("LazyTestContentPackage.pdb")); + Assert.False(HasLoadedFingerprintedAssembly("LazyTestContentPackage", ".wasm")); + Assert.False(HasLoadedFingerprintedAssembly("LazyTestContentPackage", ".pdb")); CleanPerfEntries(); @@ -103,7 +104,7 @@ public void CanLazyLoadAssemblyWithRoutes() Browser.Exists(By.Id("lazy-load-msg")); // Now the assembly has been loaded - Assert.True(HasLoadedAssembly("LazyTestContentPackage.wasm")); + Assert.True(HasLoadedFingerprintedAssembly("LazyTestContentPackage", ".wasm")); var button = Browser.Exists(By.Id("go-to-lazy-route")); button.Click(); @@ -138,8 +139,8 @@ public void CanLazyLoadViaLinkChange() var app = Browser.MountTestComponent(); // We start off with no lazy assemblies loaded - Assert.False(HasLoadedAssembly("LazyTestContentPackage.wasm")); - Assert.False(HasLoadedAssembly("Newtonsoft.Json.wasm")); + Assert.False(HasLoadedFingerprintedAssembly("LazyTestContentPackage", ".wasm")); + Assert.False(HasLoadedFingerprintedAssembly("Newtonsoft.Json", ".wasm")); CleanPerfEntries(); @@ -147,14 +148,14 @@ public void CanLazyLoadViaLinkChange() var lazyAssemblyLink = Browser.Exists(By.Id("with-lazy-assembly")); lazyAssemblyLink.Click(); var pkgButton = Browser.Exists(By.Id("use-package-button")); - Assert.True(HasLoadedAssembly("Newtonsoft.Json.wasm")); + Assert.True(HasLoadedFingerprintedAssembly("Newtonsoft.Json", ".wasm")); pkgButton.Click(); // Navigate to the next page and verify that it loaded its assembly var lazyRoutesLink = Browser.Exists(By.Id("with-lazy-routes")); lazyRoutesLink.Click(); Browser.Exists(By.Id("lazy-load-msg")); - Assert.True(HasLoadedAssembly("LazyTestContentPackage.wasm")); + Assert.True(HasLoadedFingerprintedAssembly("LazyTestContentPackage", ".wasm")); // Interact with that assembly to ensure it was loaded properly var button = Browser.Exists(By.Id("go-to-lazy-route")); @@ -175,9 +176,11 @@ private string SetUrlViaPushState(string relativeUri) return absoluteUri.AbsoluteUri; } - private bool HasLoadedAssembly(string name) + private bool HasLoadedFingerprintedAssembly(string name, string extension) { - var checkScript = $"return window.performance.getEntriesByType('resource').some(r => r.name.endsWith('{name}'));"; + var namePattern = Regex.Escape(name); + var extensionPattern = Regex.Escape(extension); + var checkScript = $"return window.performance.getEntriesByType('resource').some(r => /{namePattern}\\.\\w*{extensionPattern}/g.test(r.name))"; var jsExecutor = (IJavaScriptExecutor)Browser; var nameRequested = jsExecutor.ExecuteScript(checkScript); if (nameRequested != null)