Refactor of ViewComponent extensibility
Adds ViewComponentDescriptor and caching (provider, collection, collectionprovider). Removes IViewComponentInvokerProvider, simplifies IViewComponentInvokerFactory.
This commit is contained in:
parent
533474d07c
commit
2b82ee0255
|
|
@ -9,7 +9,7 @@ using Microsoft.AspNet.Mvc.Rendering;
|
|||
using Microsoft.Framework.DependencyInjection;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
namespace Microsoft.AspNet.Mvc.ViewComponents
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the <see cref="IViewComponentActivator"/> that is registered by default.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ViewComponents
|
||||
{
|
||||
/// <summary>
|
||||
/// A default implementation of <see cref="IViewComponentDescriptorCollectionProvider"/>
|
||||
/// </summary>
|
||||
public class DefaultViewComponentDescriptorCollectionProvider : IViewComponentDescriptorCollectionProvider
|
||||
{
|
||||
private readonly IViewComponentDescriptorProvider _descriptorProvider;
|
||||
private ViewComponentDescriptorCollection _viewComponents;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of <see cref="DefaultViewComponentDescriptorCollectionProvider"/>.
|
||||
/// </summary>
|
||||
/// <param name="descriptorProvider">The <see cref="IViewComponentDescriptorProvider"/>.</param>
|
||||
public DefaultViewComponentDescriptorCollectionProvider(IViewComponentDescriptorProvider descriptorProvider)
|
||||
{
|
||||
_descriptorProvider = descriptorProvider;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ViewComponentDescriptorCollection ViewComponents
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_viewComponents == null)
|
||||
{
|
||||
_viewComponents = GetViewComponents();
|
||||
}
|
||||
|
||||
return _viewComponents;
|
||||
}
|
||||
}
|
||||
|
||||
private ViewComponentDescriptorCollection GetViewComponents()
|
||||
{
|
||||
var descriptors = _descriptorProvider.GetViewComponents();
|
||||
return new ViewComponentDescriptorCollection(descriptors.ToArray(), version: 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ViewComponents
|
||||
{
|
||||
/// <summary>
|
||||
/// Default implementation of <see cref="IViewComponentDescriptorProvider"/>.
|
||||
/// </summary>
|
||||
public class DefaultViewComponentDescriptorProvider : IViewComponentDescriptorProvider
|
||||
{
|
||||
private readonly IAssemblyProvider _assemblyProvider;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="DefaultViewComponentDescriptorProvider"/>.
|
||||
/// </summary>
|
||||
/// <param name="assemblyProvider">The <see cref="IAssemblyProvider"/>.</param>
|
||||
public DefaultViewComponentDescriptorProvider(IAssemblyProvider assemblyProvider)
|
||||
{
|
||||
_assemblyProvider = assemblyProvider;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual IEnumerable<ViewComponentDescriptor> GetViewComponents()
|
||||
{
|
||||
var types = GetCandidateTypes();
|
||||
|
||||
return types
|
||||
.Where(IsViewComponentType)
|
||||
.Select(CreateCandidate);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the candidate <see cref="TypeInfo"/> instances. The results of this will be provided to
|
||||
/// <see cref="IsViewComponentType"/> for filtering.
|
||||
/// </summary>
|
||||
/// <returns>A list of <see cref="TypeInfo"/> instances.</returns>
|
||||
protected virtual IEnumerable<TypeInfo> GetCandidateTypes()
|
||||
{
|
||||
var assemblies = _assemblyProvider.CandidateAssemblies;
|
||||
return assemblies.SelectMany(a => a.ExportedTypes).Select(t => t.GetTypeInfo());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether or not the given <see cref="TypeInfo"/> is a View Component class.
|
||||
/// </summary>
|
||||
/// <param name="typeInfo">The <see cref="TypeInfo"/>.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if <paramref name="typeInfo"/>represents a View Component class, otherwise <c>false</c>.
|
||||
/// </returns>
|
||||
protected virtual bool IsViewComponentType([NotNull] TypeInfo typeInfo)
|
||||
{
|
||||
return ViewComponentConventions.IsComponent(typeInfo);
|
||||
}
|
||||
|
||||
private static ViewComponentDescriptor CreateCandidate(TypeInfo typeInfo)
|
||||
{
|
||||
var candidate = new ViewComponentDescriptor()
|
||||
{
|
||||
FullName = ViewComponentConventions.GetComponentFullName(typeInfo),
|
||||
ShortName = ViewComponentConventions.GetComponentName(typeInfo),
|
||||
Type = typeInfo.AsType(),
|
||||
};
|
||||
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -13,14 +13,17 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
|
|||
{
|
||||
public class DefaultViewComponentHelper : IViewComponentHelper, ICanHasViewContext
|
||||
{
|
||||
private readonly IViewComponentDescriptorCollectionProvider _descriptorProvider;
|
||||
private readonly IViewComponentInvokerFactory _invokerFactory;
|
||||
private readonly IViewComponentSelector _selector;
|
||||
private ViewContext _viewContext;
|
||||
|
||||
public DefaultViewComponentHelper(
|
||||
[NotNull] IViewComponentDescriptorCollectionProvider descriptorProvider,
|
||||
[NotNull] IViewComponentSelector selector,
|
||||
[NotNull] IViewComponentInvokerFactory invokerFactory)
|
||||
{
|
||||
_descriptorProvider = descriptorProvider;
|
||||
_selector = selector;
|
||||
_invokerFactory = invokerFactory;
|
||||
}
|
||||
|
|
@ -30,92 +33,129 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
|
|||
_viewContext = viewContext;
|
||||
}
|
||||
|
||||
public HtmlString Invoke([NotNull] string name, params object[] args)
|
||||
public HtmlString Invoke([NotNull] string name, params object[] arguments)
|
||||
{
|
||||
var componentType = SelectComponent(name);
|
||||
return Invoke(componentType, args);
|
||||
}
|
||||
var descriptor = SelectComponent(name);
|
||||
|
||||
public HtmlString Invoke([NotNull] Type componentType, params object[] args)
|
||||
{
|
||||
using (var writer = new StringWriter())
|
||||
{
|
||||
InvokeCore(writer, componentType, args);
|
||||
InvokeCore(writer, descriptor, arguments);
|
||||
return new HtmlString(writer.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public void RenderInvoke([NotNull] string name, params object[] args)
|
||||
public HtmlString Invoke([NotNull] Type componentType, params object[] arguments)
|
||||
{
|
||||
var componentType = SelectComponent(name);
|
||||
InvokeCore(_viewContext.Writer, componentType, args);
|
||||
}
|
||||
var descriptor = SelectComponent(componentType);
|
||||
|
||||
public void RenderInvoke([NotNull] Type componentType, params object[] args)
|
||||
{
|
||||
InvokeCore(_viewContext.Writer, componentType, args);
|
||||
}
|
||||
|
||||
public async Task<HtmlString> InvokeAsync([NotNull] string name, params object[] args)
|
||||
{
|
||||
var componentType = SelectComponent(name);
|
||||
return await InvokeAsync(componentType, args);
|
||||
}
|
||||
|
||||
public async Task<HtmlString> InvokeAsync([NotNull] Type componentType, params object[] args)
|
||||
{
|
||||
using (var writer = new StringWriter())
|
||||
{
|
||||
await InvokeCoreAsync(writer, componentType, args);
|
||||
InvokeCore(writer, descriptor, arguments);
|
||||
return new HtmlString(writer.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public async Task RenderInvokeAsync([NotNull] string name, params object[] args)
|
||||
public void RenderInvoke([NotNull] string name, params object[] arguments)
|
||||
{
|
||||
var componentType = SelectComponent(name);
|
||||
await InvokeCoreAsync(_viewContext.Writer, componentType, args);
|
||||
var descriptor = SelectComponent(name);
|
||||
InvokeCore(_viewContext.Writer, descriptor, arguments);
|
||||
}
|
||||
|
||||
public async Task RenderInvokeAsync([NotNull] Type componentType, params object[] args)
|
||||
public void RenderInvoke([NotNull] Type componentType, params object[] arguments)
|
||||
{
|
||||
await InvokeCoreAsync(_viewContext.Writer, componentType, args);
|
||||
var descriptor = SelectComponent(componentType);
|
||||
InvokeCore(_viewContext.Writer, descriptor, arguments);
|
||||
}
|
||||
|
||||
private Type SelectComponent([NotNull] string name)
|
||||
public async Task<HtmlString> InvokeAsync([NotNull] string name, params object[] arguments)
|
||||
{
|
||||
var componentType = _selector.SelectComponent(name);
|
||||
if (componentType == null)
|
||||
var descriptor = SelectComponent(name);
|
||||
|
||||
using (var writer = new StringWriter())
|
||||
{
|
||||
await InvokeCoreAsync(writer, descriptor, arguments);
|
||||
return new HtmlString(writer.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<HtmlString> InvokeAsync([NotNull] Type componentType, params object[] arguments)
|
||||
{
|
||||
var descriptor = SelectComponent(componentType);
|
||||
|
||||
using (var writer = new StringWriter())
|
||||
{
|
||||
await InvokeCoreAsync(writer, descriptor, arguments);
|
||||
return new HtmlString(writer.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public async Task RenderInvokeAsync([NotNull] string name, params object[] arguments)
|
||||
{
|
||||
var descriptor = SelectComponent(name);
|
||||
await InvokeCoreAsync(_viewContext.Writer, descriptor, arguments);
|
||||
}
|
||||
|
||||
public async Task RenderInvokeAsync([NotNull] Type componentType, params object[] arguments)
|
||||
{
|
||||
var descriptor = SelectComponent(componentType);
|
||||
await InvokeCoreAsync(_viewContext.Writer, descriptor, arguments);
|
||||
}
|
||||
|
||||
private ViewComponentDescriptor SelectComponent(string name)
|
||||
{
|
||||
var descriptor = _selector.SelectComponent(name);
|
||||
if (descriptor == null)
|
||||
{
|
||||
throw new InvalidOperationException(Resources.FormatViewComponent_CannotFindComponent(name));
|
||||
}
|
||||
|
||||
return componentType;
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
private async Task InvokeCoreAsync([NotNull] TextWriter writer, [NotNull] Type componentType, object[] args)
|
||||
private ViewComponentDescriptor SelectComponent(Type componentType)
|
||||
{
|
||||
var invoker = _invokerFactory.CreateInstance(componentType.GetTypeInfo(), args);
|
||||
var descriptors = _descriptorProvider.ViewComponents;
|
||||
foreach (var descriptor in descriptors.Items)
|
||||
{
|
||||
if (descriptor.Type == componentType)
|
||||
{
|
||||
return descriptor;
|
||||
}
|
||||
}
|
||||
|
||||
throw new InvalidOperationException(Resources.FormatViewComponent_CannotFindComponent(
|
||||
componentType.FullName));
|
||||
}
|
||||
|
||||
private async Task InvokeCoreAsync(
|
||||
[NotNull] TextWriter writer,
|
||||
[NotNull] ViewComponentDescriptor descriptor,
|
||||
object[] arguments)
|
||||
{
|
||||
var invoker = _invokerFactory.CreateInstance(descriptor, arguments);
|
||||
if (invoker == null)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
Resources.FormatViewComponent_IViewComponentFactory_ReturnedNull(componentType));
|
||||
Resources.FormatViewComponent_IViewComponentFactory_ReturnedNull(descriptor.Type.FullName));
|
||||
}
|
||||
|
||||
var context = new ViewComponentContext(componentType.GetTypeInfo(), _viewContext, writer);
|
||||
var context = new ViewComponentContext(descriptor, arguments, _viewContext, writer);
|
||||
await invoker.InvokeAsync(context);
|
||||
}
|
||||
|
||||
private void InvokeCore([NotNull] TextWriter writer, [NotNull] Type componentType, object[] arguments)
|
||||
private void InvokeCore(
|
||||
[NotNull] TextWriter writer,
|
||||
[NotNull] ViewComponentDescriptor descriptor,
|
||||
object[] arguments)
|
||||
{
|
||||
var invoker = _invokerFactory.CreateInstance(componentType.GetTypeInfo(), arguments);
|
||||
var invoker = _invokerFactory.CreateInstance(descriptor, arguments);
|
||||
if (invoker == null)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
Resources.FormatViewComponent_IViewComponentFactory_ReturnedNull(componentType));
|
||||
Resources.FormatViewComponent_IViewComponentFactory_ReturnedNull(descriptor.Type.FullName));
|
||||
}
|
||||
|
||||
var context = new ViewComponentContext(componentType.GetTypeInfo(), _viewContext, writer);
|
||||
var context = new ViewComponentContext(descriptor, arguments, _viewContext, writer);
|
||||
invoker.Invoke(context);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,43 +7,38 @@ using System.Runtime.ExceptionServices;
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Mvc.Core;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
namespace Microsoft.AspNet.Mvc.ViewComponents
|
||||
{
|
||||
public class DefaultViewComponentInvoker : IViewComponentInvoker
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly ITypeActivatorCache _typeActivatorCache;
|
||||
private readonly TypeInfo _componentType;
|
||||
private readonly IViewComponentActivator _viewComponentActivator;
|
||||
private readonly object[] _args;
|
||||
|
||||
public DefaultViewComponentInvoker(
|
||||
[NotNull] IServiceProvider serviceProvider,
|
||||
[NotNull] ITypeActivatorCache typeActivatorCache,
|
||||
[NotNull] IViewComponentActivator viewComponentActivator,
|
||||
[NotNull] TypeInfo componentType,
|
||||
object[] args)
|
||||
[NotNull] IViewComponentActivator viewComponentActivator)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
_typeActivatorCache = typeActivatorCache;
|
||||
_componentType = componentType;
|
||||
_viewComponentActivator = viewComponentActivator;
|
||||
_args = args ?? new object[0];
|
||||
}
|
||||
|
||||
public void Invoke([NotNull] ViewComponentContext context)
|
||||
{
|
||||
var method = ViewComponentMethodSelector.FindSyncMethod(_componentType, _args);
|
||||
var method = ViewComponentMethodSelector.FindSyncMethod(
|
||||
context.ViewComponentDescriptor.Type.GetTypeInfo(),
|
||||
context.Arguments);
|
||||
if (method == null)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
Resources.FormatViewComponent_CannotFindMethod(ViewComponentMethodSelector.SyncMethodName));
|
||||
}
|
||||
|
||||
var result = InvokeSyncCore(method, context.ViewContext);
|
||||
var result = InvokeSyncCore(method, context);
|
||||
result.Execute(context);
|
||||
}
|
||||
|
||||
|
|
@ -51,12 +46,16 @@ namespace Microsoft.AspNet.Mvc
|
|||
{
|
||||
IViewComponentResult result;
|
||||
|
||||
var asyncMethod = ViewComponentMethodSelector.FindAsyncMethod(_componentType, _args);
|
||||
var asyncMethod = ViewComponentMethodSelector.FindAsyncMethod(
|
||||
context.ViewComponentDescriptor.Type.GetTypeInfo(),
|
||||
context.Arguments);
|
||||
if (asyncMethod == null)
|
||||
{
|
||||
// We support falling back to synchronous if there is no InvokeAsync method, in this case we'll still
|
||||
// execute the IViewResult asynchronously.
|
||||
var syncMethod = ViewComponentMethodSelector.FindSyncMethod(_componentType, _args);
|
||||
var syncMethod = ViewComponentMethodSelector.FindSyncMethod(
|
||||
context.ViewComponentDescriptor.Type.GetTypeInfo(),
|
||||
context.Arguments);
|
||||
if (syncMethod == null)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
|
|
@ -65,36 +64,38 @@ namespace Microsoft.AspNet.Mvc
|
|||
}
|
||||
else
|
||||
{
|
||||
result = InvokeSyncCore(syncMethod, context.ViewContext);
|
||||
result = InvokeSyncCore(syncMethod, context);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = await InvokeAsyncCore(asyncMethod, context.ViewContext);
|
||||
result = await InvokeAsyncCore(asyncMethod, context);
|
||||
}
|
||||
|
||||
await result.ExecuteAsync(context);
|
||||
}
|
||||
|
||||
private object CreateComponent([NotNull] ViewContext context)
|
||||
private object CreateComponent([NotNull] ViewComponentContext context)
|
||||
{
|
||||
var component = _typeActivatorCache.CreateInstance<object>(_serviceProvider, _componentType.AsType());
|
||||
_viewComponentActivator.Activate(component, context);
|
||||
var component = _typeActivatorCache.CreateInstance<object>(
|
||||
_serviceProvider,
|
||||
context.ViewComponentDescriptor.Type);
|
||||
_viewComponentActivator.Activate(component, context.ViewContext);
|
||||
return component;
|
||||
}
|
||||
|
||||
private async Task<IViewComponentResult> InvokeAsyncCore(
|
||||
[NotNull] MethodInfo method,
|
||||
[NotNull] ViewContext context)
|
||||
[NotNull] ViewComponentContext context)
|
||||
{
|
||||
var component = CreateComponent(context);
|
||||
|
||||
var result = await ControllerActionExecutor.ExecuteAsync(method, component, _args);
|
||||
var result = await ControllerActionExecutor.ExecuteAsync(method, component, context.Arguments);
|
||||
|
||||
return CoerceToViewComponentResult(result);
|
||||
}
|
||||
|
||||
public IViewComponentResult InvokeSyncCore([NotNull] MethodInfo method, [NotNull] ViewContext context)
|
||||
public IViewComponentResult InvokeSyncCore([NotNull] MethodInfo method, [NotNull] ViewComponentContext context)
|
||||
{
|
||||
var component = CreateComponent(context);
|
||||
|
||||
|
|
@ -102,7 +103,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
|
||||
try
|
||||
{
|
||||
result = method.Invoke(component, _args);
|
||||
result = method.Invoke(component, context.Arguments);
|
||||
}
|
||||
catch (TargetInvocationException ex)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,38 +1,39 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ViewComponents
|
||||
{
|
||||
public class DefaultViewComponentInvokerFactory : IViewComponentInvokerFactory
|
||||
{
|
||||
private readonly IViewComponentInvokerProvider[] _providers;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly ITypeActivatorCache _typeActivatorCache;
|
||||
private readonly IViewComponentActivator _viewComponentActivator;
|
||||
|
||||
public DefaultViewComponentInvokerFactory(
|
||||
IEnumerable<IViewComponentInvokerProvider> providers)
|
||||
IServiceProvider serviceProvider,
|
||||
ITypeActivatorCache typeActivatorCache,
|
||||
IViewComponentActivator viewComponentActivator)
|
||||
{
|
||||
_providers = providers.OrderBy(item => item.Order).ToArray();
|
||||
_serviceProvider = serviceProvider;
|
||||
_typeActivatorCache = typeActivatorCache;
|
||||
_viewComponentActivator = viewComponentActivator;
|
||||
}
|
||||
|
||||
public IViewComponentInvoker CreateInstance([NotNull] TypeInfo componentType, object[] args)
|
||||
/// <inheritdoc />
|
||||
// We don't currently make use of the descriptor or the arguments here (they are available on the context).
|
||||
// We might do this some day to cache which method we select, so resist the urge to 'clean' this without
|
||||
// considering that possibility.
|
||||
public IViewComponentInvoker CreateInstance(
|
||||
[NotNull] ViewComponentDescriptor viewComponentDescriptor,
|
||||
object[] args)
|
||||
{
|
||||
var context = new ViewComponentInvokerProviderContext(componentType, args);
|
||||
|
||||
foreach (var provider in _providers)
|
||||
{
|
||||
provider.OnProvidersExecuting(context);
|
||||
}
|
||||
|
||||
for (var i = _providers.Length - 1; i >= 0; i--)
|
||||
{
|
||||
_providers[i].OnProvidersExecuted(context);
|
||||
}
|
||||
|
||||
return context.Result;
|
||||
return new DefaultViewComponentInvoker(
|
||||
_serviceProvider,
|
||||
_typeActivatorCache,
|
||||
_viewComponentActivator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,46 +0,0 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ViewComponents
|
||||
{
|
||||
public class DefaultViewComponentInvokerProvider : IViewComponentInvokerProvider
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly ITypeActivatorCache _typeActivatorCache;
|
||||
private readonly IViewComponentActivator _viewComponentActivator;
|
||||
|
||||
public DefaultViewComponentInvokerProvider(
|
||||
IServiceProvider serviceProvider,
|
||||
ITypeActivatorCache typeActivatorCache,
|
||||
IViewComponentActivator viewComponentActivator)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
_typeActivatorCache = typeActivatorCache;
|
||||
_viewComponentActivator = viewComponentActivator;
|
||||
}
|
||||
|
||||
public int Order
|
||||
{
|
||||
get { return DefaultOrder.DefaultFrameworkSortOrder; }
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnProvidersExecuting([NotNull] ViewComponentInvokerProviderContext context)
|
||||
{
|
||||
context.Result = new DefaultViewComponentInvoker(
|
||||
_serviceProvider,
|
||||
_typeActivatorCache,
|
||||
_viewComponentActivator,
|
||||
context.ComponentType,
|
||||
context.Arguments);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnProvidersExecuted([NotNull] ViewComponentInvokerProviderContext context)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,44 +3,41 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNet.Mvc.Core;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
namespace Microsoft.AspNet.Mvc.ViewComponents
|
||||
{
|
||||
/// <summary>
|
||||
/// Default implementation of <see cref="IViewComponentSelector"/>.
|
||||
/// </summary>
|
||||
public class DefaultViewComponentSelector : IViewComponentSelector
|
||||
{
|
||||
private readonly IAssemblyProvider _assemblyProvider;
|
||||
private readonly IViewComponentDescriptorCollectionProvider _descriptorProvider;
|
||||
|
||||
private ViewComponentCandidateCache _cache;
|
||||
private ViewComponentDescriptorCache _cache;
|
||||
|
||||
public DefaultViewComponentSelector(IAssemblyProvider assemblyProvider)
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="DefaultViewComponentSelector"/>.
|
||||
/// </summary>
|
||||
/// <param name="descriptorProvider">The <see cref="IViewComponentDescriptorCollectionProvider"/>.</param>
|
||||
public DefaultViewComponentSelector(IViewComponentDescriptorCollectionProvider descriptorProvider)
|
||||
{
|
||||
_assemblyProvider = assemblyProvider;
|
||||
_descriptorProvider = descriptorProvider;
|
||||
}
|
||||
|
||||
public Type SelectComponent([NotNull] string componentName)
|
||||
/// <inheritdoc />
|
||||
public ViewComponentDescriptor SelectComponent([NotNull] string componentName)
|
||||
{
|
||||
if (_cache == null)
|
||||
var collection = _descriptorProvider.ViewComponents;
|
||||
if (_cache == null || _cache.Version != collection.Version)
|
||||
{
|
||||
var assemblies = _assemblyProvider.CandidateAssemblies;
|
||||
var types = assemblies.SelectMany(a => a.DefinedTypes);
|
||||
|
||||
var candidates =
|
||||
types
|
||||
.Where(IsViewComponentType)
|
||||
.Select(CreateCandidate)
|
||||
.ToArray();
|
||||
|
||||
_cache = new ViewComponentCandidateCache(candidates);
|
||||
_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.
|
||||
var matching = new List<ViewComponentCandidate>();
|
||||
if (componentName.Contains("."))
|
||||
{
|
||||
return _cache.SelectByFullName(componentName);
|
||||
|
|
@ -51,65 +48,34 @@ namespace Microsoft.AspNet.Mvc
|
|||
}
|
||||
}
|
||||
|
||||
protected virtual bool IsViewComponentType([NotNull] TypeInfo typeInfo)
|
||||
private class ViewComponentDescriptorCache
|
||||
{
|
||||
return ViewComponentConventions.IsComponent(typeInfo);
|
||||
}
|
||||
private readonly ILookup<string, ViewComponentDescriptor> _lookupByShortName;
|
||||
private readonly ILookup<string, ViewComponentDescriptor> _lookupByFullName;
|
||||
|
||||
private static ViewComponentCandidate CreateCandidate(TypeInfo typeInfo)
|
||||
{
|
||||
var candidate = new ViewComponentCandidate()
|
||||
public ViewComponentDescriptorCache(ViewComponentDescriptorCollection collection)
|
||||
{
|
||||
FullName = ViewComponentConventions.GetComponentFullName(typeInfo),
|
||||
ShortName = ViewComponentConventions.GetComponentName(typeInfo),
|
||||
Type = typeInfo.AsType(),
|
||||
};
|
||||
Version = collection.Version;
|
||||
|
||||
Debug.Assert(!string.IsNullOrEmpty(candidate.FullName));
|
||||
var separatorIndex = candidate.FullName.LastIndexOf('.');
|
||||
if (separatorIndex >= 0)
|
||||
{
|
||||
candidate.ShortName = candidate.FullName.Substring(separatorIndex + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
candidate.ShortName = candidate.FullName;
|
||||
_lookupByShortName = collection.Items.ToLookup(c => c.ShortName, c => c);
|
||||
_lookupByFullName = collection.Items.ToLookup(c => c.FullName, c => c);
|
||||
}
|
||||
|
||||
return candidate;
|
||||
}
|
||||
public int Version { get; }
|
||||
|
||||
private class ViewComponentCandidate
|
||||
{
|
||||
public string FullName { get; set; }
|
||||
|
||||
public string ShortName { get; set; }
|
||||
|
||||
public Type Type { get; set; }
|
||||
}
|
||||
|
||||
private class ViewComponentCandidateCache
|
||||
{
|
||||
private readonly ILookup<string, ViewComponentCandidate> _lookupByShortName;
|
||||
private readonly ILookup<string, ViewComponentCandidate> _lookupByFullName;
|
||||
|
||||
public ViewComponentCandidateCache(ViewComponentCandidate[] candidates)
|
||||
{
|
||||
_lookupByShortName = candidates.ToLookup(c => c.ShortName, c => c);
|
||||
_lookupByFullName = candidates.ToLookup(c => c.FullName, c => c);
|
||||
}
|
||||
|
||||
public Type SelectByShortName(string name)
|
||||
public ViewComponentDescriptor SelectByShortName(string name)
|
||||
{
|
||||
return Select(_lookupByShortName, name);
|
||||
}
|
||||
|
||||
public Type SelectByFullName(string name)
|
||||
public ViewComponentDescriptor SelectByFullName(string name)
|
||||
{
|
||||
return Select(_lookupByFullName, name);
|
||||
}
|
||||
|
||||
private static Type Select(ILookup<string, ViewComponentCandidate> candidates, string name)
|
||||
private static ViewComponentDescriptor Select(
|
||||
ILookup<string, ViewComponentDescriptor> candidates,
|
||||
string name)
|
||||
{
|
||||
var matches = candidates[name];
|
||||
|
||||
|
|
@ -120,7 +86,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
}
|
||||
else if (count == 1)
|
||||
{
|
||||
return matches.Single().Type;
|
||||
return matches.Single();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
namespace Microsoft.AspNet.Mvc.ViewComponents
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides methods to activate an instantiated ViewComponent
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ViewComponents
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides the currently cached collection of <see cref="ViewComponentDescriptor"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The default implementation does not update the cache, it is up to the user
|
||||
/// to create or use an implementation that can update the available view components in
|
||||
/// the application. The implementor is also responsible for updating the
|
||||
/// <see cref="ViewComponentDescriptorCollection.Version"/> in a thread safe way.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Default consumers of this service, are aware of the version and will recache
|
||||
/// data as appropriate, but rely on the version being unique.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public interface IViewComponentDescriptorCollectionProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the current cached <see cref="ViewComponentDescriptorCollection"/>.
|
||||
/// </summary>
|
||||
ViewComponentDescriptorCollection ViewComponents { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ViewComponents
|
||||
{
|
||||
/// <summary>
|
||||
/// Discovers the View Components in the application.
|
||||
/// </summary>
|
||||
public interface IViewComponentDescriptorProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the set of <see cref="ViewComponentDescriptor"/>.
|
||||
/// </summary>
|
||||
/// <returns>A list of <see cref="ViewComponentDescriptor"/>.</returns>
|
||||
IEnumerable<ViewComponentDescriptor> GetViewComponents();
|
||||
}
|
||||
}
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
namespace Microsoft.AspNet.Mvc.ViewComponents
|
||||
{
|
||||
public interface IViewComponentInvoker
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Reflection;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ViewComponents
|
||||
{
|
||||
public interface IViewComponentInvokerFactory
|
||||
{
|
||||
IViewComponentInvoker CreateInstance([NotNull] TypeInfo componentType, object[] args);
|
||||
IViewComponentInvoker CreateInstance(
|
||||
[NotNull] ViewComponentDescriptor viewComponentDescriptor,
|
||||
object[] args);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +0,0 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.Framework.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ViewComponents
|
||||
{
|
||||
public interface IViewComponentInvokerProvider
|
||||
{
|
||||
int Order { get; }
|
||||
void OnProvidersExecuting([NotNull] ViewComponentInvokerProviderContext context);
|
||||
void OnProvidersExecuted([NotNull] ViewComponentInvokerProviderContext context);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +1,20 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
namespace Microsoft.AspNet.Mvc.ViewComponents
|
||||
{
|
||||
/// <summary>
|
||||
/// Selects a View Component based on a View Component name.
|
||||
/// </summary>
|
||||
public interface IViewComponentSelector
|
||||
{
|
||||
Type SelectComponent([NotNull] string componentName);
|
||||
/// <summary>
|
||||
/// Selects a View Component based on <paramref name="componentName"/>.
|
||||
/// </summary>
|
||||
/// <param name="componentName">The View Component name.</param>
|
||||
/// <returns>A <see cref="ViewComponentDescriptor"/>, or <c>null</c> if no match is found.</returns>
|
||||
ViewComponentDescriptor SelectComponent([NotNull] string componentName);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,25 +2,59 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNet.Mvc.ViewComponents;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
/// <summary>
|
||||
/// A context for View Components.
|
||||
/// </summary>
|
||||
public class ViewComponentContext
|
||||
{
|
||||
public ViewComponentContext([NotNull] TypeInfo componentType, [NotNull] ViewContext viewContext,
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="ViewComponentContext"/>.
|
||||
/// </summary>
|
||||
/// <param name="viewComponentDescriptor">
|
||||
/// The <see cref="ViewComponentContext"/> for the View Component being invoked.
|
||||
/// </param>
|
||||
/// <param name="arguments">The View Component arguments.</param>
|
||||
/// <param name="viewContext">The <see cref="ViewContext"/>.</param>
|
||||
/// <param name="writer">The <see cref="TextWriter"/> for writing output.</param>
|
||||
public ViewComponentContext(
|
||||
[NotNull] ViewComponentDescriptor viewComponentDescriptor,
|
||||
[NotNull] object[] arguments,
|
||||
[NotNull] ViewContext viewContext,
|
||||
[NotNull] TextWriter writer)
|
||||
{
|
||||
ComponentType = componentType;
|
||||
ViewComponentDescriptor = viewComponentDescriptor;
|
||||
Arguments = arguments;
|
||||
ViewContext = viewContext;
|
||||
Writer = writer;
|
||||
}
|
||||
|
||||
public TypeInfo ComponentType { get; private set; }
|
||||
/// <summary>
|
||||
/// Gets the View Component arguments.
|
||||
/// </summary>
|
||||
public object[] Arguments { get; }
|
||||
|
||||
public ViewContext ViewContext { get; private set; }
|
||||
/// <summary>
|
||||
/// Gets the <see cref="ViewComponentDescriptor"/> for the View Component being invoked.
|
||||
/// </summary>
|
||||
public ViewComponentDescriptor ViewComponentDescriptor { get; }
|
||||
|
||||
public TextWriter Writer { get; private set; }
|
||||
/// <summary>
|
||||
/// Gets the <see cref="ViewContext"/>.
|
||||
/// </summary>
|
||||
public ViewContext ViewContext { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="TextWriter"/> for writing output.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <see cref="IViewComponentHelper.Invoke(string, object[])"/> or a similar overload is used to invoke the
|
||||
/// View Component, then <see cref="Writer"/> will be different than <see cref="ViewContext.Writer"/>.
|
||||
/// </remarks>
|
||||
public TextWriter Writer { get; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ using System;
|
|||
using System.Reflection;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
namespace Microsoft.AspNet.Mvc.ViewComponents
|
||||
{
|
||||
public static class ViewComponentConventions
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,79 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ViewComponents
|
||||
{
|
||||
/// <summary>
|
||||
/// A descriptor for a View Component.
|
||||
/// </summary>
|
||||
public class ViewComponentDescriptor
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the full name.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The full name is defaulted to the full namespace of the View Component class, prepended to
|
||||
/// the the class name with a '.' character as the separator. If the View Component class uses
|
||||
/// <code>ViewComponent</code> as a suffix, the suffix will be omitted from the <see cref="FullName"/>.
|
||||
/// </para>
|
||||
/// <example>
|
||||
/// Class Name: Contoso.Products.LoginViewComponent
|
||||
/// View Component FullName: Contoso.Products.Login
|
||||
/// </example>
|
||||
/// <example>
|
||||
/// Class Name: Contoso.Blog.Tags
|
||||
/// View Component FullName: Contoso.Blog.Tags
|
||||
/// </example>
|
||||
/// <para>
|
||||
/// If <see cref="ViewComponentAttribute.Name"/> is used to set a name, then this will be used as
|
||||
/// the <see cref="FullName"/>.
|
||||
/// </para>
|
||||
/// <example>
|
||||
/// [ViewComponent(Name = "Contoso.Forum.UsersOnline")]
|
||||
/// public class OnlineUsersViewComponent
|
||||
/// {
|
||||
/// }
|
||||
/// View Component FullName: Contoso.Forum.UsersOnline
|
||||
/// </example>
|
||||
/// </remarks>
|
||||
public string FullName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the short name.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The short name is defaulted to the name of the View Component class. If the View Component class uses
|
||||
/// <code>ViewComponent</code> as a suffix, the suffix will be omitted from the <see cref="ShortName"/>.
|
||||
/// </para>
|
||||
/// <example>
|
||||
/// Class Name: Contoso.Products.LoginViewComponent
|
||||
/// View Component ShortName: Login
|
||||
/// </example>
|
||||
/// <example>
|
||||
/// Class Name: Contoso.Blog.Tags
|
||||
/// View Component ShortName: Tags
|
||||
/// </example>
|
||||
/// <para>
|
||||
/// If <see cref="ViewComponentAttribute.Name"/> is used to set a name, then the last segment of the
|
||||
/// value (using '.' as a separate) will be used as the <see cref="ShortName"/>.
|
||||
/// </para>
|
||||
/// <example>
|
||||
/// [ViewComponent(Name = "Contoso.Forum.UsersOnline")]
|
||||
/// public class OnlineUsersViewComponent
|
||||
/// {
|
||||
/// }
|
||||
/// View Component ShortName: UsersOnline
|
||||
/// </example>
|
||||
/// </remarks>
|
||||
public string ShortName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="Type"/>.
|
||||
/// </summary>
|
||||
public Type Type { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ViewComponents
|
||||
{
|
||||
/// <summary>
|
||||
/// A cached collection of <see cref="ViewComponentDescriptor" />.
|
||||
/// </summary>
|
||||
public class ViewComponentDescriptorCollection
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ViewComponentDescriptorCollection"/>.
|
||||
/// </summary>
|
||||
/// <param name="items">The result of view component discovery</param>
|
||||
/// <param name="version">The unique version of discovered view components.</param>
|
||||
public ViewComponentDescriptorCollection([NotNull] IEnumerable<ViewComponentDescriptor> items, int version)
|
||||
{
|
||||
Items = new List<ViewComponentDescriptor>(items);
|
||||
Version = version;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached <see cref="IReadOnlyList{ViewComponentDescriptor}"/>.
|
||||
/// </summary>
|
||||
public IReadOnlyList<ViewComponentDescriptor> Items { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the unique version of the currently cached items.
|
||||
/// </summary>
|
||||
public int Version { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Reflection;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ViewComponents
|
||||
{
|
||||
public class ViewComponentInvokerProviderContext
|
||||
{
|
||||
public ViewComponentInvokerProviderContext([NotNull] TypeInfo componentType, object[] arguments)
|
||||
{
|
||||
ComponentType = componentType;
|
||||
Arguments = arguments;
|
||||
}
|
||||
|
||||
public object[] Arguments { get; private set; }
|
||||
|
||||
public TypeInfo ComponentType { get; private set; }
|
||||
|
||||
public IViewComponentInvoker Result { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -8,7 +8,7 @@ using System.Threading.Tasks;
|
|||
using Microsoft.AspNet.Mvc.Core;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
namespace Microsoft.AspNet.Mvc.ViewComponents
|
||||
{
|
||||
public static class ViewComponentMethodSelector
|
||||
{
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ using System;
|
|||
using System.Globalization;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using Microsoft.AspNet.Mvc.ViewComponents;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
||||
|
|
@ -85,7 +86,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
qualifiedViewName = string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
ViewPathFormat,
|
||||
ViewComponentConventions.GetComponentName(context.ComponentType),
|
||||
context.ViewComponentDescriptor.ShortName,
|
||||
ViewName ?? "Default");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -155,9 +155,11 @@ namespace Microsoft.AspNet.Mvc
|
|||
// These do caching so they should stay singleton
|
||||
services.AddSingleton<IViewComponentSelector, DefaultViewComponentSelector>();
|
||||
services.AddSingleton<IViewComponentActivator, DefaultViewComponentActivator>();
|
||||
services.AddSingleton<IViewComponentDescriptorCollectionProvider,
|
||||
DefaultViewComponentDescriptorCollectionProvider>();
|
||||
|
||||
services.AddTransient<IViewComponentDescriptorProvider, DefaultViewComponentDescriptorProvider>();
|
||||
services.AddTransient<IViewComponentInvokerFactory, DefaultViewComponentInvokerFactory>();
|
||||
services.AddTransient<IViewComponentInvokerProvider, DefaultViewComponentInvokerProvider>();
|
||||
services.AddTransient<IViewComponentHelper, DefaultViewComponentHelper>();
|
||||
|
||||
// Security and Authorization
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNet.Http.Core;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using Microsoft.AspNet.Mvc.ViewComponents;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
|
@ -56,7 +56,13 @@ namespace Microsoft.AspNet.Mvc
|
|||
var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider());
|
||||
var viewContext = new ViewContext(actionContext, view, viewData, null, TextWriter.Null);
|
||||
var writer = new StreamWriter(stream) { AutoFlush = true };
|
||||
var viewComponentContext = new ViewComponentContext(typeof(object).GetTypeInfo(), viewContext, writer);
|
||||
|
||||
var viewComponentDescriptor = new ViewComponentDescriptor()
|
||||
{
|
||||
Type = typeof(object),
|
||||
};
|
||||
|
||||
var viewComponentContext = new ViewComponentContext(viewComponentDescriptor, new object[0], viewContext, writer);
|
||||
return viewComponentContext;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ using Microsoft.AspNet.Routing;
|
|||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
namespace Microsoft.AspNet.Mvc.ViewComponents
|
||||
{
|
||||
public class DefaultViewComponentActivatorTests
|
||||
{
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. 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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ViewComponents
|
||||
{
|
||||
public class DefaultViewComponentDescriptorProviderTest
|
||||
{
|
||||
[Fact]
|
||||
public void GetDescriptor_DefaultConventions()
|
||||
{
|
||||
// Arrange
|
||||
var provider = CreateProvider(typeof(ConventionsViewComponent));
|
||||
|
||||
// Act
|
||||
var descriptors = provider.GetViewComponents();
|
||||
|
||||
// Assert
|
||||
var descriptor = Assert.Single(descriptors);
|
||||
Assert.Equal(typeof(ConventionsViewComponent), descriptor.Type);
|
||||
Assert.Equal("Microsoft.AspNet.Mvc.ViewComponents.Conventions", descriptor.FullName);
|
||||
Assert.Equal("Conventions", descriptor.ShortName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetDescriptor_WithAttribute()
|
||||
{
|
||||
// Arrange
|
||||
var provider = CreateProvider(typeof(AttributeViewComponent));
|
||||
|
||||
// Act
|
||||
var descriptors = provider.GetViewComponents();
|
||||
|
||||
// Assert
|
||||
var descriptor = Assert.Single(descriptors);
|
||||
Assert.Equal(typeof(AttributeViewComponent), descriptor.Type);
|
||||
Assert.Equal("AttributesAreGreat", descriptor.FullName);
|
||||
Assert.Equal("AttributesAreGreat", descriptor.ShortName);
|
||||
}
|
||||
|
||||
private class ConventionsViewComponent
|
||||
{
|
||||
}
|
||||
|
||||
[ViewComponent(Name = "AttributesAreGreat")]
|
||||
private class AttributeViewComponent
|
||||
{
|
||||
}
|
||||
|
||||
private DefaultViewComponentDescriptorProvider CreateProvider(Type componentType)
|
||||
{
|
||||
return new FilteredViewComponentDescriptorProvider(componentType);
|
||||
}
|
||||
|
||||
// This will only consider types nested inside this class as ViewComponent classes
|
||||
private class FilteredViewComponentDescriptorProvider : DefaultViewComponentDescriptorProvider
|
||||
{
|
||||
public FilteredViewComponentDescriptorProvider(params Type[] allowedTypes)
|
||||
: base(GetAssemblyProvider())
|
||||
{
|
||||
AllowedTypes = allowedTypes;
|
||||
}
|
||||
|
||||
public Type[] AllowedTypes { get; }
|
||||
|
||||
protected override bool IsViewComponentType(TypeInfo typeInfo)
|
||||
{
|
||||
return AllowedTypes.Contains(typeInfo.AsType());
|
||||
}
|
||||
|
||||
// Need to override this since the default provider does not support private classes.
|
||||
protected override IEnumerable<TypeInfo> GetCandidateTypes()
|
||||
{
|
||||
return
|
||||
GetAssemblyProvider()
|
||||
.CandidateAssemblies
|
||||
.SelectMany(a => a.DefinedTypes)
|
||||
.Select(t => t.GetTypeInfo());
|
||||
}
|
||||
|
||||
private static IAssemblyProvider GetAssemblyProvider()
|
||||
{
|
||||
var assemblyProvider = new FixedSetAssemblyProvider();
|
||||
assemblyProvider.CandidateAssemblies.Add(
|
||||
typeof(FilteredViewComponentDescriptorProvider).GetTypeInfo().Assembly);
|
||||
|
||||
return assemblyProvider;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,12 +2,13 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Microsoft.Framework.Internal;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
namespace Microsoft.AspNet.Mvc.ViewComponents
|
||||
{
|
||||
public class DefaultViewComponentSelectorTest
|
||||
{
|
||||
|
|
@ -21,7 +22,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
var result = selector.SelectComponent("Suffix");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(typeof(SuffixViewComponent), result);
|
||||
Assert.Equal(typeof(SuffixViewComponent), result.Type);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -31,10 +32,10 @@ namespace Microsoft.AspNet.Mvc
|
|||
var selector = CreateSelector();
|
||||
|
||||
// Act
|
||||
var result = selector.SelectComponent("Microsoft.AspNet.Mvc.Suffix");
|
||||
var result = selector.SelectComponent("Microsoft.AspNet.Mvc.ViewComponents.Suffix");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(typeof(SuffixViewComponent), result);
|
||||
Assert.Equal(typeof(SuffixViewComponent), result.Type);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -47,7 +48,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
var result = selector.SelectComponent("WithoutSuffix");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(typeof(WithoutSuffix), result);
|
||||
Assert.Equal(typeof(WithoutSuffix), result.Type);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -57,10 +58,10 @@ namespace Microsoft.AspNet.Mvc
|
|||
var selector = CreateSelector();
|
||||
|
||||
// Act
|
||||
var result = selector.SelectComponent("Microsoft.AspNet.Mvc.WithoutSuffix");
|
||||
var result = selector.SelectComponent("Microsoft.AspNet.Mvc.ViewComponents.WithoutSuffix");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(typeof(WithoutSuffix), result);
|
||||
Assert.Equal(typeof(WithoutSuffix), result.Type);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -73,7 +74,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
var result = selector.SelectComponent("ByAttribute");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(typeof(ByAttribute), result);
|
||||
Assert.Equal(typeof(ByAttribute), result.Type);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -86,7 +87,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
var result = selector.SelectComponent("ByNamingConvention");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(typeof(ByNamingConventionViewComponent), result);
|
||||
Assert.Equal(typeof(ByNamingConventionViewComponent), result.Type);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -97,9 +98,9 @@ namespace Microsoft.AspNet.Mvc
|
|||
|
||||
var expected =
|
||||
"The view component name 'Ambiguous' matched multiple types:" + Environment.NewLine +
|
||||
"Type: 'Microsoft.AspNet.Mvc.DefaultViewComponentSelectorTest+Ambiguous1' - " +
|
||||
"Type: 'Microsoft.AspNet.Mvc.ViewComponents.DefaultViewComponentSelectorTest+Ambiguous1' - " +
|
||||
"Name: 'Namespace1.Ambiguous'" + Environment.NewLine +
|
||||
"Type: 'Microsoft.AspNet.Mvc.DefaultViewComponentSelectorTest+Ambiguous2' - " +
|
||||
"Type: 'Microsoft.AspNet.Mvc.ViewComponents.DefaultViewComponentSelectorTest+Ambiguous2' - " +
|
||||
"Name: 'Namespace2.Ambiguous'";
|
||||
|
||||
// Act
|
||||
|
|
@ -119,7 +120,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
var result = selector.SelectComponent("Namespace1.Ambiguous");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(typeof(Ambiguous1), result);
|
||||
Assert.Equal(typeof(Ambiguous1), result.Type);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
@ -134,7 +135,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
var result = selector.SelectComponent(name);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(typeof(FullNameInAttribute), result);
|
||||
Assert.Equal(typeof(FullNameInAttribute), result.Type);
|
||||
}
|
||||
|
||||
private IViewComponentSelector CreateSelector()
|
||||
|
|
@ -175,9 +176,9 @@ namespace Microsoft.AspNet.Mvc
|
|||
}
|
||||
|
||||
// This will only consider types nested inside this class as ViewComponent classes
|
||||
private class FilteredViewComponentSelector : DefaultViewComponentSelector
|
||||
private class FilteredViewComponentDescriptorProvider : DefaultViewComponentDescriptorProvider
|
||||
{
|
||||
public FilteredViewComponentSelector()
|
||||
public FilteredViewComponentDescriptorProvider()
|
||||
: base(GetAssemblyProvider())
|
||||
{
|
||||
AllowedTypes = typeof(DefaultViewComponentSelectorTest).GetNestedTypes(BindingFlags.NonPublic);
|
||||
|
|
@ -190,6 +191,16 @@ namespace Microsoft.AspNet.Mvc
|
|||
return AllowedTypes.Contains(typeInfo.AsType());
|
||||
}
|
||||
|
||||
// Need to override this since the default provider does not support private classes.
|
||||
protected override IEnumerable<TypeInfo> GetCandidateTypes()
|
||||
{
|
||||
return
|
||||
GetAssemblyProvider()
|
||||
.CandidateAssemblies
|
||||
.SelectMany(a => a.DefinedTypes)
|
||||
.Select(t => t.GetTypeInfo());
|
||||
}
|
||||
|
||||
private static IAssemblyProvider GetAssemblyProvider()
|
||||
{
|
||||
var assemblyProvider = new FixedSetAssemblyProvider();
|
||||
|
|
@ -199,5 +210,14 @@ namespace Microsoft.AspNet.Mvc
|
|||
return assemblyProvider;
|
||||
}
|
||||
}
|
||||
|
||||
// This will only consider types nested inside this class as ViewComponent classes
|
||||
private class FilteredViewComponentSelector : DefaultViewComponentSelector
|
||||
{
|
||||
public FilteredViewComponentSelector()
|
||||
: base(new DefaultViewComponentDescriptorCollectionProvider(new FilteredViewComponentDescriptorProvider()))
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,10 +3,10 @@
|
|||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNet.Http.Core;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using Microsoft.AspNet.Mvc.ViewComponents;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
using Moq;
|
||||
|
|
@ -94,7 +94,13 @@ namespace Microsoft.AspNet.Mvc
|
|||
var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider());
|
||||
var viewContext = new ViewContext(actionContext, view, viewData, null, TextWriter.Null);
|
||||
var writer = new StreamWriter(stream) { AutoFlush = true };
|
||||
var viewComponentContext = new ViewComponentContext(typeof(object).GetTypeInfo(), viewContext, writer);
|
||||
|
||||
var viewComponentDescriptor = new ViewComponentDescriptor()
|
||||
{
|
||||
Type = typeof(object),
|
||||
};
|
||||
|
||||
var viewComponentContext = new ViewComponentContext(viewComponentDescriptor, new object[0], viewContext, writer);
|
||||
return viewComponentContext;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ using System.Reflection;
|
|||
using Microsoft.AspNet.Mvc.ViewComponentConventionsTestClasses;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
namespace Microsoft.AspNet.Mvc.ViewComponents
|
||||
{
|
||||
public class ViewComponentConventionsTest
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@
|
|||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Http.Core;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using Microsoft.AspNet.Mvc.ViewComponents;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
using Moq;
|
||||
|
|
@ -301,7 +301,13 @@ namespace Microsoft.AspNet.Mvc
|
|||
{
|
||||
var actionContext = new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor());
|
||||
var viewContext = new ViewContext(actionContext, view, viewData, null, TextWriter.Null);
|
||||
var viewComponentContext = new ViewComponentContext(typeof(object).GetTypeInfo(), viewContext, TextWriter.Null);
|
||||
|
||||
var viewComponentDescriptor = new ViewComponentDescriptor()
|
||||
{
|
||||
Type = typeof(object),
|
||||
};
|
||||
|
||||
var viewComponentContext = new ViewComponentContext(viewComponentDescriptor, new object[0], viewContext, TextWriter.Null);
|
||||
return viewComponentContext;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
|||
[InlineData(typeof(IActionInvokerProvider), null, -1000)]
|
||||
[InlineData(typeof(IApiDescriptionProvider), null, -1000)]
|
||||
[InlineData(typeof(IFilterProvider), null, -1000)]
|
||||
[InlineData(typeof(IViewComponentInvokerProvider), null, -1000)]
|
||||
[InlineData(typeof(IActionConstraintProvider), null, -1000)]
|
||||
[InlineData(typeof(IConfigureOptions<RazorViewEngineOptions>), null, -1000)]
|
||||
[InlineData(typeof(IConfigureOptions<MvcOptions>), null, -1000)]
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ using System.Linq;
|
|||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Mvc;
|
||||
using Microsoft.AspNet.Mvc.ViewComponents;
|
||||
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
|
||||
|
||||
namespace MvcSample.Web.Components
|
||||
|
|
@ -34,11 +35,19 @@ namespace MvcSample.Web.Components
|
|||
{
|
||||
var result = await InvokeAsync(Count);
|
||||
var writer = new StringWriter();
|
||||
|
||||
var viewComponentDescriptor = new ViewComponentDescriptor()
|
||||
{
|
||||
Type = typeof(TagCloudViewComponentTagHelper),
|
||||
ShortName = "TagCloudViewComponentTagHelper",
|
||||
FullName = "TagCloudViewComponentTagHelper",
|
||||
};
|
||||
|
||||
await result.ExecuteAsync(
|
||||
new ViewComponentContext(typeof(TagCloudViewComponentTagHelper).GetTypeInfo(),
|
||||
ViewContext,
|
||||
writer));
|
||||
await result.ExecuteAsync(new ViewComponentContext(
|
||||
viewComponentDescriptor,
|
||||
new object[0],
|
||||
ViewContext,
|
||||
writer));
|
||||
|
||||
output.TagName = null;
|
||||
output.Content.SetContent(writer.ToString());
|
||||
|
|
|
|||
Loading…
Reference in New Issue