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

Prevent synchronous writes when using Razor #9395

Merged
merged 2 commits into from
Apr 16, 2019
Merged

Conversation

pranavkm
Copy link
Contributor

@pranavkm pranavkm commented Apr 15, 2019

  • Do not perform synchronous writes to the Response TextWriter after a Razor FlushAsync
  • Use ViewBuffer to perform async writes to the response when using ViewComponentResult

Related to #6397

Fixes #4885

@pranavkm pranavkm force-pushed the prkrishn/view-buffering branch 2 times, most recently from 80b1ee1 to 6b2f24b Compare April 15, 2019 20:29
* Do not perform synchronous writes to the Response TextWriter after a Razor FlushAsync
* Use ViewBuffer to perform async writes to the response when using ViewComponentResult
/// <inheritdoc />
public override void Write(char value)
{
if (IsBuffering)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some background - ViewBufferTextWriter had a dual mode of operation - after a Flush, all writes directly went to the underlying TextWriter (i.e. HttpResponseStreamWriter). With large enough content, we'll run out of buffer in the writer and result in a synchronous write that throws.

There isn't a very good reason for us to stop buffering once a flush is performed, it's really not an important \ well-defined requirement of FlushAsync .

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I agree. This seems like such an obvious improvment, I'm sad we didn't think of it befores.

@@ -62,6 +77,7 @@ public class ViewComponentResultExecutor : IActionResultExecutor<ViewComponentRe
_htmlEncoder = htmlEncoder;
_modelMetadataProvider = modelMetadataProvider;
_tempDataDictionaryFactory = tempDataDictionaryFactory;
_writerFactory = writerFactory;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Explicitly allowing null. We will get the service in the body of ExecuteAsync

var viewComponentResult = await GetViewComponentResult(viewComponentHelper, _logger, result);
viewComponentResult.WriteTo(writer, _htmlEncoder);

if (viewComponentResult is ViewBuffer viewBuffer)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://github.com/aspnet/AspNetCore/blob/master/src/Mvc/Mvc.ViewFeatures/src/ViewComponents/DefaultViewComponentHelper.cs#L176 returns ViewBuffer. It's a bit unfortunate we have to downcast this since a user could have customized the implementation.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I dunno why we made this stuff public. Sadbeans

}
else
{
using var memoryStream = new MemoryStream();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll change this to use the FileBufferingWriteStream once that's in.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth a comment with the issue # to rememberize it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Tratcher
Copy link
Member

/* No comments for this PR. */

Any updates for #9015?

@pranavkm
Copy link
Contributor Author

Any updates for #9015?

I split this one off as a separate PR just because I realized it had mostly unrelated changes. I'll get the other one updated soon

@aspnet-hello
Copy link

This comment was made automatically. If there is a problem contact ryanbrandenburg.

I've triaged the above build. I've created/commented on the following issue(s)
https://github.com/aspnet/AspNetCore-Internal/issues/2277

@Eilon Eilon added the area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates label Apr 16, 2019
{
syncIOFeature.AllowSynchronousIO = true;
}
_writerFactory ??= context.HttpContext.RequestServices.GetRequiredService<IHttpResponseStreamWriterFactory>();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P R A N A V P O I N T S

@pranavkm pranavkm merged commit 2be8052 into master Apr 16, 2019
@pranavkm pranavkm deleted the prkrishn/view-buffering branch April 16, 2019 23:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Why doesn't the ViewComponentResultExecutor use the IHttpResponseStreamWriterFactory
5 participants