/// <summary> /// Asynchronously renders the specified <paramref name="view"/> to the response body. /// </summary> /// <param name="view">The <see cref="IView"/> to render.</param> /// <param name="actionContext">The <see cref="ActionContext"/> for the current executing action.</param> /// <param name="viewData">The <see cref="ViewDataDictionary"/> for the view being rendered.</param> /// <param name="tempData">The <see cref="ITempDataDictionary"/> for the view being rendered.</param> /// <returns>A <see cref="Task"/> that represents the asynchronous rendering.</returns> public static async Task ExecuteAsync([NotNull] IView view, [NotNull] ActionContext actionContext, [NotNull] ViewDataDictionary viewData, [NotNull] ITempDataDictionary tempData, [NotNull] HtmlHelperOptions htmlHelperOptions, MediaTypeHeaderValue contentType) { var response = actionContext.HttpContext.Response; contentType = contentType ?? DefaultContentType; if (contentType.Encoding == null) { // Do not modify the user supplied content type, so copy it instead contentType = contentType.Copy(); contentType.Encoding = Encoding.UTF8; } response.ContentType = contentType.ToString(); using (var writer = new HttpResponseStreamWriter(response.Body, contentType.Encoding)) { var viewContext = new ViewContext( actionContext, view, viewData, tempData, writer, htmlHelperOptions); await view.RenderAsync(viewContext); } }
public void Copy_SimpleMediaType_Copied() { var mediaType0 = new MediaTypeHeaderValue("text/plain"); var mediaType1 = mediaType0.Copy(); Assert.NotSame(mediaType0, mediaType1); Assert.Same(mediaType0.MediaType, mediaType1.MediaType); Assert.NotSame(mediaType0.Parameters, mediaType1.Parameters); Assert.Equal(mediaType0.Parameters.Count, mediaType1.Parameters.Count); }
public void Copy_WithParameters_Copied() { var mediaType0 = new MediaTypeHeaderValue("text/plain"); mediaType0.Parameters.Add(new NameValueHeaderValue("name", "value")); var mediaType1 = mediaType0.Copy(); Assert.NotSame(mediaType0, mediaType1); Assert.Same(mediaType0.MediaType, mediaType1.MediaType); Assert.NotSame(mediaType0.Parameters, mediaType1.Parameters); Assert.Equal(mediaType0.Parameters.Count, mediaType1.Parameters.Count); var pair0 = mediaType0.Parameters.First(); var pair1 = mediaType1.Parameters.First(); Assert.NotSame(pair0, pair1); Assert.Same(pair0.Name, pair1.Name); Assert.Same(pair0.Value, pair1.Value); }
/// <summary> /// Asynchronously renders the specified <paramref name="view"/> to the response body. /// </summary> /// <param name="view">The <see cref="IView"/> to render.</param> /// <param name="actionContext">The <see cref="ActionContext"/> for the current executing action.</param> /// <param name="viewData">The <see cref="ViewDataDictionary"/> for the view being rendered.</param> /// <param name="tempData">The <see cref="ITempDataDictionary"/> for the view being rendered.</param> /// <returns>A <see cref="Task"/> that represents the asynchronous rendering.</returns> public static async Task ExecuteAsync( IView view, ActionContext actionContext, ViewDataDictionary viewData, ITempDataDictionary tempData, HtmlHelperOptions htmlHelperOptions, MediaTypeHeaderValue contentType) { if (view == null) { throw new ArgumentNullException(nameof(view)); } if (actionContext == null) { throw new ArgumentNullException(nameof(actionContext)); } if (viewData == null) { throw new ArgumentNullException(nameof(viewData)); } if (tempData == null) { throw new ArgumentNullException(nameof(tempData)); } if (htmlHelperOptions == null) { throw new ArgumentNullException(nameof(htmlHelperOptions)); } 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(); using (var writer = new HttpResponseStreamWriter(response.Body, contentType?.Encoding ?? DefaultContentType.Encoding)) { var viewContext = new ViewContext( actionContext, view, viewData, tempData, writer, htmlHelperOptions); await view.RenderAsync(viewContext); // Invoke FlushAsync to ensure any buffered content is asynchronously written to the underlying // response. 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(); } }