| File: Controller.cs | Web Access |
| Project: src\aspnetcore\src\Mvc\Mvc.ViewFeatures\src\Microsoft.AspNetCore.Mvc.ViewFeatures.csproj (Microsoft.AspNetCore.Mvc.ViewFeatures) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. #nullable enable using System.Text.Json; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.Extensions.DependencyInjection; namespace Microsoft.AspNetCore.Mvc; /// <summary> /// A base class for an MVC controller with view support. /// </summary> public abstract class Controller : ControllerBase, IActionFilter, IAsyncActionFilter, IDisposable { private ITempDataDictionary? _tempData; private DynamicViewData? _viewBag; private ViewDataDictionary? _viewData; /// <summary> /// Gets or sets <see cref="ViewDataDictionary"/> used by <see cref="ViewResult"/> and <see cref="ViewBag"/>. /// </summary> /// <remarks> /// By default, this property is initialized when <see cref="Controllers.IControllerActivator"/> activates /// controllers. /// <para> /// This property can be accessed after the controller has been activated, for example, in a controller action /// or by overriding <see cref="OnActionExecuting(ActionExecutingContext)"/>. /// </para> /// <para> /// This property can be also accessed from within a unit test where it is initialized with /// <see cref="EmptyModelMetadataProvider"/>. /// </para> /// </remarks> [ViewDataDictionary] public ViewDataDictionary ViewData { get { if (_viewData == null) { // This should run only for the controller unit test scenarios _viewData = new ViewDataDictionary(new EmptyModelMetadataProvider(), ControllerContext.ModelState); } return _viewData!; } set { if (value == null) { throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(ViewData)); } _viewData = value; } } /// <summary> /// Gets or sets <see cref="ITempDataDictionary"/> used by <see cref="ViewResult"/>. /// </summary> public ITempDataDictionary TempData { get { if (_tempData == null) { var factory = HttpContext?.RequestServices?.GetRequiredService<ITempDataDictionaryFactory>(); _tempData = factory?.GetTempData(HttpContext); } return _tempData!; } set { ArgumentNullException.ThrowIfNull(value); _tempData = value; } } /// <summary> /// Gets the dynamic view bag. /// </summary> public dynamic ViewBag { get { if (_viewBag == null) { _viewBag = new DynamicViewData(() => ViewData); } return _viewBag; } } /// <summary> /// Creates a <see cref="ViewResult"/> object that renders a view to the response. /// </summary> /// <returns>The created <see cref="ViewResult"/> object for the response.</returns> [NonAction] public virtual ViewResult View() { return View(viewName: null); } /// <summary> /// Creates a <see cref="ViewResult"/> object by specifying a <paramref name="viewName"/>. /// </summary> /// <param name="viewName">The name or path of the view that is rendered to the response.</param> /// <returns>The created <see cref="ViewResult"/> object for the response.</returns> [NonAction] public virtual ViewResult View(string? viewName) { return View(viewName, model: ViewData.Model); } /// <summary> /// Creates a <see cref="ViewResult"/> object by specifying a <paramref name="model"/> /// to be rendered by the view. /// </summary> /// <param name="model">The model that is rendered by the view.</param> /// <returns>The created <see cref="ViewResult"/> object for the response.</returns> [NonAction] public virtual ViewResult View(object? model) { return View(viewName: null, model: model); } /// <summary> /// Creates a <see cref="ViewResult"/> object by specifying a <paramref name="viewName"/> /// and the <paramref name="model"/> to be rendered by the view. /// </summary> /// <param name="viewName">The name or path of the view that is rendered to the response.</param> /// <param name="model">The model that is rendered by the view.</param> /// <returns>The created <see cref="ViewResult"/> object for the response.</returns> [NonAction] public virtual ViewResult View(string? viewName, object? model) { ViewData.Model = model; return new ViewResult() { ViewName = viewName, ViewData = ViewData, TempData = TempData }; } /// <summary> /// Creates a <see cref="PartialViewResult"/> object that renders a partial view to the response. /// </summary> /// <returns>The created <see cref="PartialViewResult"/> object for the response.</returns> [NonAction] public virtual PartialViewResult PartialView() { return PartialView(viewName: null); } /// <summary> /// Creates a <see cref="PartialViewResult"/> object by specifying a <paramref name="viewName"/>. /// </summary> /// <param name="viewName">The name or path of the partial view that is rendered to the response.</param> /// <returns>The created <see cref="PartialViewResult"/> object for the response.</returns> [NonAction] public virtual PartialViewResult PartialView(string? viewName) { return PartialView(viewName, model: ViewData.Model); } /// <summary> /// Creates a <see cref="PartialViewResult"/> object by specifying a <paramref name="model"/> /// to be rendered by the partial view. /// </summary> /// <param name="model">The model that is rendered by the partial view.</param> /// <returns>The created <see cref="PartialViewResult"/> object for the response.</returns> [NonAction] public virtual PartialViewResult PartialView(object? model) { return PartialView(viewName: null, model: model); } /// <summary> /// Creates a <see cref="PartialViewResult"/> object by specifying a <paramref name="viewName"/> /// and the <paramref name="model"/> to be rendered by the partial view. /// </summary> /// <param name="viewName">The name or path of the partial view that is rendered to the response.</param> /// <param name="model">The model that is rendered by the partial view.</param> /// <returns>The created <see cref="PartialViewResult"/> object for the response.</returns> [NonAction] public virtual PartialViewResult PartialView(string? viewName, object? model) { ViewData.Model = model; return new PartialViewResult() { ViewName = viewName, ViewData = ViewData, TempData = TempData }; } /// <summary> /// Creates a <see cref="ViewComponentResult"/> by specifying the name of a view component to render. /// </summary> /// <param name="componentName"> /// The view component name. Can be a view component /// <see cref="ViewComponents.ViewComponentDescriptor.ShortName"/> or /// <see cref="ViewComponents.ViewComponentDescriptor.FullName"/>.</param> /// <returns>The created <see cref="ViewComponentResult"/> object for the response.</returns> [NonAction] public virtual ViewComponentResult ViewComponent(string componentName) { return ViewComponent(componentName, arguments: null); } /// <summary> /// Creates a <see cref="ViewComponentResult"/> by specifying the <see cref="Type"/> of a view component to /// render. /// </summary> /// <param name="componentType">The view component <see cref="Type"/>.</param> /// <returns>The created <see cref="ViewComponentResult"/> object for the response.</returns> [NonAction] public virtual ViewComponentResult ViewComponent(Type componentType) { return ViewComponent(componentType, arguments: null); } /// <summary> /// Creates a <see cref="ViewComponentResult"/> by specifying the name of a view component to render. /// </summary> /// <param name="componentName"> /// The view component name. Can be a view component /// <see cref="ViewComponents.ViewComponentDescriptor.ShortName"/> or /// <see cref="ViewComponents.ViewComponentDescriptor.FullName"/>.</param> /// <param name="arguments"> /// An <see cref="object"/> with properties representing arguments to be passed to the invoked view component /// method. Alternatively, an <see cref="System.Collections.Generic.IDictionary{String, Object}"/> instance /// containing the invocation arguments. /// </param> /// <returns>The created <see cref="ViewComponentResult"/> object for the response.</returns> [NonAction] public virtual ViewComponentResult ViewComponent(string componentName, object? arguments) { return new ViewComponentResult { ViewComponentName = componentName, Arguments = arguments, ViewData = ViewData, TempData = TempData }; } /// <summary> /// Creates a <see cref="ViewComponentResult"/> by specifying the <see cref="Type"/> of a view component to /// render. /// </summary> /// <param name="componentType">The view component <see cref="Type"/>.</param> /// <param name="arguments"> /// An <see cref="object"/> with properties representing arguments to be passed to the invoked view component /// method. Alternatively, an <see cref="System.Collections.Generic.IDictionary{String, Object}"/> instance /// containing the invocation arguments. /// </param> /// <returns>The created <see cref="ViewComponentResult"/> object for the response.</returns> [NonAction] public virtual ViewComponentResult ViewComponent(Type componentType, object? arguments) { return new ViewComponentResult { ViewComponentType = componentType, Arguments = arguments, ViewData = ViewData, TempData = TempData }; } /// <summary> /// Creates a <see cref="JsonResult"/> object that serializes the specified <paramref name="data"/> object /// to JSON. /// </summary> /// <param name="data">The object to serialize.</param> /// <returns>The created <see cref="JsonResult"/> that serializes the specified <paramref name="data"/> /// to JSON format for the response.</returns> [NonAction] public virtual JsonResult Json(object? data) { return new JsonResult(data); } /// <summary> /// Creates a <see cref="JsonResult"/> object that serializes the specified <paramref name="data"/> object /// to JSON. /// </summary> /// <param name="data">The object to serialize.</param> /// <param name="serializerSettings">The serializer settings to be used by the formatter. /// <para> /// When using <c>System.Text.Json</c>, this should be an instance of <see cref="JsonSerializerOptions" />. /// </para> /// <para> /// When using <c>Newtonsoft.Json</c>, this should be an instance of <c>JsonSerializerSettings</c>. /// </para> /// </param> /// <returns>The created <see cref="JsonResult"/> that serializes the specified <paramref name="data"/> /// as JSON format for the response.</returns> /// <remarks>Callers should cache an instance of serializer settings to avoid /// recreating cached data with each call.</remarks> [NonAction] public virtual JsonResult Json(object? data, object? serializerSettings) { return new JsonResult(data, serializerSettings); } /// <summary> /// Called before the action method is invoked. /// </summary> /// <param name="context">The action executing context.</param> [NonAction] public virtual void OnActionExecuting(ActionExecutingContext context) { } /// <summary> /// Called after the action method is invoked. /// </summary> /// <param name="context">The action executed context.</param> [NonAction] public virtual void OnActionExecuted(ActionExecutedContext context) { } /// <summary> /// Called before the action method is invoked. /// </summary> /// <param name="context">The action executing context.</param> /// <param name="next">The <see cref="ActionExecutionDelegate"/> to execute. Invoke this delegate in the body /// of <see cref="OnActionExecutionAsync" /> to continue execution of the action.</param> /// <returns>A <see cref="Task"/> instance.</returns> [NonAction] public virtual Task OnActionExecutionAsync( ActionExecutingContext context, ActionExecutionDelegate next) { ArgumentNullException.ThrowIfNull(context); ArgumentNullException.ThrowIfNull(next); OnActionExecuting(context); if (context.Result == null) { var task = next(); if (!task.IsCompletedSuccessfully) { return Awaited(this, task); } OnActionExecuted(task.Result); } return Task.CompletedTask; static async Task Awaited(Controller controller, Task<ActionExecutedContext> task) { controller.OnActionExecuted(await task); } } /// <inheritdoc /> public void Dispose() => Dispose(disposing: true); /// <summary> /// Releases all resources currently used by this <see cref="Controller"/> instance. /// </summary> /// <param name="disposing"><c>true</c> if this method is being invoked by the <see cref="Dispose()"/> method, /// otherwise <c>false</c>.</param> protected virtual void Dispose(bool disposing) { } }