/// <summary> /// Executes a view asynchronously. /// </summary> /// <param name="viewContext">The <see cref="ViewContext"/> associated with the current request.</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> protected async Task ExecuteAsync( ViewContext viewContext, string contentType, int?statusCode) { if (viewContext == null) { throw new ArgumentNullException(nameof(viewContext)); } var response = viewContext.HttpContext.Response; string resolvedContentType; Encoding resolvedContentTypeEncoding; 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 view = viewContext.View; var oldWriter = viewContext.Writer; try { viewContext.Writer = writer; DiagnosticSource.BeforeView(view, viewContext); await view.RenderAsync(viewContext); DiagnosticSource.AfterView(view, viewContext); } finally { viewContext.Writer = oldWriter; } // 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(); } }
/// <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, MediaTypeHeaderValue contentType, int?statusCode) { if (actionContext == null) { throw new ArgumentNullException(nameof(actionContext)); } if (view == null) { throw new ArgumentNullException(nameof(view)); } var services = actionContext.HttpContext.RequestServices; if (viewData == null) { var metadataProvider = services.GetRequiredService <IModelMetadataProvider>(); viewData = new ViewDataDictionary(metadataProvider); } if (tempData == null) { tempData = services.GetRequiredService <ITempDataDictionary>(); } var response = actionContext.HttpContext.Response; if (contentType != null && contentType.Encoding == null) { // Do not modify the user supplied content type, so copy it instead contentType = contentType.Copy(); contentType.Encoding = Encoding.UTF8; } // Priority list for setting content-type: // 1. passed in contentType (likely set by the user on the result) // 2. response.ContentType (likely set by the user in controller code) // 3. ViewExecutor.DefaultContentType (sensible default) response.ContentType = contentType?.ToString() ?? response.ContentType ?? DefaultContentType.ToString(); if (statusCode != null) { response.StatusCode = statusCode.Value; } var encoding = contentType?.Encoding ?? DefaultContentType.Encoding; using (var writer = WriterFactory.CreateWriter(response.Body, encoding)) { 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(); } }
/// <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(); } }