File: Internal\DefaultJsonSerializerFactory.cs
Web Access
Project: src\src\Libraries\Microsoft.Extensions.Caching.Hybrid\Microsoft.Extensions.Caching.Hybrid.csproj (Microsoft.Extensions.Caching.Hybrid)
// 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.Buffers;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
using Microsoft.Extensions.DependencyInjection;
 
namespace Microsoft.Extensions.Caching.Hybrid.Internal;
 
internal sealed class DefaultJsonSerializerFactory : IHybridCacheSerializerFactory
{
    private readonly IServiceProvider _serviceProvider;
 
    internal static JsonSerializerOptions FieldEnabledJsonOptions { get; } = new() { IncludeFields = true };
 
    internal JsonSerializerOptions Options { get; }
 
    public DefaultJsonSerializerFactory(IServiceProvider serviceProvider)
    {
        // store the service provider and obtain the default JSON options, keyed by the **open** generic interface type
        _serviceProvider = serviceProvider;
 
#pragma warning disable IDE0079 // unnecessary suppression: TFM-dependent
#pragma warning disable IL2026, IL3050 // AOT bits
        Options = serviceProvider.GetKeyedService<JsonSerializerOptions>(typeof(IHybridCacheSerializer<>)) ?? JsonSerializerOptions.Default;
#pragma warning restore IL2026, IL3050
#pragma warning restore IDE0079
    }
 
    public bool TryCreateSerializer<T>([NotNullWhen(true)] out IHybridCacheSerializer<T>? serializer)
    {
        // no restriction - accept any type (i.e. always return true)
 
        // see if there is a per-type options registered (keyed by the **closed** generic type), otherwise use the default
        JsonSerializerOptions options = _serviceProvider.GetKeyedService<JsonSerializerOptions>(typeof(IHybridCacheSerializer<T>)) ?? Options;
        if (IsValueTuple(typeof(T)) && !options.IncludeFields)
        {
            // value-tuples expose fields, not properties; special-case this as a common scenario
            options = FieldEnabledJsonOptions;
        }
 
        serializer = new DefaultJsonSerializer<T>(options);
        return true;
    }
 
    private static bool IsValueTuple(Type type)
        => type.IsValueType && (type.FullName ?? string.Empty).StartsWith("System.ValueTuple`", StringComparison.Ordinal);
 
    internal sealed class DefaultJsonSerializer<T> : IHybridCacheSerializer<T>
    {
        internal JsonSerializerOptions Options { get; }
 
        public DefaultJsonSerializer(JsonSerializerOptions options)
        {
            Options = options;
        }
 
#pragma warning disable IDE0079 // unnecessary suppression: TFM-dependent
#pragma warning disable IL2026, IL3050 // AOT bits
        T IHybridCacheSerializer<T>.Deserialize(ReadOnlySequence<byte> source)
        {
            var reader = new Utf8JsonReader(source);
            return JsonSerializer.Deserialize<T>(ref reader, Options)!;
 
        }
 
        void IHybridCacheSerializer<T>.Serialize(T value, IBufferWriter<byte> target)
        {
            using var writer = new Utf8JsonWriter(target);
 
            JsonSerializer.Serialize<T>(writer, value, Options);
        }
#pragma warning restore IL2026, IL3050
#pragma warning restore IDE0079
    }
 
}