Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce generic JsonResult<T> #55535

Open
alex-jitbit opened this issue May 5, 2024 · 4 comments
Open

Introduce generic JsonResult<T> #55535

alex-jitbit opened this issue May 5, 2024 · 4 comments
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation area-web-frameworks

Comments

@alex-jitbit
Copy link
Contributor

alex-jitbit commented May 5, 2024

Background and Motivation

Currently in System.Text.Json we have JsonSerializer.Serialize<T>(...) that serializes an object "as T". Which means, if we cast an object to some base class, or to an interface - the serializer will use that exact casted type's properties etc..

HOWEVER the AspNetCore JsonResult works differently. When it serializes an object, it always takes the object's hard type. See the source here: https://source.dot.net/#Microsoft.AspNetCore.Mvc.Core/Infrastructure/SystemTextJsonResultExecutor.cs,61 which means that even if we cast the object to something - nah, it does not care, it just uses the actual type.

As a workaround, people either use JsonSerializer.Serialize<T> to serialize to intermediate string and then return content (not optimal since it buffers everything into a huge string before sending to the client). Or - people write their own JsonResult<T> that handles this (tat's what I did)

Proposed API

Disclaimer: this is just the code I use as a workaround, it's very simple, and misses stuff, but just to give the idea...

/// <summary>
/// Serializes to output stream
/// Almost same as .NET built-in json result but allows specifying a type
/// </summary>
public class JsonResult<T> : IActionResult
{
	private readonly T _value;
	private readonly JsonSerializerOptions _options;

	public JsonResult(T value, JsonSerializerOptions options)
	{
		_value = value;
		_options = options;
	}

	public async Task ExecuteResultAsync(ActionContext context)
	{
		var response = context.HttpContext.Response;
		response.ContentType = "application/json";

		await JsonSerializer.SerializeAsync<T>(response.Body, _value, _options); //serialize to response stream
		await response.Body.FlushAsync();
	}
}

Usage Examples

public IActionResult Get()
{
	return new JsonResult<T>(someData, _someSerializerOptionsField);
}

Alternative Designs

Another option would e to somehow pass the type to existing JsonResult

@alex-jitbit alex-jitbit added the api-suggestion Early API idea and discussion, it is NOT ready for implementation label May 5, 2024
@martincostello
Copy link
Member

Given that MVC supports IResult now (#40639), would using the existing TypedResults.Json<T>() method solve this use case without introducing any new APIs?

@alex-jitbit
Copy link
Contributor Author

@martincostello wow, at first glance this looks exactly like a solution. Thanks. This is planned for .NET 9 correct?

@martincostello
Copy link
Member

It was added in .NET 7.

@alex-jitbit alex-jitbit closed this as not planned Won't fix, can't repro, duplicate, stale May 5, 2024
@alex-jitbit
Copy link
Contributor Author

alex-jitbit commented May 5, 2024

@martincostello unfortunately TypedResults.Json suffers from the same problem - it does not care about casting. It just uses GetType(). See here https://source.dot.net/#Microsoft.AspNetCore.Http.Results/HttpResultsHelper.cs,41

For example if I pass myCollection.Cast<ILightWeightInterfaceThatHidesSomeProperties> to it - it just takes the underlying type, ignoreing the Cast

@alex-jitbit alex-jitbit reopened this May 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation area-web-frameworks
Projects
None yet
Development

No branches or pull requests

2 participants