Skip to content

Commit 48dd6a9

Browse files
mgravellamcaseyBrennanConroyjoegoldman2
authored
Add HybridCache public API (#55084)
* initial API cut (post review) --------- Co-authored-by: Andrew Casey <amcasey@users.noreply.github.com> Co-authored-by: Brennan <brecon@microsoft.com> Co-authored-by: joegoldman2 <147369450+joegoldman2@users.noreply.github.com>
1 parent 7412c71 commit 48dd6a9

24 files changed

+989
-0
lines changed

AspNetCore.sln

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1788,6 +1788,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NotReferencedInWasmCodePack
17881788
EndProject
17891789
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Components.WasmRemoteAuthentication", "src\Components\test\testassets\Components.WasmRemoteAuthentication\Components.WasmRemoteAuthentication.csproj", "{8A021D6D-7935-4AB3-BB47-38D4FF9B0D13}"
17901790
EndProject
1791+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Hybrid", "Hybrid", "{2D64CA23-6E81-488E-A7D3-9BDF87240098}"
1792+
EndProject
1793+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Caching.Hybrid", "src\Caching\Hybrid\src\Microsoft.Extensions.Caching.Hybrid.csproj", "{2B60E6D3-9E7C-427A-AD4E-BBE9A6D935B9}"
1794+
EndProject
1795+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Caching.Hybrid.Tests", "src\Caching\Hybrid\test\Microsoft.Extensions.Caching.Hybrid.Tests.csproj", "{CF63C942-895A-4F6B-888A-7653D7C4991A}"
1796+
EndProject
17911797
Global
17921798
GlobalSection(SolutionConfigurationPlatforms) = preSolution
17931799
Debug|Any CPU = Debug|Any CPU
@@ -10789,6 +10795,38 @@ Global
1078910795
{8A021D6D-7935-4AB3-BB47-38D4FF9B0D13}.Release|x64.Build.0 = Release|Any CPU
1079010796
{8A021D6D-7935-4AB3-BB47-38D4FF9B0D13}.Release|x86.ActiveCfg = Release|Any CPU
1079110797
{8A021D6D-7935-4AB3-BB47-38D4FF9B0D13}.Release|x86.Build.0 = Release|Any CPU
10798+
{2B60E6D3-9E7C-427A-AD4E-BBE9A6D935B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
10799+
{2B60E6D3-9E7C-427A-AD4E-BBE9A6D935B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
10800+
{2B60E6D3-9E7C-427A-AD4E-BBE9A6D935B9}.Debug|arm64.ActiveCfg = Debug|Any CPU
10801+
{2B60E6D3-9E7C-427A-AD4E-BBE9A6D935B9}.Debug|arm64.Build.0 = Debug|Any CPU
10802+
{2B60E6D3-9E7C-427A-AD4E-BBE9A6D935B9}.Debug|x64.ActiveCfg = Debug|Any CPU
10803+
{2B60E6D3-9E7C-427A-AD4E-BBE9A6D935B9}.Debug|x64.Build.0 = Debug|Any CPU
10804+
{2B60E6D3-9E7C-427A-AD4E-BBE9A6D935B9}.Debug|x86.ActiveCfg = Debug|Any CPU
10805+
{2B60E6D3-9E7C-427A-AD4E-BBE9A6D935B9}.Debug|x86.Build.0 = Debug|Any CPU
10806+
{2B60E6D3-9E7C-427A-AD4E-BBE9A6D935B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
10807+
{2B60E6D3-9E7C-427A-AD4E-BBE9A6D935B9}.Release|Any CPU.Build.0 = Release|Any CPU
10808+
{2B60E6D3-9E7C-427A-AD4E-BBE9A6D935B9}.Release|arm64.ActiveCfg = Release|Any CPU
10809+
{2B60E6D3-9E7C-427A-AD4E-BBE9A6D935B9}.Release|arm64.Build.0 = Release|Any CPU
10810+
{2B60E6D3-9E7C-427A-AD4E-BBE9A6D935B9}.Release|x64.ActiveCfg = Release|Any CPU
10811+
{2B60E6D3-9E7C-427A-AD4E-BBE9A6D935B9}.Release|x64.Build.0 = Release|Any CPU
10812+
{2B60E6D3-9E7C-427A-AD4E-BBE9A6D935B9}.Release|x86.ActiveCfg = Release|Any CPU
10813+
{2B60E6D3-9E7C-427A-AD4E-BBE9A6D935B9}.Release|x86.Build.0 = Release|Any CPU
10814+
{CF63C942-895A-4F6B-888A-7653D7C4991A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
10815+
{CF63C942-895A-4F6B-888A-7653D7C4991A}.Debug|Any CPU.Build.0 = Debug|Any CPU
10816+
{CF63C942-895A-4F6B-888A-7653D7C4991A}.Debug|arm64.ActiveCfg = Debug|Any CPU
10817+
{CF63C942-895A-4F6B-888A-7653D7C4991A}.Debug|arm64.Build.0 = Debug|Any CPU
10818+
{CF63C942-895A-4F6B-888A-7653D7C4991A}.Debug|x64.ActiveCfg = Debug|Any CPU
10819+
{CF63C942-895A-4F6B-888A-7653D7C4991A}.Debug|x64.Build.0 = Debug|Any CPU
10820+
{CF63C942-895A-4F6B-888A-7653D7C4991A}.Debug|x86.ActiveCfg = Debug|Any CPU
10821+
{CF63C942-895A-4F6B-888A-7653D7C4991A}.Debug|x86.Build.0 = Debug|Any CPU
10822+
{CF63C942-895A-4F6B-888A-7653D7C4991A}.Release|Any CPU.ActiveCfg = Release|Any CPU
10823+
{CF63C942-895A-4F6B-888A-7653D7C4991A}.Release|Any CPU.Build.0 = Release|Any CPU
10824+
{CF63C942-895A-4F6B-888A-7653D7C4991A}.Release|arm64.ActiveCfg = Release|Any CPU
10825+
{CF63C942-895A-4F6B-888A-7653D7C4991A}.Release|arm64.Build.0 = Release|Any CPU
10826+
{CF63C942-895A-4F6B-888A-7653D7C4991A}.Release|x64.ActiveCfg = Release|Any CPU
10827+
{CF63C942-895A-4F6B-888A-7653D7C4991A}.Release|x64.Build.0 = Release|Any CPU
10828+
{CF63C942-895A-4F6B-888A-7653D7C4991A}.Release|x86.ActiveCfg = Release|Any CPU
10829+
{CF63C942-895A-4F6B-888A-7653D7C4991A}.Release|x86.Build.0 = Release|Any CPU
1079210830
EndGlobalSection
1079310831
GlobalSection(SolutionProperties) = preSolution
1079410832
HideSolutionNode = FALSE
@@ -11672,6 +11710,9 @@ Global
1167211710
{15D08EA7-8C63-45FB-8B4D-C5F8E43B433E} = {05A169C7-4F20-4516-B10A-B13C5649D346}
1167311711
{433F91E4-E39D-4EB0-B798-2998B3969A2C} = {6126DCE4-9692-4EE2-B240-C65743572995}
1167411712
{8A021D6D-7935-4AB3-BB47-38D4FF9B0D13} = {6126DCE4-9692-4EE2-B240-C65743572995}
11713+
{2D64CA23-6E81-488E-A7D3-9BDF87240098} = {0F39820F-F4A5-41C6-9809-D79B68F032EF}
11714+
{2B60E6D3-9E7C-427A-AD4E-BBE9A6D935B9} = {2D64CA23-6E81-488E-A7D3-9BDF87240098}
11715+
{CF63C942-895A-4F6B-888A-7653D7C4991A} = {2D64CA23-6E81-488E-A7D3-9BDF87240098}
1167511716
EndGlobalSection
1167611717
GlobalSection(ExtensibilityGlobals) = postSolution
1167711718
SolutionGuid = {3E8720B3-DBDD-498C-B383-2CC32A054E8F}

eng/ProjectReferences.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
-->
66
<Project>
77
<ItemGroup>
8+
<ProjectReferenceProvider Include="Microsoft.Extensions.Caching.Hybrid" ProjectPath="$(RepoRoot)src\Caching\Hybrid\src\Microsoft.Extensions.Caching.Hybrid.csproj" />
89
<ProjectReferenceProvider Include="Microsoft.Extensions.Caching.SqlServer" ProjectPath="$(RepoRoot)src\Caching\SqlServer\src\Microsoft.Extensions.Caching.SqlServer.csproj" />
910
<ProjectReferenceProvider Include="Microsoft.Extensions.Caching.StackExchangeRedis" ProjectPath="$(RepoRoot)src\Caching\StackExchangeRedis\src\Microsoft.Extensions.Caching.StackExchangeRedis.csproj" />
1011
<ProjectReferenceProvider Include="Microsoft.AspNetCore" ProjectPath="$(RepoRoot)src\DefaultBuilder\src\Microsoft.AspNetCore.csproj" />

eng/ShippingAssemblies.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@
104104
<AspNetCoreShippingAssembly Include="Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions" />
105105
<AspNetCoreShippingAssembly Include="Microsoft.Extensions.Diagnostics.HealthChecks" />
106106
<AspNetCoreShippingAssembly Include="Microsoft.Extensions.Features" />
107+
<AspNetCoreShippingAssembly Include="Microsoft.Extensions.Caching.Hybrid" />
107108
<AspNetCoreShippingAssembly Include="Microsoft.Extensions.Caching.SqlServer" />
108109
<AspNetCoreShippingAssembly Include="Microsoft.Extensions.Caching.StackExchangeRedis" />
109110
<AspNetCoreShippingAssembly Include="Microsoft.AspNetCore.JsonPatch" />

src/Caching/Caching.slnf

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
"solution": {
33
"path": "..\\..\\AspNetCore.sln",
44
"projects": [
5+
"src\\Caching\\Hybrid\\src\\Microsoft.Extensions.Caching.Hybrid.csproj",
6+
"src\\Caching\\Hybrid\\test\\Microsoft.Extensions.Caching.Hybrid.Tests.csproj",
57
"src\\Caching\\SqlServer\\src\\Microsoft.Extensions.Caching.SqlServer.csproj",
68
"src\\Caching\\SqlServer\\test\\Microsoft.Extensions.Caching.SqlServer.Tests.csproj",
79
"src\\Caching\\StackExchangeRedis\\src\\Microsoft.Extensions.Caching.StackExchangeRedis.csproj",
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Diagnostics.CodeAnalysis;
7+
using System.Linq;
8+
using System.Text;
9+
using System.Threading.Tasks;
10+
using Microsoft.Extensions.DependencyInjection;
11+
12+
namespace Microsoft.Extensions.Caching.Hybrid;
13+
14+
/// <summary>
15+
/// Configuration extension methods for <see cref="IHybridCacheBuilder"/> / <see cref="HybridCache"/>.
16+
/// </summary>
17+
public static class HybridCacheBuilderExtensions
18+
{
19+
/// <summary>
20+
/// Serialize values of type <typeparamref name="T"/> with the specified serializer from <paramref name="serializer"/>.
21+
/// </summary>
22+
public static IHybridCacheBuilder WithSerializer<T>(this IHybridCacheBuilder builder, IHybridCacheSerializer<T> serializer)
23+
{
24+
builder.Services.AddSingleton<IHybridCacheSerializer<T>>(serializer);
25+
return builder;
26+
}
27+
28+
/// <summary>
29+
/// Serialize values of type <typeparamref name="T"/> with the serializer of type <typeparamref name="TImplementation"/>.
30+
/// </summary>
31+
public static IHybridCacheBuilder WithSerializer<T,
32+
#if NET5_0_OR_GREATER
33+
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
34+
#endif
35+
TImplementation>(this IHybridCacheBuilder builder)
36+
where TImplementation : class, IHybridCacheSerializer<T>
37+
{
38+
builder.Services.AddSingleton<IHybridCacheSerializer<T>, TImplementation>();
39+
return builder;
40+
}
41+
42+
/// <summary>
43+
/// Add <paramref name="factory"/> as an additional serializer factory, which can provide serializers for multiple types.
44+
/// </summary>
45+
public static IHybridCacheBuilder WithSerializerFactory(this IHybridCacheBuilder builder, IHybridCacheSerializerFactory factory)
46+
{
47+
builder.Services.AddSingleton<IHybridCacheSerializerFactory>(factory);
48+
return builder;
49+
}
50+
51+
/// <summary>
52+
/// Add a factory of type <typeparamref name="TImplementation"/> as an additional serializer factory, which can provide serializers for multiple types.
53+
/// </summary>
54+
public static IHybridCacheBuilder WithSerializerFactory<
55+
#if NET5_0_OR_GREATER
56+
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
57+
#endif
58+
TImplementation>(this IHybridCacheBuilder builder)
59+
where TImplementation : class, IHybridCacheSerializerFactory
60+
{
61+
builder.Services.AddSingleton<IHybridCacheSerializerFactory, TImplementation>();
62+
return builder;
63+
}
64+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using System.Text;
8+
using System.Threading.Tasks;
9+
10+
namespace Microsoft.Extensions.Caching.Hybrid;
11+
12+
/// <summary>
13+
/// Options for configuring the default <see cref="HybridCache"/> implementation.
14+
/// </summary>
15+
public class HybridCacheOptions
16+
{
17+
/// <summary>
18+
/// Default global options to be applied to <see cref="HybridCache"/> operations; if options are
19+
/// specified at the individual call level, the non-null values are merged (with the per-call
20+
/// options being used in preference to the global options). If no value is specified for a given
21+
/// option (globally or per-call), the implementation may choose a reasonable default.
22+
/// </summary>
23+
public HybridCacheEntryOptions? DefaultEntryOptions { get; set; }
24+
25+
/// <summary>
26+
/// Disallow compression for this <see cref="HybridCache"/> instance.
27+
/// </summary>
28+
public bool DisableCompression { get; set; }
29+
30+
/// <summary>
31+
/// The maximum size of cache items; attempts to store values over this size will be logged
32+
/// and the value will not be stored in cache.
33+
/// </summary>
34+
/// <remarks>The default value is 1 MiB.</remarks>
35+
public long MaximumPayloadBytes { get; set; } = 1 << 20; // 1MiB
36+
37+
/// <summary>
38+
/// The maximum permitted length (in characters) of keys; attempts to use keys over this size will be logged.
39+
/// </summary>
40+
/// <remark>The default value is 1024 characters.</remark>
41+
public int MaximumKeyLength { get; set; } = 1024; // characters
42+
43+
/// <summary>
44+
/// Use "tags" data as dimensions on metric reporting; if enabled, care should be used to ensure that
45+
/// tags do not contain data that should not be visible in metrics systems.
46+
/// </summary>
47+
public bool ReportTagMetrics { get; set; }
48+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Diagnostics.CodeAnalysis;
7+
using System.Linq;
8+
using System.Text;
9+
using System.Threading.Tasks;
10+
using Microsoft.Extensions.Caching.Hybrid.Internal;
11+
using Microsoft.Extensions.DependencyInjection;
12+
using Microsoft.Extensions.DependencyInjection.Extensions;
13+
using Microsoft.Extensions.Internal;
14+
15+
namespace Microsoft.Extensions.Caching.Hybrid;
16+
17+
/// <summary>
18+
/// Configuration extension methods for <see cref="HybridCache"/>.
19+
/// </summary>
20+
public static class HybridCacheServiceExtensions
21+
{
22+
/// <summary>
23+
/// Adds support for multi-tier caching services.
24+
/// </summary>
25+
/// <returns>A builder instance that allows further configuration of the <see cref="HybridCache"/> system.</returns>
26+
public static IHybridCacheBuilder AddHybridCache(this IServiceCollection services, Action<HybridCacheOptions> setupAction)
27+
{
28+
#if NET7_0_OR_GREATER
29+
ArgumentNullException.ThrowIfNull(setupAction);
30+
#else
31+
_ = setupAction ?? throw new ArgumentNullException(nameof(setupAction));
32+
#endif
33+
AddHybridCache(services);
34+
services.Configure(setupAction);
35+
return new HybridCacheBuilder(services);
36+
}
37+
38+
/// <summary>
39+
/// Adds support for multi-tier caching services.
40+
/// </summary>
41+
/// <returns>A builder instance that allows further configuration of the <see cref="HybridCache"/> system.</returns>
42+
public static IHybridCacheBuilder AddHybridCache(this IServiceCollection services)
43+
{
44+
#if NET7_0_OR_GREATER
45+
ArgumentNullException.ThrowIfNull(services);
46+
#else
47+
_ = services ?? throw new ArgumentNullException(nameof(services));
48+
#endif
49+
50+
services.TryAddSingleton(TimeProvider.System);
51+
services.AddOptions();
52+
services.AddMemoryCache();
53+
services.AddDistributedMemoryCache(); // we need a backend; use in-proc by default
54+
services.TryAddSingleton<IHybridCacheSerializerFactory, DefaultJsonSerializerFactory>();
55+
services.TryAddSingleton<IHybridCacheSerializer<string>>(InbuiltTypeSerializer.Instance);
56+
services.TryAddSingleton<IHybridCacheSerializer<byte[]>>(InbuiltTypeSerializer.Instance);
57+
services.TryAddSingleton<HybridCache, DefaultHybridCache>();
58+
return new HybridCacheBuilder(services);
59+
}
60+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using System.Text;
8+
using System.Threading.Tasks;
9+
using Microsoft.Extensions.DependencyInjection;
10+
11+
namespace Microsoft.Extensions.Caching.Hybrid;
12+
13+
/// <summary>
14+
/// Helper API for configuring <see cref="HybridCache"/>.
15+
/// </summary>
16+
public interface IHybridCacheBuilder
17+
{
18+
/// <summary>
19+
/// Gets the services collection associated with this instance.
20+
/// </summary>
21+
IServiceCollection Services { get; }
22+
}
23+
24+
internal sealed class HybridCacheBuilder(IServiceCollection services) : IHybridCacheBuilder
25+
{
26+
public IServiceCollection Services { get; } = services;
27+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using System.Threading;
8+
using System.Threading.Tasks;
9+
using Microsoft.Extensions.Caching.Distributed;
10+
using Microsoft.Extensions.DependencyInjection;
11+
using Microsoft.Extensions.Options;
12+
13+
namespace Microsoft.Extensions.Caching.Hybrid.Internal;
14+
15+
/// <summary>
16+
/// The inbuilt ASP.NET implementation of <see cref="HybridCache"/>.
17+
/// </summary>
18+
internal sealed class DefaultHybridCache : HybridCache
19+
{
20+
private readonly IDistributedCache _backendCache;
21+
private readonly IServiceProvider _services;
22+
private readonly HybridCacheOptions _options;
23+
24+
public DefaultHybridCache(IOptions<HybridCacheOptions> options, IDistributedCache backendCache, IServiceProvider services)
25+
{
26+
_backendCache = backendCache ?? throw new ArgumentNullException(nameof(backendCache));
27+
_services = services ?? throw new ArgumentNullException(nameof(services));
28+
_options = options.Value;
29+
}
30+
31+
internal HybridCacheOptions Options => _options;
32+
33+
public override ValueTask<T> GetOrCreateAsync<TState, T>(string key, TState state, Func<TState, CancellationToken, ValueTask<T>> underlyingDataCallback, HybridCacheEntryOptions? options = null, IReadOnlyCollection<string>? tags = null, CancellationToken token = default)
34+
=> underlyingDataCallback(state, token); // pass-thru without caching for initial API pass
35+
36+
public override ValueTask RemoveKeyAsync(string key, CancellationToken token = default)
37+
=> default; // no cache, nothing to remove
38+
39+
public override ValueTask RemoveTagAsync(string tag, CancellationToken token = default)
40+
=> default; // no cache, nothing to remove
41+
42+
public override ValueTask SetAsync<T>(string key, T value, HybridCacheEntryOptions? options = null, IReadOnlyCollection<string>? tags = null, CancellationToken token = default)
43+
=> default; // no cache, nothing to set
44+
45+
internal IHybridCacheSerializer<T> GetSerializer<T>()
46+
{
47+
// unused API, primarily intended to show configuration is working;
48+
// the real version would memoize the result
49+
var service = _services.GetService<IHybridCacheSerializer<T>>();
50+
if (service is null)
51+
{
52+
foreach (var factory in _services.GetServices<IHybridCacheSerializerFactory>())
53+
{
54+
if (factory.TryCreateSerializer<T>(out var current))
55+
{
56+
service = current;
57+
}
58+
}
59+
}
60+
return service ?? throw new InvalidOperationException("No serializer configured for type: " + typeof(T).Name);
61+
}
62+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Buffers;
5+
using System.Diagnostics.CodeAnalysis;
6+
using System.Text.Json;
7+
8+
namespace Microsoft.Extensions.Caching.Hybrid.Internal;
9+
10+
internal sealed class DefaultJsonSerializerFactory : IHybridCacheSerializerFactory
11+
{
12+
public bool TryCreateSerializer<T>([NotNullWhen(true)] out IHybridCacheSerializer<T>? serializer)
13+
{
14+
// no restriction
15+
serializer = new DefaultJsonSerializer<T>();
16+
return true;
17+
}
18+
19+
internal sealed class DefaultJsonSerializer<T> : IHybridCacheSerializer<T>
20+
{
21+
T IHybridCacheSerializer<T>.Deserialize(ReadOnlySequence<byte> source)
22+
{
23+
var reader = new Utf8JsonReader(source);
24+
#pragma warning disable IL2026, IL3050 // AOT bits
25+
return JsonSerializer.Deserialize<T>(ref reader)!;
26+
#pragma warning restore IL2026, IL3050
27+
}
28+
29+
void IHybridCacheSerializer<T>.Serialize(T value, IBufferWriter<byte> target)
30+
{
31+
using var writer = new Utf8JsonWriter(target);
32+
#pragma warning disable IL2026, IL3050 // AOT bits
33+
JsonSerializer.Serialize<T>(writer, value, JsonSerializerOptions.Default);
34+
#pragma warning restore IL2026, IL3050
35+
}
36+
}
37+
38+
}

0 commit comments

Comments
 (0)