public async Task ExecuteAsync(ActionContext context, JsonResult result) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (result == null) { throw new ArgumentNullException(nameof(result)); } var jsonSerializerOptions = GetSerializerOptions(result); var response = context.HttpContext.Response; ResponseContentTypeHelper.ResolveContentTypeAndEncoding( result.ContentType, response.ContentType, DefaultContentType, out var resolvedContentType, out var resolvedContentTypeEncoding); response.ContentType = resolvedContentType; if (result.StatusCode != null) { response.StatusCode = result.StatusCode.Value; } Log.JsonResultExecuting(_logger, result.Value); // Keep this code in sync with SystemTextJsonOutputFormatter var writeStream = GetWriteStream(context.HttpContext, resolvedContentTypeEncoding); try { var value = result.Value; if (value is IAsyncEnumerable <object> asyncEnumerable) { Log.BufferingAsyncEnumerable(_logger, asyncEnumerable); value = await _asyncEnumerableReader.ReadAsync(asyncEnumerable); } var type = value?.GetType() ?? typeof(object); await JsonSerializer.SerializeAsync(writeStream, value, type, jsonSerializerOptions); // 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 (writeStream is TranscodingWriteStream transcodingStream) { await transcodingStream.FinalWriteAsync(CancellationToken.None); } await writeStream.FlushAsync(); } finally { if (writeStream is TranscodingWriteStream transcodingStream) { await transcodingStream.DisposeAsync(); } } }
public async Task ExecuteAsync(ActionContext context, JsonResult result) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (result == null) { throw new ArgumentNullException(nameof(result)); } var jsonSerializerOptions = GetSerializerOptions(result); var response = context.HttpContext.Response; ResponseContentTypeHelper.ResolveContentTypeAndEncoding( result.ContentType, response.ContentType, DefaultContentType, out var resolvedContentType, out var resolvedContentTypeEncoding); response.ContentType = resolvedContentType; if (result.StatusCode != null) { response.StatusCode = result.StatusCode.Value; } Log.JsonResultExecuting(_logger, result.Value); var value = result.Value; if (value != null && _asyncEnumerableReaderFactory.TryGetReader(value.GetType(), out var reader)) { Log.BufferingAsyncEnumerable(_logger, value); value = await reader(value); } var objectType = value?.GetType() ?? typeof(object); // Keep this code in sync with SystemTextJsonOutputFormatter var responseStream = response.Body; if (resolvedContentTypeEncoding.CodePage == Encoding.UTF8.CodePage) { await JsonSerializer.SerializeAsync(responseStream, value, objectType, jsonSerializerOptions); await responseStream.FlushAsync(); } else { // JsonSerializer only emits UTF8 encoded output, but we need to write the response in the encoding specified by // selectedEncoding var transcodingStream = Encoding.CreateTranscodingStream(response.Body, resolvedContentTypeEncoding, Encoding.UTF8, leaveOpen: true); ExceptionDispatchInfo?exceptionDispatchInfo = null; try { await JsonSerializer.SerializeAsync(transcodingStream, value, objectType, jsonSerializerOptions); await transcodingStream.FlushAsync(); } catch (Exception ex) { // TranscodingStream may write to the inner stream as part of it's disposal. // We do not want this exception "ex" to be eclipsed by any exception encountered during the write. We will stash it and // explicitly rethrow it during the finally block. exceptionDispatchInfo = ExceptionDispatchInfo.Capture(ex); } finally { try { await transcodingStream.DisposeAsync(); } catch when(exceptionDispatchInfo != null) { } exceptionDispatchInfo?.Throw(); } } }
/// <summary> /// Executes the <see cref="JsonResult"/> and writes the response. /// </summary> /// <param name="context">The <see cref="ActionContext"/>.</param> /// <param name="result">The <see cref="JsonResult"/>.</param> /// <returns>A <see cref="Task"/> which will complete when writing has completed.</returns> public async Task ExecuteAsync(ActionContext context, JsonResult result) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (result == null) { throw new ArgumentNullException(nameof(result)); } var jsonSerializerSettings = GetSerializerSettings(result); var response = context.HttpContext.Response; ResponseContentTypeHelper.ResolveContentTypeAndEncoding( result.ContentType, response.ContentType, DefaultContentType, out var resolvedContentType, out var resolvedContentTypeEncoding); response.ContentType = resolvedContentType; if (result.StatusCode != null) { response.StatusCode = result.StatusCode.Value; } Log.JsonResultExecuting(_logger, result.Value); var responseStream = response.Body; FileBufferingWriteStream?fileBufferingWriteStream = null; if (!_mvcOptions.SuppressOutputFormatterBuffering) { fileBufferingWriteStream = new FileBufferingWriteStream(); responseStream = fileBufferingWriteStream; } try { await using (var writer = _writerFactory.CreateWriter(responseStream, resolvedContentTypeEncoding)) { using var jsonWriter = new JsonTextWriter(writer); jsonWriter.ArrayPool = _charPool; jsonWriter.CloseOutput = false; jsonWriter.AutoCompleteOnClose = false; var jsonSerializer = JsonSerializer.Create(jsonSerializerSettings); var value = result.Value; if (value != null && _asyncEnumerableReaderFactory.TryGetReader(value.GetType(), out var reader)) { Log.BufferingAsyncEnumerable(_logger, value); value = await reader(value); } jsonSerializer.Serialize(jsonWriter, value); } if (fileBufferingWriteStream != null) { await fileBufferingWriteStream.DrainBufferAsync(response.Body); } } finally { if (fileBufferingWriteStream != null) { await fileBufferingWriteStream.DisposeAsync(); } } }
public virtual async Task ExecuteAsync(ActionContext context, ViewComponentResult result) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (result == null) { throw new ArgumentNullException(nameof(result)); } var response = context.HttpContext.Response; var viewData = result.ViewData; if (viewData == null) { viewData = new ViewDataDictionary(_modelMetadataProvider, context.ModelState); } var tempData = result.TempData; if (tempData == null) { tempData = _tempDataDictionaryFactory.GetTempData(context.HttpContext); } ResponseContentTypeHelper.ResolveContentTypeAndEncoding( result.ContentType, response.ContentType, (ViewExecutor.DefaultContentType, Encoding.UTF8), MediaType.GetEncoding, out var resolvedContentType, out var resolvedContentTypeEncoding); response.ContentType = resolvedContentType; if (result.StatusCode != null) { response.StatusCode = result.StatusCode.Value; } await using var writer = _writerFactory.CreateWriter(response.Body, resolvedContentTypeEncoding); var viewContext = new ViewContext( context, NullView.Instance, viewData, tempData, writer, _htmlHelperOptions); OnExecuting(viewContext); // IViewComponentHelper is stateful, we want to make sure to retrieve it every time we need it. var viewComponentHelper = context.HttpContext.RequestServices.GetRequiredService <IViewComponentHelper>(); (viewComponentHelper as IViewContextAware)?.Contextualize(viewContext); var viewComponentResult = await GetViewComponentResult(viewComponentHelper, _logger, result); if (viewComponentResult is ViewBuffer viewBuffer) { // In the ordinary case, DefaultViewComponentHelper will return an instance of ViewBuffer. We can simply // invoke WriteToAsync on it. await viewBuffer.WriteToAsync(writer, _htmlEncoder); await writer.FlushAsync(); } else { await using var bufferingStream = new FileBufferingWriteStream(); await using (var intermediateWriter = _writerFactory.CreateWriter(bufferingStream, resolvedContentTypeEncoding)) { viewComponentResult.WriteTo(intermediateWriter, _htmlEncoder); } await bufferingStream.DrainBufferAsync(response.Body); } }
/// <inheritdoc /> public virtual async Task ExecuteAsync(ActionContext context, ViewComponentResult result) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (result == null) { throw new ArgumentNullException(nameof(result)); } var response = context.HttpContext.Response; var viewData = result.ViewData; if (viewData == null) { viewData = new ViewDataDictionary(_modelMetadataProvider, context.ModelState); } var tempData = result.TempData; if (tempData == null) { tempData = _tempDataDictionaryFactory.GetTempData(context.HttpContext); } ResponseContentTypeHelper.ResolveContentTypeAndEncoding( result.ContentType, response.ContentType, ViewExecutor.DefaultContentType, out var resolvedContentType, out var resolvedContentTypeEncoding); response.ContentType = resolvedContentType; if (result.StatusCode != null) { response.StatusCode = result.StatusCode.Value; } // Opt into sync IO support until we can work out an alternative https://github.com/aspnet/AspNetCore/issues/6397 var syncIOFeature = context.HttpContext.Features.Get <Http.Features.IHttpBodyControlFeature>(); if (syncIOFeature != null) { syncIOFeature.AllowSynchronousIO = true; } using (var writer = new HttpResponseStreamWriter(response.Body, resolvedContentTypeEncoding)) { var viewContext = new ViewContext( context, NullView.Instance, viewData, tempData, writer, _htmlHelperOptions); OnExecuting(viewContext); // IViewComponentHelper is stateful, we want to make sure to retrieve it every time we need it. var viewComponentHelper = context.HttpContext.RequestServices.GetRequiredService <IViewComponentHelper>(); (viewComponentHelper as IViewContextAware)?.Contextualize(viewContext); var viewComponentResult = await GetViewComponentResult(viewComponentHelper, _logger, result); viewComponentResult.WriteTo(writer, _htmlEncoder); } }
/// <inheritdoc /> public virtual async Task ExecuteAsync(ActionContext context, ViewComponentResult result) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (result == null) { throw new ArgumentNullException(nameof(result)); } var response = context.HttpContext.Response; var viewData = result.ViewData; if (viewData == null) { viewData = new ViewDataDictionary(_modelMetadataProvider, context.ModelState); } var tempData = result.TempData; if (tempData == null) { tempData = _tempDataDictionaryFactory.GetTempData(context.HttpContext); } ResponseContentTypeHelper.ResolveContentTypeAndEncoding( result.ContentType, response.ContentType, ViewExecutor.DefaultContentType, out var resolvedContentType, out var resolvedContentTypeEncoding); response.ContentType = resolvedContentType; if (result.StatusCode != null) { response.StatusCode = result.StatusCode.Value; } using (var writer = new HttpResponseStreamWriter(response.Body, resolvedContentTypeEncoding)) { var viewContext = new ViewContext( context, NullView.Instance, viewData, tempData, writer, _htmlHelperOptions); // IViewComponentHelper is stateful, we want to make sure to retrieve it every time we need it. var viewComponentHelper = context.HttpContext.RequestServices.GetRequiredService <IViewComponentHelper>(); (viewComponentHelper as IViewContextAware)?.Contextualize(viewContext); var viewComponentResult = await GetViewComponentResult(viewComponentHelper, _logger, result); viewComponentResult.WriteTo(writer, _htmlEncoder); } }
public override Task ExecuteAsync(ActionContext context, JsonResult result) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (result == null) { throw new ArgumentNullException(nameof(result)); } var response = context.HttpContext.Response; ResponseContentTypeHelper.ResolveContentTypeAndEncoding( result.ContentType, response.ContentType, DefaultContentType, out var resolvedContentType, out var resolvedContentTypeEncoding); response.ContentType = resolvedContentType; if (result.Value != null) { using (var writer = WriterFactory.CreateWriter(response.Body, resolvedContentTypeEncoding)) { JsonSerializeOption option = null; if (result is JsonResultWrapper wrapper) { option = wrapper.Option; } else { var hosting = context.HttpContext.RequestServices.GetService <JsonSerializeOptionHosting>(); if (hosting != null) { option = hosting.Option; } } if (option == null) { option = mvcOptions.JsonSerializeOption; } else { option.Reference(mvcOptions.JsonSerializeOption); } var serializer = new JsonSerializer(option); using (var jsonWriter = new JsonWriter(writer)) { serializer.Serialize(result.Value, jsonWriter); } } } return(Task.CompletedTask); }
/// <summary> /// Executes a view asynchronously. /// </summary> /// <param name="actionContext">The <see cref="ActionContext"/> associated with the current request.</param> /// <param name="view">The <see cref="IView"/>.</param> /// <param name="viewData">The <see cref="ViewDataDictionary"/>.</param> /// <param name="tempData">The <see cref="ITempDataDictionary"/>.</param> /// <param name="contentType"> /// The content-type header value to set in the response. If <c>null</c>, /// <see cref="DefaultContentType"/> will be used. /// </param> /// <param name="statusCode"> /// The HTTP status code to set in the response. May be <c>null</c>. /// </param> /// <returns>A <see cref="Task"/> which will complete when view execution is completed.</returns> public virtual async Task ExecuteAsync( ActionContext actionContext, IView view, ViewDataDictionary viewData, ITempDataDictionary tempData, string contentType, int?statusCode) { if (actionContext == null) { throw new ArgumentNullException(nameof(actionContext)); } if (view == null) { throw new ArgumentNullException(nameof(view)); } if (viewData == null) { viewData = new ViewDataDictionary(_modelMetadataProvider, actionContext.ModelState); } if (tempData == null) { tempData = TempDataFactory.GetTempData(actionContext.HttpContext); } var response = actionContext.HttpContext.Response; string resolvedContentType = null; Encoding resolvedContentTypeEncoding = null; ResponseContentTypeHelper.ResolveContentTypeAndEncoding( contentType, response.ContentType, DefaultContentType, out resolvedContentType, out resolvedContentTypeEncoding); response.ContentType = resolvedContentType; if (statusCode != null) { response.StatusCode = statusCode.Value; } using (var writer = WriterFactory.CreateWriter(response.Body, resolvedContentTypeEncoding)) { var viewContext = new ViewContext( actionContext, view, viewData, tempData, writer, ViewOptions.HtmlHelperOptions); DiagnosticSource.BeforeView(view, viewContext); await view.RenderAsync(viewContext); DiagnosticSource.AfterView(view, viewContext); // Perf: Invoke FlushAsync to ensure any buffered content is asynchronously written to the underlying // response asynchronously. In the absence of this line, the buffer gets synchronously written to the // response as part of the Dispose which has a perf impact. await writer.FlushAsync(); } }
public override Task ExecuteAsync(ActionContext context, JsonResult result) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (result == null) { throw new ArgumentNullException(nameof(result)); } var serviceProvider = context.HttpContext.RequestServices; var response = context.HttpContext.Response; ResponseContentTypeHelper.ResolveContentTypeAndEncoding( result.ContentType, response.ContentType, DefaultContentType, out var resolvedContentType, out var resolvedContentTypeEncoding); response.ContentType = resolvedContentType; if (result.Value != null) { JsonSerializeOption option = null; if (result is JsonResultWrapper wrapper) { option = wrapper.Option; } else { var hosting = serviceProvider.GetService <JsonSerializeOptionHosting>(); if (hosting != null) { option = hosting.Option; } } if (option == null) { option = _mvcOptions.JsonSerializeOption; } else { option.Reference(_mvcOptions.JsonSerializeOption); } var serializer = serviceProvider.TryGetService <ISerializer>(() => new JsonSerializer(option)); if (serializer is ITextSerializer txtSerializer) { var content = txtSerializer.Serialize(result.Value); response.Body.WriteAsync(resolvedContentTypeEncoding.GetBytes(content)); } else { response.Body.WriteAsync(serializer.Serialize(result.Value)); } } return(Task.CompletedTask); }
/// <inheritdoc /> public override async Task ExecuteResultAsync(ActionContext context) { var response = context.HttpContext.Response; var services = context.HttpContext.RequestServices; var htmlHelperOptions = services.GetRequiredService <IOptions <MvcViewOptions> >().Value.HtmlHelperOptions; var viewComponentHelper = services.GetRequiredService <IViewComponentHelper>(); var loggerFactory = services.GetRequiredService <ILoggerFactory>(); var logger = loggerFactory.CreateLogger <ViewComponentResult>(); var htmlEncoder = services.GetRequiredService <HtmlEncoder>(); var viewData = ViewData; if (viewData == null) { var modelMetadataProvider = services.GetRequiredService <IModelMetadataProvider>(); viewData = new ViewDataDictionary(modelMetadataProvider, context.ModelState); } var tempData = TempData; if (tempData == null) { var factory = services.GetRequiredService <ITempDataDictionaryFactory>(); tempData = factory.GetTempData(context.HttpContext); } string resolvedContentType = null; Encoding resolvedContentTypeEncoding = null; ResponseContentTypeHelper.ResolveContentTypeAndEncoding( ContentType, response.ContentType, ViewExecutor.DefaultContentType, out resolvedContentType, out resolvedContentTypeEncoding); response.ContentType = resolvedContentType; if (StatusCode != null) { response.StatusCode = StatusCode.Value; } using (var writer = new HttpResponseStreamWriter(response.Body, resolvedContentTypeEncoding)) { var viewContext = new ViewContext( context, NullView.Instance, viewData, tempData, writer, htmlHelperOptions); (viewComponentHelper as ICanHasViewContext)?.Contextualize(viewContext); var result = await GetViewComponentResult(viewComponentHelper, logger); result.WriteTo(writer, htmlEncoder); } }