Handle synchronous exceptions from partial (#16679)
Handle sync exceptions within async context
This commit is contained in:
parent
a0dfffa4cb
commit
7816ef94ca
|
|
@ -55,7 +55,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
||||||
{
|
{
|
||||||
response.ContentLength = resolvedContentTypeEncoding.GetByteCount(result.Content);
|
response.ContentLength = resolvedContentTypeEncoding.GetByteCount(result.Content);
|
||||||
|
|
||||||
using (var textWriter = _httpResponseStreamWriterFactory.CreateWriter(response.Body, resolvedContentTypeEncoding))
|
await using (var textWriter = _httpResponseStreamWriterFactory.CreateWriter(response.Body, resolvedContentTypeEncoding))
|
||||||
{
|
{
|
||||||
await textWriter.WriteAsync(result.Content);
|
await textWriter.WriteAsync(result.Content);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -286,7 +286,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor
|
||||||
{
|
{
|
||||||
// This means we're writing to a 'real' writer, probably to the actual output stream.
|
// This means we're writing to a 'real' writer, probably to the actual output stream.
|
||||||
// We're using PagedBufferedTextWriter here to 'smooth' synchronous writes of IHtmlContent values.
|
// We're using PagedBufferedTextWriter here to 'smooth' synchronous writes of IHtmlContent values.
|
||||||
using (var writer = _bufferScope.CreateWriter(context.Writer))
|
await using (var writer = _bufferScope.CreateWriter(context.Writer))
|
||||||
{
|
{
|
||||||
await bodyWriter.Buffer.WriteToAsync(writer, _htmlEncoder);
|
await bodyWriter.Buffer.WriteToAsync(writer, _htmlEncoder);
|
||||||
await writer.FlushAsync();
|
await writer.FlushAsync();
|
||||||
|
|
|
||||||
|
|
@ -123,7 +123,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
|
||||||
|
|
||||||
_writerFactory ??= context.HttpContext.RequestServices.GetRequiredService<IHttpResponseStreamWriterFactory>();
|
_writerFactory ??= context.HttpContext.RequestServices.GetRequiredService<IHttpResponseStreamWriterFactory>();
|
||||||
|
|
||||||
using (var writer = _writerFactory.CreateWriter(response.Body, resolvedContentTypeEncoding))
|
await using (var writer = _writerFactory.CreateWriter(response.Body, resolvedContentTypeEncoding))
|
||||||
{
|
{
|
||||||
var viewContext = new ViewContext(
|
var viewContext = new ViewContext(
|
||||||
context,
|
context,
|
||||||
|
|
@ -149,8 +149,8 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
using var bufferingStream = new FileBufferingWriteStream();
|
await using var bufferingStream = new FileBufferingWriteStream();
|
||||||
using (var intermediateWriter = _writerFactory.CreateWriter(bufferingStream, resolvedContentTypeEncoding))
|
await using (var intermediateWriter = _writerFactory.CreateWriter(bufferingStream, resolvedContentTypeEncoding))
|
||||||
{
|
{
|
||||||
viewComponentResult.WriteTo(intermediateWriter, _htmlEncoder);
|
viewComponentResult.WriteTo(intermediateWriter, _htmlEncoder);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -233,7 +233,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
|
||||||
|
|
||||||
OnExecuting(viewContext);
|
OnExecuting(viewContext);
|
||||||
|
|
||||||
using (var writer = WriterFactory.CreateWriter(response.Body, resolvedContentTypeEncoding))
|
await using (var writer = WriterFactory.CreateWriter(response.Body, resolvedContentTypeEncoding))
|
||||||
{
|
{
|
||||||
var view = viewContext.View;
|
var view = viewContext.View;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,44 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task ExecuteAsync_ExceptionInSyncContext()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var view = CreateView((v) =>
|
||||||
|
{
|
||||||
|
v.Writer.Write("xyz");
|
||||||
|
throw new NotImplementedException("This should be raw!");
|
||||||
|
});
|
||||||
|
|
||||||
|
var context = new DefaultHttpContext();
|
||||||
|
var stream = new Mock<Stream>();
|
||||||
|
stream.Setup(s => s.CanWrite).Returns(true);
|
||||||
|
|
||||||
|
context.Response.Body = stream.Object;
|
||||||
|
var actionContext = new ActionContext(
|
||||||
|
context,
|
||||||
|
new RouteData(),
|
||||||
|
new ActionDescriptor());
|
||||||
|
var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider());
|
||||||
|
|
||||||
|
var viewExecutor = CreateViewExecutor();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var exception = await Assert.ThrowsAsync<NotImplementedException>(async () => await viewExecutor.ExecuteAsync(
|
||||||
|
actionContext,
|
||||||
|
view,
|
||||||
|
viewData,
|
||||||
|
Mock.Of<ITempDataDictionary>(),
|
||||||
|
contentType: null,
|
||||||
|
statusCode: null)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal("This should be raw!", exception.Message);
|
||||||
|
stream.Verify(s => s.Write(It.IsAny<byte[]>(), It.IsAny<int>(), It.IsAny<int>()), Times.Never);
|
||||||
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[MemberData(nameof(ViewExecutorSetsContentTypeAndEncodingData))]
|
[MemberData(nameof(ViewExecutorSetsContentTypeAndEncodingData))]
|
||||||
public async Task ExecuteAsync_SetsContentTypeAndEncoding(
|
public async Task ExecuteAsync_SetsContentTypeAndEncoding(
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,17 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GivesCorrectCallstackForSyncronousCalls()
|
||||||
|
{
|
||||||
|
// Regression test for https://github.com/aspnet/AspNetCore/issues/15367
|
||||||
|
// Arrange
|
||||||
|
var exception = await Assert.ThrowsAsync<HttpRequestException>(async () => await Client.GetAsync("http://localhost/Home/MyHtml"));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal("Should be visible", exception.InnerException.InnerException.Message);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task CanRenderViewsWithTagHelpersAndUnboundDynamicAttributes_Encoded()
|
public async Task CanRenderViewsWithTagHelpersAndUnboundDynamicAttributes_Encoded()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,11 @@ namespace TagHelpersWebSite.Controllers
|
||||||
return View();
|
return View();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IActionResult MyHtml()
|
||||||
|
{
|
||||||
|
return View();
|
||||||
|
}
|
||||||
|
|
||||||
public IActionResult ViewComponentTagHelpers()
|
public IActionResult ViewComponentTagHelpers()
|
||||||
{
|
{
|
||||||
return View();
|
return View();
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
|
using System.Text.Encodings.Web;
|
||||||
|
using Microsoft.AspNetCore.Html;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||||
|
|
||||||
|
namespace TagHelpersWebSite
|
||||||
|
{
|
||||||
|
public class MyHtmlContent : IHtmlContent
|
||||||
|
{
|
||||||
|
private IHtmlHelper Html { get; }
|
||||||
|
|
||||||
|
public MyHtmlContent(IHtmlHelper html)
|
||||||
|
{
|
||||||
|
Html = html;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteTo(TextWriter writer, HtmlEncoder encoder)
|
||||||
|
{
|
||||||
|
#pragma warning disable MVC1000 // Use of IHtmlHelper.{0} should be avoided.
|
||||||
|
Html.Partial("_Test").WriteTo(writer, encoder);
|
||||||
|
#pragma warning restore MVC1000 // Use of IHtmlHelper.{0} should be avoided.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Diagnostics;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
@(new TagHelpersWebSite.MyHtmlContent(Html))
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
@{
|
||||||
|
throw new Exception("Should be visible");
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue