| File: ViewComponents\DefaultViewComponentHelper.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.Reflection; using System.Text.Encodings.Web; using Microsoft.AspNetCore.Html; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.AspNetCore.Mvc.ViewFeatures.Buffers; using Microsoft.Extensions.Internal; namespace Microsoft.AspNetCore.Mvc.ViewComponents; /// <summary> /// Default implementation for <see cref="IViewComponentHelper"/>. /// </summary> public class DefaultViewComponentHelper : IViewComponentHelper, IViewContextAware { private readonly IViewComponentDescriptorCollectionProvider _descriptorProvider; private readonly HtmlEncoder _htmlEncoder; private readonly IViewComponentInvokerFactory _invokerFactory; private readonly IViewComponentSelector _selector; private readonly IViewBufferScope _viewBufferScope; private ViewContext _viewContext = default!; /// <summary> /// Initializes a new instance of <see cref="DefaultViewComponentHelper"/>. /// </summary> /// <param name="descriptorProvider">The <see cref="IViewComponentDescriptorCollectionProvider"/> /// used to locate view components.</param> /// <param name="htmlEncoder">The <see cref="HtmlEncoder"/>.</param> /// <param name="selector">The <see cref="IViewComponentSelector"/>.</param> /// <param name="invokerFactory">The <see cref="IViewComponentInvokerFactory"/>.</param> /// <param name="viewBufferScope">The <see cref="IViewBufferScope"/> that manages the lifetime of /// <see cref="ViewBuffer"/> instances.</param> public DefaultViewComponentHelper( IViewComponentDescriptorCollectionProvider descriptorProvider, HtmlEncoder htmlEncoder, IViewComponentSelector selector, IViewComponentInvokerFactory invokerFactory, IViewBufferScope viewBufferScope) { ArgumentNullException.ThrowIfNull(descriptorProvider); ArgumentNullException.ThrowIfNull(htmlEncoder); ArgumentNullException.ThrowIfNull(selector); ArgumentNullException.ThrowIfNull(invokerFactory); ArgumentNullException.ThrowIfNull(viewBufferScope); _descriptorProvider = descriptorProvider; _htmlEncoder = htmlEncoder; _selector = selector; _invokerFactory = invokerFactory; _viewBufferScope = viewBufferScope; } /// <inheritdoc /> public void Contextualize(ViewContext viewContext) { ArgumentNullException.ThrowIfNull(viewContext); _viewContext = viewContext; } /// <inheritdoc /> public Task<IHtmlContent> InvokeAsync(string name, object? arguments) { ArgumentNullException.ThrowIfNull(name); var descriptor = _selector.SelectComponent(name); if (descriptor == null) { throw new InvalidOperationException(Resources.FormatViewComponent_CannotFindComponent( name, nameof(ViewComponentAttribute), ViewComponentConventions.ViewComponentSuffix, nameof(NonViewComponentAttribute))); } return InvokeCoreAsync(descriptor, arguments); } /// <inheritdoc /> public Task<IHtmlContent> InvokeAsync(Type componentType, object? arguments) { ArgumentNullException.ThrowIfNull(componentType); var descriptor = SelectComponent(componentType); return InvokeCoreAsync(descriptor, arguments); } private ViewComponentDescriptor SelectComponent(Type componentType) { var descriptors = _descriptorProvider.ViewComponents; for (var i = 0; i < descriptors.Items.Count; i++) { var descriptor = descriptors.Items[i]; if (descriptor.TypeInfo == componentType.GetTypeInfo()) { return descriptor; } } throw new InvalidOperationException(Resources.FormatViewComponent_CannotFindComponent( componentType.FullName, nameof(ViewComponentAttribute), ViewComponentConventions.ViewComponentSuffix, nameof(NonViewComponentAttribute))); } // Internal for testing internal static IDictionary<string, object?> GetArgumentDictionary(ViewComponentDescriptor descriptor, object? arguments) { if (arguments != null) { if (descriptor.Parameters.Count == 1 && descriptor.Parameters[0].ParameterType.IsAssignableFrom(arguments.GetType())) { return new Dictionary<string, object?>(capacity: 1, comparer: StringComparer.OrdinalIgnoreCase) { { descriptor.Parameters[0].Name!, arguments } }; } } return PropertyHelper.ObjectToDictionary(arguments); } private async Task<IHtmlContent> InvokeCoreAsync(ViewComponentDescriptor descriptor, object? arguments) { var argumentDictionary = GetArgumentDictionary(descriptor, arguments); var viewBuffer = new ViewBuffer(_viewBufferScope, descriptor.FullName, ViewBuffer.ViewComponentPageSize); using (var writer = new ViewBufferTextWriter(viewBuffer, _viewContext.Writer.Encoding)) { var context = new ViewComponentContext(descriptor, argumentDictionary, _htmlEncoder, _viewContext, writer); var invoker = _invokerFactory.CreateInstance(context); if (invoker == null) { throw new InvalidOperationException( Resources.FormatViewComponent_IViewComponentFactory_ReturnedNull(descriptor.FullName)); } await invoker.InvokeAsync(context); return viewBuffer; } } }