-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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
Add an API to perform streaming transcoding #30260
Comments
For context, I spoke with Pranav about this a few days ago. The Framework currently has a static method The request here is that we have an API akin to |
@pranavkm Can you share a sample of the code that you want to be able to write? That would help inform the shape of the API that is missing. |
Right now this is basically what it looks like.... Again, we're happy if you want to try and improve this with the knowledge that we're optimizing for performance over simplicity. The task we need to perform is to use the serializer with arbitrary encodings. Ultimately we don't get any value from managing these streams ourselves - if this were an implementation detail of the JSON serializer that would suit our needs even better. Reading var httpContext = null; // assume we have the httpContext
var encoding = null; // assume we already decided on an Encoding
Stream stream;
bool disposeStream;
if (encoding.CodePage == Encoding.UTF8.CodePage)
{
stream = httpContext.Request.Body;
disposeStream = false;
}
else
{
stream = new TranscodingReadStream(httpContext.Request.Body, encoding, disposeInner: false);
disposeStream = true;
}
object result;
try
{
result = await JsonSerializer.DeserializeAsync(stream, someType, SerializerOptions);
}
catch (JsonException)
{
// Do error handling xD
}
finally
{
if (disposeStream)
{
await stream.DisposeAsync();
}
} Writing var httpContext = null; // assume we have the httpContext
var encoding = null; // assume we already decided on an Encoding
Stream stream;
bool wrappedStream;
if (encoding.CodePage == Encoding.UTF8.CodePage)
{
stream = httpContext.Response.Body;
wrappedStream = false;
}
else
{
stream = new TranscodingWriteStream(httpContext.Response.Body, selectedEncoding, disposeInner: false);
wrappedStream = true;
}
try
{
await JsonSerializer.SerializeAsync(stream, someObject, someType, SerializerOptions);
// The transcoding streams use Encoders and Decoders that have internal buffers. We need to flush these
// when there is no more data to be written. Stream.FlushAsync isn't suitable since it's
// acceptable to Flush a Stream (multiple times) prior to completion.
if (wrappedStream)
{
await ((TranscodingWriteStream)stream).FinalWriteAsync(CancellationToken.None);
}
await stream.FlushAsync();
}
finally
{
if (wrappedStream)
{
await stream.DisposeAsync();
}
} |
Are there particular |
I'm not certain we care deeply about the performance. Out of the box MVC is configured to do UTF8 and UTF16 for historical reasons, but IMO if you're not doing UTF8 on the web, you are doing the weird. No one has ever asked us to add something else to the defaults. We need this feature just because it would be genuinely surprising if we didn't have it. |
So seems like something very straightforward would work then: namespace System.Text // perhaps should be System.IO?
{
// NEW type being proposed - sealed by default (see detailed comments below)
public sealed class TranscodingStream : Stream
{
public TranscodingStream(Stream innerStream, Encoding outerEncoding, Encoding innerEncoding, bool leaveOpen = false);
/* all virtual methods defined by Stream are overridden */
}
} The new proposed class is sealed because I haven't yet thought through what extensibility points we'd need to add, and unsealing in the future is a non-breaking change. When calling When calling When disposing the |
This sounds like it meets our requirements pretty well! |
@pranavkm - any thoughts? |
This sounds pretty close to what we have in MVC (with more bells and whistles). Just to have this in writing, we'll have async versions of the |
Yes, the plan is to override all virtual methods, including async methods. I'll clarify that in the API description. |
@GrabYourPitchforks - what do we need to do to make progress on this? We want to build more functionality in ASP.NET Core that would use this, and I'd really love not to duplicate the code we're using in MVC today. |
@rynowak I'll mark it partner blocking so that it gets prioritized during triage. |
namespace System.Text
{
public partial class Encoding
{
public static Stream CreateTranscodingStream(Stream innerStream, Encoding innerStreamEncoding, Encoding outerStreamEncoding, bool leaveOpen = false);
}
} |
@GrabYourPitchforks I'd love a version of this API that checks for byte order marks; I know there are a few places in code we check for these. Something like: public static Stream CreateTranscodingStreamFromBOM(Stream innerStream, Encoding fallbackInnerStreamEncoding, Encoding outerStreamEncoding, bool leaveOpen = false); |
@scalablecory If you don't mind go ahead and open a new issue tracking the BOM request. Since this issue is now closed I don't want your feedback to get lost! |
(Edit by @GrabYourPitchforks: proposed API is in a comment at https://github.com/dotnet/corefx/issues/39483#issuecomment-557737022.)
System.Text.Json specifically supports UTF8 inputs and outputs. MVC needs to support arbitrary user configured encoding schemes. To support this in a performant way, MVC has transcoding
Stream
implementations that minimally buffer inputs and outputs to the serializer.Most of the work in these implementations is to perform state management when calling
Utf8.FromUtf16
\Encoders
*Decoders
. It would be great if these APIs were instead available as part of CoreFx.The text was updated successfully, but these errors were encountered: