// 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.Text; using System.Text.Encodings.Web; using System.Threading.Tasks; using Microsoft.AspNet.Html; using Microsoft.AspNet.Mvc.Internal; using Microsoft.AspNet.Mvc.Logging; using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.Rendering; using Microsoft.AspNet.Mvc.ViewEngines; using Microsoft.AspNet.Mvc.ViewFeatures; using Microsoft.AspNet.Mvc.ViewFeatures.Internal; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Microsoft.Net.Http.Headers; namespace Microsoft.AspNet.Mvc { /// /// An which renders a view component to the response. /// public class ViewComponentResult : ActionResult { /// /// Gets or sets the arguments provided to the view component. /// public object Arguments { get; set; } /// /// Gets or sets the representing the Content-Type header of the response. /// public MediaTypeHeaderValue ContentType { get; set; } /// /// Gets or sets the HTTP status code. /// public int? StatusCode { get; set; } /// /// Gets or sets the for this result. /// public ITempDataDictionary TempData { get; set; } /// /// Gets or sets the name of the view component to invoke. Will be ignored if /// is set to a non-null value. /// public string ViewComponentName { get; set; } /// /// Gets or sets the type of the view component to invoke. /// public Type ViewComponentType { get; set; } /// /// Gets or sets the for this result. /// public ViewDataDictionary ViewData { get; set; } /// /// Gets or sets the used to locate views. /// /// When null, an instance of from /// ActionContext.HttpContext.RequestServices is used. public IViewEngine ViewEngine { get; set; } /// public override async Task ExecuteResultAsync(ActionContext context) { var response = context.HttpContext.Response; var services = context.HttpContext.RequestServices; var htmlHelperOptions = services.GetRequiredService>().Value.HtmlHelperOptions; var viewComponentHelper = services.GetRequiredService(); var loggerFactory = services.GetRequiredService(); var logger = loggerFactory.CreateLogger(); var htmlEncoder = services.GetRequiredService(); var viewData = ViewData; if (viewData == null) { var modelMetadataProvider = services.GetRequiredService(); viewData = new ViewDataDictionary(modelMetadataProvider, context.ModelState); } var tempData = TempData; if (tempData == null) { var factory = services.GetRequiredService(); 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); } } private Task GetViewComponentResult(IViewComponentHelper viewComponentHelper, ILogger logger) { if (ViewComponentType == null && ViewComponentName == null) { throw new InvalidOperationException(Resources.FormatViewComponentResult_NameOrTypeMustBeSet( nameof(ViewComponentName), nameof(ViewComponentType))); } else if (ViewComponentType == null) { logger.ViewComponentResultExecuting(ViewComponentName); return viewComponentHelper.InvokeAsync(ViewComponentName, Arguments); } else { logger.ViewComponentResultExecuting(ViewComponentType); return viewComponentHelper.InvokeAsync(ViewComponentType, Arguments); } } } }