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.DependencyInjection;
|
||||||
using Microsoft.Framework.Internal;
|
using Microsoft.Framework.Internal;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc
|
namespace Microsoft.AspNet.Mvc.ViewComponents
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents the <see cref="IViewComponentActivator"/> that is registered by default.
|
/// 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
|
public class DefaultViewComponentHelper : IViewComponentHelper, ICanHasViewContext
|
||||||
{
|
{
|
||||||
|
private readonly IViewComponentDescriptorCollectionProvider _descriptorProvider;
|
||||||
private readonly IViewComponentInvokerFactory _invokerFactory;
|
private readonly IViewComponentInvokerFactory _invokerFactory;
|
||||||
private readonly IViewComponentSelector _selector;
|
private readonly IViewComponentSelector _selector;
|
||||||
private ViewContext _viewContext;
|
private ViewContext _viewContext;
|
||||||
|
|
||||||
public DefaultViewComponentHelper(
|
public DefaultViewComponentHelper(
|
||||||
|
[NotNull] IViewComponentDescriptorCollectionProvider descriptorProvider,
|
||||||
[NotNull] IViewComponentSelector selector,
|
[NotNull] IViewComponentSelector selector,
|
||||||
[NotNull] IViewComponentInvokerFactory invokerFactory)
|
[NotNull] IViewComponentInvokerFactory invokerFactory)
|
||||||
{
|
{
|
||||||
|
_descriptorProvider = descriptorProvider;
|
||||||
_selector = selector;
|
_selector = selector;
|
||||||
_invokerFactory = invokerFactory;
|
_invokerFactory = invokerFactory;
|
||||||
}
|
}
|
||||||
|
|
@ -30,92 +33,129 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
|
||||||
_viewContext = viewContext;
|
_viewContext = viewContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HtmlString Invoke([NotNull] string name, params object[] args)
|
public HtmlString Invoke([NotNull] string name, params object[] arguments)
|
||||||
{
|
{
|
||||||
var componentType = SelectComponent(name);
|
var descriptor = SelectComponent(name);
|
||||||
return Invoke(componentType, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
public HtmlString Invoke([NotNull] Type componentType, params object[] args)
|
|
||||||
{
|
|
||||||
using (var writer = new StringWriter())
|
using (var writer = new StringWriter())
|
||||||
{
|
{
|
||||||
InvokeCore(writer, componentType, args);
|
InvokeCore(writer, descriptor, arguments);
|
||||||
return new HtmlString(writer.ToString());
|
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);
|
var descriptor = SelectComponent(componentType);
|
||||||
InvokeCore(_viewContext.Writer, componentType, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
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())
|
using (var writer = new StringWriter())
|
||||||
{
|
{
|
||||||
await InvokeCoreAsync(writer, componentType, args);
|
InvokeCore(writer, descriptor, arguments);
|
||||||
return new HtmlString(writer.ToString());
|
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);
|
var descriptor = SelectComponent(name);
|
||||||
await InvokeCoreAsync(_viewContext.Writer, componentType, args);
|
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);
|
var descriptor = SelectComponent(name);
|
||||||
if (componentType == null)
|
|
||||||
|
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));
|
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)
|
if (invoker == null)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException(
|
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);
|
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)
|
if (invoker == null)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException(
|
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);
|
invoker.Invoke(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,43 +7,38 @@ using System.Runtime.ExceptionServices;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Mvc.Core;
|
using Microsoft.AspNet.Mvc.Core;
|
||||||
using Microsoft.AspNet.Mvc.Rendering;
|
using Microsoft.AspNet.Mvc.Rendering;
|
||||||
using Microsoft.Framework.DependencyInjection;
|
|
||||||
using Microsoft.Framework.Internal;
|
using Microsoft.Framework.Internal;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc
|
namespace Microsoft.AspNet.Mvc.ViewComponents
|
||||||
{
|
{
|
||||||
public class DefaultViewComponentInvoker : IViewComponentInvoker
|
public class DefaultViewComponentInvoker : IViewComponentInvoker
|
||||||
{
|
{
|
||||||
private readonly IServiceProvider _serviceProvider;
|
private readonly IServiceProvider _serviceProvider;
|
||||||
private readonly ITypeActivatorCache _typeActivatorCache;
|
private readonly ITypeActivatorCache _typeActivatorCache;
|
||||||
private readonly TypeInfo _componentType;
|
|
||||||
private readonly IViewComponentActivator _viewComponentActivator;
|
private readonly IViewComponentActivator _viewComponentActivator;
|
||||||
private readonly object[] _args;
|
|
||||||
|
|
||||||
public DefaultViewComponentInvoker(
|
public DefaultViewComponentInvoker(
|
||||||
[NotNull] IServiceProvider serviceProvider,
|
[NotNull] IServiceProvider serviceProvider,
|
||||||
[NotNull] ITypeActivatorCache typeActivatorCache,
|
[NotNull] ITypeActivatorCache typeActivatorCache,
|
||||||
[NotNull] IViewComponentActivator viewComponentActivator,
|
[NotNull] IViewComponentActivator viewComponentActivator)
|
||||||
[NotNull] TypeInfo componentType,
|
|
||||||
object[] args)
|
|
||||||
{
|
{
|
||||||
_serviceProvider = serviceProvider;
|
_serviceProvider = serviceProvider;
|
||||||
_typeActivatorCache = typeActivatorCache;
|
_typeActivatorCache = typeActivatorCache;
|
||||||
_componentType = componentType;
|
|
||||||
_viewComponentActivator = viewComponentActivator;
|
_viewComponentActivator = viewComponentActivator;
|
||||||
_args = args ?? new object[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Invoke([NotNull] ViewComponentContext context)
|
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)
|
if (method == null)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException(
|
throw new InvalidOperationException(
|
||||||
Resources.FormatViewComponent_CannotFindMethod(ViewComponentMethodSelector.SyncMethodName));
|
Resources.FormatViewComponent_CannotFindMethod(ViewComponentMethodSelector.SyncMethodName));
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = InvokeSyncCore(method, context.ViewContext);
|
var result = InvokeSyncCore(method, context);
|
||||||
result.Execute(context);
|
result.Execute(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -51,12 +46,16 @@ namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
IViewComponentResult result;
|
IViewComponentResult result;
|
||||||
|
|
||||||
var asyncMethod = ViewComponentMethodSelector.FindAsyncMethod(_componentType, _args);
|
var asyncMethod = ViewComponentMethodSelector.FindAsyncMethod(
|
||||||
|
context.ViewComponentDescriptor.Type.GetTypeInfo(),
|
||||||
|
context.Arguments);
|
||||||
if (asyncMethod == null)
|
if (asyncMethod == null)
|
||||||
{
|
{
|
||||||
// We support falling back to synchronous if there is no InvokeAsync method, in this case we'll still
|
// We support falling back to synchronous if there is no InvokeAsync method, in this case we'll still
|
||||||
// execute the IViewResult asynchronously.
|
// execute the IViewResult asynchronously.
|
||||||
var syncMethod = ViewComponentMethodSelector.FindSyncMethod(_componentType, _args);
|
var syncMethod = ViewComponentMethodSelector.FindSyncMethod(
|
||||||
|
context.ViewComponentDescriptor.Type.GetTypeInfo(),
|
||||||
|
context.Arguments);
|
||||||
if (syncMethod == null)
|
if (syncMethod == null)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException(
|
throw new InvalidOperationException(
|
||||||
|
|
@ -65,36 +64,38 @@ namespace Microsoft.AspNet.Mvc
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
result = InvokeSyncCore(syncMethod, context.ViewContext);
|
result = InvokeSyncCore(syncMethod, context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
result = await InvokeAsyncCore(asyncMethod, context.ViewContext);
|
result = await InvokeAsyncCore(asyncMethod, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
await result.ExecuteAsync(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());
|
var component = _typeActivatorCache.CreateInstance<object>(
|
||||||
_viewComponentActivator.Activate(component, context);
|
_serviceProvider,
|
||||||
|
context.ViewComponentDescriptor.Type);
|
||||||
|
_viewComponentActivator.Activate(component, context.ViewContext);
|
||||||
return component;
|
return component;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<IViewComponentResult> InvokeAsyncCore(
|
private async Task<IViewComponentResult> InvokeAsyncCore(
|
||||||
[NotNull] MethodInfo method,
|
[NotNull] MethodInfo method,
|
||||||
[NotNull] ViewContext context)
|
[NotNull] ViewComponentContext context)
|
||||||
{
|
{
|
||||||
var component = CreateComponent(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);
|
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);
|
var component = CreateComponent(context);
|
||||||
|
|
||||||
|
|
@ -102,7 +103,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
result = method.Invoke(component, _args);
|
result = method.Invoke(component, context.Arguments);
|
||||||
}
|
}
|
||||||
catch (TargetInvocationException ex)
|
catch (TargetInvocationException ex)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,38 +1,39 @@
|
||||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
// 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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System;
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using Microsoft.Framework.Internal;
|
using Microsoft.Framework.Internal;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.ViewComponents
|
namespace Microsoft.AspNet.Mvc.ViewComponents
|
||||||
{
|
{
|
||||||
public class DefaultViewComponentInvokerFactory : IViewComponentInvokerFactory
|
public class DefaultViewComponentInvokerFactory : IViewComponentInvokerFactory
|
||||||
{
|
{
|
||||||
private readonly IViewComponentInvokerProvider[] _providers;
|
private readonly IServiceProvider _serviceProvider;
|
||||||
|
private readonly ITypeActivatorCache _typeActivatorCache;
|
||||||
|
private readonly IViewComponentActivator _viewComponentActivator;
|
||||||
|
|
||||||
public DefaultViewComponentInvokerFactory(
|
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);
|
return new DefaultViewComponentInvoker(
|
||||||
|
_serviceProvider,
|
||||||
foreach (var provider in _providers)
|
_typeActivatorCache,
|
||||||
{
|
_viewComponentActivator);
|
||||||
provider.OnProvidersExecuting(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = _providers.Length - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
_providers[i].OnProvidersExecuted(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
return context.Result;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
|
||||||
using Microsoft.AspNet.Mvc.Core;
|
using Microsoft.AspNet.Mvc.Core;
|
||||||
using Microsoft.Framework.Internal;
|
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
|
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;
|
_cache = new ViewComponentDescriptorCache(collection);
|
||||||
var types = assemblies.SelectMany(a => a.DefinedTypes);
|
|
||||||
|
|
||||||
var candidates =
|
|
||||||
types
|
|
||||||
.Where(IsViewComponentType)
|
|
||||||
.Select(CreateCandidate)
|
|
||||||
.ToArray();
|
|
||||||
|
|
||||||
_cache = new ViewComponentCandidateCache(candidates);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ViewComponent names can either be fully-qualified, or refer to the 'short-name'. If the provided
|
// 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.
|
// name contains a '.' - then it's a fully-qualified name.
|
||||||
var matching = new List<ViewComponentCandidate>();
|
|
||||||
if (componentName.Contains("."))
|
if (componentName.Contains("."))
|
||||||
{
|
{
|
||||||
return _cache.SelectByFullName(componentName);
|
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)
|
public ViewComponentDescriptorCache(ViewComponentDescriptorCollection collection)
|
||||||
{
|
|
||||||
var candidate = new ViewComponentCandidate()
|
|
||||||
{
|
{
|
||||||
FullName = ViewComponentConventions.GetComponentFullName(typeInfo),
|
Version = collection.Version;
|
||||||
ShortName = ViewComponentConventions.GetComponentName(typeInfo),
|
|
||||||
Type = typeInfo.AsType(),
|
|
||||||
};
|
|
||||||
|
|
||||||
Debug.Assert(!string.IsNullOrEmpty(candidate.FullName));
|
_lookupByShortName = collection.Items.ToLookup(c => c.ShortName, c => c);
|
||||||
var separatorIndex = candidate.FullName.LastIndexOf('.');
|
_lookupByFullName = collection.Items.ToLookup(c => c.FullName, c => c);
|
||||||
if (separatorIndex >= 0)
|
|
||||||
{
|
|
||||||
candidate.ShortName = candidate.FullName.Substring(separatorIndex + 1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
candidate.ShortName = candidate.FullName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return candidate;
|
public int Version { get; }
|
||||||
}
|
|
||||||
|
|
||||||
private class ViewComponentCandidate
|
public ViewComponentDescriptor SelectByShortName(string name)
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
return Select(_lookupByShortName, name);
|
return Select(_lookupByShortName, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Type SelectByFullName(string name)
|
public ViewComponentDescriptor SelectByFullName(string name)
|
||||||
{
|
{
|
||||||
return Select(_lookupByFullName, 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];
|
var matches = candidates[name];
|
||||||
|
|
||||||
|
|
@ -120,7 +86,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
}
|
}
|
||||||
else if (count == 1)
|
else if (count == 1)
|
||||||
{
|
{
|
||||||
return matches.Single().Type;
|
return matches.Single();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
// 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.
|
// 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>
|
/// <summary>
|
||||||
/// Provides methods to activate an instantiated ViewComponent
|
/// 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 System.Threading.Tasks;
|
||||||
using Microsoft.Framework.Internal;
|
using Microsoft.Framework.Internal;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc
|
namespace Microsoft.AspNet.Mvc.ViewComponents
|
||||||
{
|
{
|
||||||
public interface IViewComponentInvoker
|
public interface IViewComponentInvoker
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,14 @@
|
||||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
// 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.
|
// 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;
|
using Microsoft.Framework.Internal;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.ViewComponents
|
namespace Microsoft.AspNet.Mvc.ViewComponents
|
||||||
{
|
{
|
||||||
public interface IViewComponentInvokerFactory
|
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.
|
// 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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
|
||||||
using Microsoft.Framework.Internal;
|
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
|
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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Reflection;
|
using Microsoft.AspNet.Mvc.ViewComponents;
|
||||||
using Microsoft.Framework.Internal;
|
using Microsoft.Framework.Internal;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc
|
namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A context for View Components.
|
||||||
|
/// </summary>
|
||||||
public class ViewComponentContext
|
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)
|
[NotNull] TextWriter writer)
|
||||||
{
|
{
|
||||||
ComponentType = componentType;
|
ViewComponentDescriptor = viewComponentDescriptor;
|
||||||
|
Arguments = arguments;
|
||||||
ViewContext = viewContext;
|
ViewContext = viewContext;
|
||||||
Writer = writer;
|
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 System.Reflection;
|
||||||
using Microsoft.Framework.Internal;
|
using Microsoft.Framework.Internal;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc
|
namespace Microsoft.AspNet.Mvc.ViewComponents
|
||||||
{
|
{
|
||||||
public static class ViewComponentConventions
|
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.AspNet.Mvc.Core;
|
||||||
using Microsoft.Framework.Internal;
|
using Microsoft.Framework.Internal;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc
|
namespace Microsoft.AspNet.Mvc.ViewComponents
|
||||||
{
|
{
|
||||||
public static class ViewComponentMethodSelector
|
public static class ViewComponentMethodSelector
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Mvc.Rendering;
|
using Microsoft.AspNet.Mvc.Rendering;
|
||||||
|
using Microsoft.AspNet.Mvc.ViewComponents;
|
||||||
using Microsoft.Framework.DependencyInjection;
|
using Microsoft.Framework.DependencyInjection;
|
||||||
using Microsoft.Framework.Internal;
|
using Microsoft.Framework.Internal;
|
||||||
|
|
||||||
|
|
@ -85,7 +86,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
qualifiedViewName = string.Format(
|
qualifiedViewName = string.Format(
|
||||||
CultureInfo.InvariantCulture,
|
CultureInfo.InvariantCulture,
|
||||||
ViewPathFormat,
|
ViewPathFormat,
|
||||||
ViewComponentConventions.GetComponentName(context.ComponentType),
|
context.ViewComponentDescriptor.ShortName,
|
||||||
ViewName ?? "Default");
|
ViewName ?? "Default");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -155,9 +155,11 @@ namespace Microsoft.AspNet.Mvc
|
||||||
// These do caching so they should stay singleton
|
// These do caching so they should stay singleton
|
||||||
services.AddSingleton<IViewComponentSelector, DefaultViewComponentSelector>();
|
services.AddSingleton<IViewComponentSelector, DefaultViewComponentSelector>();
|
||||||
services.AddSingleton<IViewComponentActivator, DefaultViewComponentActivator>();
|
services.AddSingleton<IViewComponentActivator, DefaultViewComponentActivator>();
|
||||||
|
services.AddSingleton<IViewComponentDescriptorCollectionProvider,
|
||||||
|
DefaultViewComponentDescriptorCollectionProvider>();
|
||||||
|
|
||||||
|
services.AddTransient<IViewComponentDescriptorProvider, DefaultViewComponentDescriptorProvider>();
|
||||||
services.AddTransient<IViewComponentInvokerFactory, DefaultViewComponentInvokerFactory>();
|
services.AddTransient<IViewComponentInvokerFactory, DefaultViewComponentInvokerFactory>();
|
||||||
services.AddTransient<IViewComponentInvokerProvider, DefaultViewComponentInvokerProvider>();
|
|
||||||
services.AddTransient<IViewComponentHelper, DefaultViewComponentHelper>();
|
services.AddTransient<IViewComponentHelper, DefaultViewComponentHelper>();
|
||||||
|
|
||||||
// Security and Authorization
|
// 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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Reflection;
|
|
||||||
using Microsoft.AspNet.Http.Core;
|
using Microsoft.AspNet.Http.Core;
|
||||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||||
using Microsoft.AspNet.Mvc.Rendering;
|
using Microsoft.AspNet.Mvc.Rendering;
|
||||||
|
using Microsoft.AspNet.Mvc.ViewComponents;
|
||||||
using Microsoft.AspNet.Routing;
|
using Microsoft.AspNet.Routing;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
@ -56,7 +56,13 @@ namespace Microsoft.AspNet.Mvc
|
||||||
var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider());
|
var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider());
|
||||||
var viewContext = new ViewContext(actionContext, view, viewData, null, TextWriter.Null);
|
var viewContext = new ViewContext(actionContext, view, viewData, null, TextWriter.Null);
|
||||||
var writer = new StreamWriter(stream) { AutoFlush = true };
|
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;
|
return viewComponentContext;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ using Microsoft.AspNet.Routing;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc
|
namespace Microsoft.AspNet.Mvc.ViewComponents
|
||||||
{
|
{
|
||||||
public class DefaultViewComponentActivatorTests
|
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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Microsoft.Framework.Internal;
|
using Microsoft.Framework.Internal;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc
|
namespace Microsoft.AspNet.Mvc.ViewComponents
|
||||||
{
|
{
|
||||||
public class DefaultViewComponentSelectorTest
|
public class DefaultViewComponentSelectorTest
|
||||||
{
|
{
|
||||||
|
|
@ -21,7 +22,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
var result = selector.SelectComponent("Suffix");
|
var result = selector.SelectComponent("Suffix");
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(typeof(SuffixViewComponent), result);
|
Assert.Equal(typeof(SuffixViewComponent), result.Type);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -31,10 +32,10 @@ namespace Microsoft.AspNet.Mvc
|
||||||
var selector = CreateSelector();
|
var selector = CreateSelector();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = selector.SelectComponent("Microsoft.AspNet.Mvc.Suffix");
|
var result = selector.SelectComponent("Microsoft.AspNet.Mvc.ViewComponents.Suffix");
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(typeof(SuffixViewComponent), result);
|
Assert.Equal(typeof(SuffixViewComponent), result.Type);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -47,7 +48,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
var result = selector.SelectComponent("WithoutSuffix");
|
var result = selector.SelectComponent("WithoutSuffix");
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(typeof(WithoutSuffix), result);
|
Assert.Equal(typeof(WithoutSuffix), result.Type);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -57,10 +58,10 @@ namespace Microsoft.AspNet.Mvc
|
||||||
var selector = CreateSelector();
|
var selector = CreateSelector();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = selector.SelectComponent("Microsoft.AspNet.Mvc.WithoutSuffix");
|
var result = selector.SelectComponent("Microsoft.AspNet.Mvc.ViewComponents.WithoutSuffix");
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(typeof(WithoutSuffix), result);
|
Assert.Equal(typeof(WithoutSuffix), result.Type);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -73,7 +74,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
var result = selector.SelectComponent("ByAttribute");
|
var result = selector.SelectComponent("ByAttribute");
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(typeof(ByAttribute), result);
|
Assert.Equal(typeof(ByAttribute), result.Type);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -86,7 +87,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
var result = selector.SelectComponent("ByNamingConvention");
|
var result = selector.SelectComponent("ByNamingConvention");
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(typeof(ByNamingConventionViewComponent), result);
|
Assert.Equal(typeof(ByNamingConventionViewComponent), result.Type);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -97,9 +98,9 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
var expected =
|
var expected =
|
||||||
"The view component name 'Ambiguous' matched multiple types:" + Environment.NewLine +
|
"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 +
|
"Name: 'Namespace1.Ambiguous'" + Environment.NewLine +
|
||||||
"Type: 'Microsoft.AspNet.Mvc.DefaultViewComponentSelectorTest+Ambiguous2' - " +
|
"Type: 'Microsoft.AspNet.Mvc.ViewComponents.DefaultViewComponentSelectorTest+Ambiguous2' - " +
|
||||||
"Name: 'Namespace2.Ambiguous'";
|
"Name: 'Namespace2.Ambiguous'";
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -119,7 +120,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
var result = selector.SelectComponent("Namespace1.Ambiguous");
|
var result = selector.SelectComponent("Namespace1.Ambiguous");
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(typeof(Ambiguous1), result);
|
Assert.Equal(typeof(Ambiguous1), result.Type);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
|
|
@ -134,7 +135,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
var result = selector.SelectComponent(name);
|
var result = selector.SelectComponent(name);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(typeof(FullNameInAttribute), result);
|
Assert.Equal(typeof(FullNameInAttribute), result.Type);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IViewComponentSelector CreateSelector()
|
private IViewComponentSelector CreateSelector()
|
||||||
|
|
@ -175,9 +176,9 @@ namespace Microsoft.AspNet.Mvc
|
||||||
}
|
}
|
||||||
|
|
||||||
// This will only consider types nested inside this class as ViewComponent classes
|
// 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())
|
: base(GetAssemblyProvider())
|
||||||
{
|
{
|
||||||
AllowedTypes = typeof(DefaultViewComponentSelectorTest).GetNestedTypes(BindingFlags.NonPublic);
|
AllowedTypes = typeof(DefaultViewComponentSelectorTest).GetNestedTypes(BindingFlags.NonPublic);
|
||||||
|
|
@ -190,6 +191,16 @@ namespace Microsoft.AspNet.Mvc
|
||||||
return AllowedTypes.Contains(typeInfo.AsType());
|
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()
|
private static IAssemblyProvider GetAssemblyProvider()
|
||||||
{
|
{
|
||||||
var assemblyProvider = new FixedSetAssemblyProvider();
|
var assemblyProvider = new FixedSetAssemblyProvider();
|
||||||
|
|
@ -199,5 +210,14 @@ namespace Microsoft.AspNet.Mvc
|
||||||
return assemblyProvider;
|
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;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Reflection;
|
|
||||||
using Microsoft.AspNet.Http.Core;
|
using Microsoft.AspNet.Http.Core;
|
||||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||||
using Microsoft.AspNet.Mvc.Rendering;
|
using Microsoft.AspNet.Mvc.Rendering;
|
||||||
|
using Microsoft.AspNet.Mvc.ViewComponents;
|
||||||
using Microsoft.AspNet.Routing;
|
using Microsoft.AspNet.Routing;
|
||||||
using Microsoft.Framework.DependencyInjection;
|
using Microsoft.Framework.DependencyInjection;
|
||||||
using Moq;
|
using Moq;
|
||||||
|
|
@ -94,7 +94,13 @@ namespace Microsoft.AspNet.Mvc
|
||||||
var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider());
|
var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider());
|
||||||
var viewContext = new ViewContext(actionContext, view, viewData, null, TextWriter.Null);
|
var viewContext = new ViewContext(actionContext, view, viewData, null, TextWriter.Null);
|
||||||
var writer = new StreamWriter(stream) { AutoFlush = true };
|
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;
|
return viewComponentContext;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ using System.Reflection;
|
||||||
using Microsoft.AspNet.Mvc.ViewComponentConventionsTestClasses;
|
using Microsoft.AspNet.Mvc.ViewComponentConventionsTestClasses;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc
|
namespace Microsoft.AspNet.Mvc.ViewComponents
|
||||||
{
|
{
|
||||||
public class ViewComponentConventionsTest
|
public class ViewComponentConventionsTest
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,11 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Reflection;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Http.Core;
|
using Microsoft.AspNet.Http.Core;
|
||||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||||
using Microsoft.AspNet.Mvc.Rendering;
|
using Microsoft.AspNet.Mvc.Rendering;
|
||||||
|
using Microsoft.AspNet.Mvc.ViewComponents;
|
||||||
using Microsoft.AspNet.Routing;
|
using Microsoft.AspNet.Routing;
|
||||||
using Microsoft.Framework.DependencyInjection;
|
using Microsoft.Framework.DependencyInjection;
|
||||||
using Moq;
|
using Moq;
|
||||||
|
|
@ -301,7 +301,13 @@ namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
var actionContext = new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor());
|
var actionContext = new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor());
|
||||||
var viewContext = new ViewContext(actionContext, view, viewData, null, TextWriter.Null);
|
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;
|
return viewComponentContext;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,6 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||||
[InlineData(typeof(IActionInvokerProvider), null, -1000)]
|
[InlineData(typeof(IActionInvokerProvider), null, -1000)]
|
||||||
[InlineData(typeof(IApiDescriptionProvider), null, -1000)]
|
[InlineData(typeof(IApiDescriptionProvider), null, -1000)]
|
||||||
[InlineData(typeof(IFilterProvider), null, -1000)]
|
[InlineData(typeof(IFilterProvider), null, -1000)]
|
||||||
[InlineData(typeof(IViewComponentInvokerProvider), null, -1000)]
|
|
||||||
[InlineData(typeof(IActionConstraintProvider), null, -1000)]
|
[InlineData(typeof(IActionConstraintProvider), null, -1000)]
|
||||||
[InlineData(typeof(IConfigureOptions<RazorViewEngineOptions>), null, -1000)]
|
[InlineData(typeof(IConfigureOptions<RazorViewEngineOptions>), null, -1000)]
|
||||||
[InlineData(typeof(IConfigureOptions<MvcOptions>), null, -1000)]
|
[InlineData(typeof(IConfigureOptions<MvcOptions>), null, -1000)]
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Mvc;
|
using Microsoft.AspNet.Mvc;
|
||||||
|
using Microsoft.AspNet.Mvc.ViewComponents;
|
||||||
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
|
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
|
||||||
|
|
||||||
namespace MvcSample.Web.Components
|
namespace MvcSample.Web.Components
|
||||||
|
|
@ -35,10 +36,18 @@ namespace MvcSample.Web.Components
|
||||||
var result = await InvokeAsync(Count);
|
var result = await InvokeAsync(Count);
|
||||||
var writer = new StringWriter();
|
var writer = new StringWriter();
|
||||||
|
|
||||||
await result.ExecuteAsync(
|
var viewComponentDescriptor = new ViewComponentDescriptor()
|
||||||
new ViewComponentContext(typeof(TagCloudViewComponentTagHelper).GetTypeInfo(),
|
{
|
||||||
ViewContext,
|
Type = typeof(TagCloudViewComponentTagHelper),
|
||||||
writer));
|
ShortName = "TagCloudViewComponentTagHelper",
|
||||||
|
FullName = "TagCloudViewComponentTagHelper",
|
||||||
|
};
|
||||||
|
|
||||||
|
await result.ExecuteAsync(new ViewComponentContext(
|
||||||
|
viewComponentDescriptor,
|
||||||
|
new object[0],
|
||||||
|
ViewContext,
|
||||||
|
writer));
|
||||||
|
|
||||||
output.TagName = null;
|
output.TagName = null;
|
||||||
output.Content.SetContent(writer.ToString());
|
output.Content.SetContent(writer.ToString());
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue