-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Description
EDIT New proposal can be found here: #51544 (comment)
Details
Background
The existing JsonContent type in System.Net.Http.Json uses existing JsonSerializerOptions-based JsonSerializer.Serialize(Async) overloads which root reflection code and all built-in STJ converters (even when not needed in an app). We should add a new type that uses new JsonSerializerContext-based overloads, which are AOT-friendly and allow for a smaller app. Also the existing type has been marked as "requires unreferenced code", so it is beneficial to provide an alternative which is trim-friendly.
API Proposal
public sealed partial class JsonContent<TValue> : HttpContent
{
internal JsonContent() { }
public TValue? Value { get { throw null; } }
}We should also expose static Create methods for these types to the existing JsonContent :
public sealed partial class JsonContent : HttpContent
{
// Existing
// internal JsonContent() { }
// public Type ObjectType { get { throw null; } }
// public object? Value { get { throw null; } }
// public static JsonContent Create(object? inputValue, Type inputType, MediaTypeHeaderValue? mediaType = null, JsonSerializerOptions? options = null) { throw null; }
// public static JsonContent Create<T>(T inputValue, MediaTypeHeaderValue? mediaType = null, JsonSerializerOptions? options = null) { throw null; }
// New create methods for JsonContent<TValue>
public static JsonContent<object?> Create(object? inputValue, Type inputType, JsonSerializerContext context, MediaTypeHeaderValue? mediaType = null) { throw null; }
public static JsonContent<TValue> Create(TValue? inputValue, JsonTypeInfo<TValue> jsonTypeInfo, MediaTypeHeaderValue? mediaType = null) { throw null; }
}The new create methods should go on JsonContent - if we put them on JsonContent<TValue>, then it will be possible for users to write awkward code like this:
JsonContent<object> content = JsonContent<int>.Create(myVal, type, context);Usage
Just like the existing JsonContent type, JsonContent<TValue> can be used when building a HttpResponseMessage based on JSON. The difference is that now the JSON will be serialized in a trim-safe way which is also optimized for app size:
public static Task<HttpResponseMessage> PutAsJsonAsync<TValue>(this HttpClient client, string? requestUri, TValue value, JsonTypeInfo<TValue> jsonTypeInfo, CancellationToken cancellationToken = default)
{
if (client == null)
{
throw new ArgumentNullException(nameof(client));
}
JsonContent<TValue> content = JsonContent.Create(value, jsonTypeInfo);
return client.PutAsync(requestUri, content, cancellationToken);
}Q/A
Can JsonContent<TValue> derive from JsonContent<T>?
It's better not to do this, because the ILLinker won't be able to trim away reflection-based code and extra JsonConverters used by the existing JsonContent type. The underlying infrastructure for serializing the JSON content is based on overriding virtual methods. Making the new JsonContent<TValue> type derive from the existing type is bad because the linker will preserve the virtual and override methods of called methods in the hierarchy, because it doesn't know which one will be called at run-time. This is discussed in more detail here.