186 lines
6.8 KiB
C#
186 lines
6.8 KiB
C#
// 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;
|
|
using System.Diagnostics;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using Microsoft.AspNetCore.Mvc.Internal;
|
|
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
|
using Microsoft.AspNetCore.Mvc.Rendering;
|
|
using Microsoft.AspNetCore.Mvc.ViewEngines;
|
|
using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.Options;
|
|
|
|
namespace Microsoft.AspNetCore.Mvc.ViewFeatures
|
|
{
|
|
/// <summary>
|
|
/// Executes an <see cref="IView"/>.
|
|
/// </summary>
|
|
public class ViewExecutor
|
|
{
|
|
/// <summary>
|
|
/// The default content-type header value for views, <c>text/html; charset=utf-8</c>.
|
|
/// </summary>
|
|
public static readonly string DefaultContentType = "text/html; charset=utf-8";
|
|
|
|
/// <summary>
|
|
/// Creates a new <see cref="ViewExecutor"/>.
|
|
/// </summary>
|
|
/// <param name="viewOptions">The <see cref="IOptions{MvcViewOptions}"/>.</param>
|
|
/// <param name="writerFactory">The <see cref="IHttpResponseStreamWriterFactory"/>.</param>
|
|
/// <param name="viewEngine">The <see cref="ICompositeViewEngine"/>.</param>
|
|
/// <param name="tempDataFactory">The <see cref="ITempDataDictionaryFactory"/>.</param>
|
|
/// <param name="diagnosticSource">The <see cref="DiagnosticSource"/>.</param>
|
|
public ViewExecutor(
|
|
IOptions<MvcViewOptions> viewOptions,
|
|
IHttpResponseStreamWriterFactory writerFactory,
|
|
ICompositeViewEngine viewEngine,
|
|
ITempDataDictionaryFactory tempDataFactory,
|
|
DiagnosticSource diagnosticSource)
|
|
{
|
|
if (viewOptions == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(viewOptions));
|
|
}
|
|
|
|
if (writerFactory == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(writerFactory));
|
|
}
|
|
|
|
if (viewEngine == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(viewEngine));
|
|
}
|
|
|
|
if (tempDataFactory == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(tempDataFactory));
|
|
}
|
|
|
|
if (diagnosticSource == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(diagnosticSource));
|
|
}
|
|
|
|
ViewOptions = viewOptions.Value;
|
|
WriterFactory = writerFactory;
|
|
ViewEngine = viewEngine;
|
|
TempDataFactory = tempDataFactory;
|
|
DiagnosticSource = diagnosticSource;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the <see cref="DiagnosticSource"/>.
|
|
/// </summary>
|
|
protected DiagnosticSource DiagnosticSource { get; }
|
|
|
|
/// <summary>
|
|
/// Gets the <see cref="ITempDataDictionaryFactory"/>.
|
|
/// </summary>
|
|
protected ITempDataDictionaryFactory TempDataFactory { get; }
|
|
|
|
/// <summary>
|
|
/// Gets the default <see cref="IViewEngine"/>.
|
|
/// </summary>
|
|
protected IViewEngine ViewEngine { get; }
|
|
|
|
/// <summary>
|
|
/// Gets the <see cref="MvcViewOptions"/>.
|
|
/// </summary>
|
|
protected MvcViewOptions ViewOptions { get; }
|
|
|
|
/// <summary>
|
|
/// Gets the <see cref="IHttpResponseStreamWriterFactory"/>.
|
|
/// </summary>
|
|
protected IHttpResponseStreamWriterFactory WriterFactory { get; }
|
|
|
|
/// <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)
|
|
{
|
|
var services = actionContext.HttpContext.RequestServices;
|
|
var metadataProvider = services.GetRequiredService<IModelMetadataProvider>();
|
|
viewData = new ViewDataDictionary(metadataProvider, 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();
|
|
}
|
|
}
|
|
}
|
|
} |