| File: ViewComponents\DefaultViewComponentSelector.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. using System.Linq; using Microsoft.AspNetCore.Mvc.ViewFeatures; namespace Microsoft.AspNetCore.Mvc.ViewComponents; /// <summary> /// Default implementation of <see cref="IViewComponentSelector"/>. /// </summary> public class DefaultViewComponentSelector : IViewComponentSelector { private readonly IViewComponentDescriptorCollectionProvider _descriptorProvider; private ViewComponentDescriptorCache _cache; /// <summary> /// Creates a new <see cref="DefaultViewComponentSelector"/>. /// </summary> /// <param name="descriptorProvider">The <see cref="IViewComponentDescriptorCollectionProvider"/>.</param> public DefaultViewComponentSelector(IViewComponentDescriptorCollectionProvider descriptorProvider) { _descriptorProvider = descriptorProvider; } /// <inheritdoc /> public ViewComponentDescriptor SelectComponent(string componentName) { ArgumentNullException.ThrowIfNull(componentName); var collection = _descriptorProvider.ViewComponents; if (_cache == null || _cache.Version != collection.Version) { _cache = new ViewComponentDescriptorCache(collection); } // ViewComponent names can either be fully-qualified, or refer to the 'short-name'. If the provided // name contains a '.' - then it's a fully-qualified name. if (componentName.Contains('.')) { return _cache.SelectByFullName(componentName); } else { return _cache.SelectByShortName(componentName); } } private sealed class ViewComponentDescriptorCache { private readonly ILookup<string, ViewComponentDescriptor> _lookupByShortName; private readonly ILookup<string, ViewComponentDescriptor> _lookupByFullName; public ViewComponentDescriptorCache(ViewComponentDescriptorCollection collection) { Version = collection.Version; _lookupByShortName = collection.Items.ToLookup(c => c.ShortName, c => c); _lookupByFullName = collection.Items.ToLookup(c => c.FullName, c => c); } public int Version { get; } public ViewComponentDescriptor SelectByShortName(string name) { return Select(_lookupByShortName, name); } public ViewComponentDescriptor SelectByFullName(string name) { return Select(_lookupByFullName, name); } private static ViewComponentDescriptor Select( ILookup<string, ViewComponentDescriptor> candidates, string name) { var matches = candidates[name]; var count = matches.Count(); if (count == 0) { return null; } else if (count == 1) { return matches.Single(); } else { var matchedTypes = new List<string>(); foreach (var candidate in matches) { matchedTypes.Add(Resources.FormatViewComponent_AmbiguousTypeMatch_Item( candidate.TypeInfo.FullName, candidate.FullName)); } var typeNames = string.Join(Environment.NewLine, matchedTypes); throw new InvalidOperationException( Resources.FormatViewComponent_AmbiguousTypeMatch(name, Environment.NewLine, typeNames)); } } } }