diff --git a/samples/TagHelperSample.Web/Components/FeaturedMoviesComponent.cs b/samples/TagHelperSample.Web/Components/FeaturedMoviesComponent.cs
index b038feb711..def141a4a5 100644
--- a/samples/TagHelperSample.Web/Components/FeaturedMoviesComponent.cs
+++ b/samples/TagHelperSample.Web/Components/FeaturedMoviesComponent.cs
@@ -38,18 +38,5 @@ namespace TagHelperSample.Web.Components
return View(movies);
}
-
- public IViewComponentResult Invoke(string movieName)
- {
- string quote;
- if (!_cache.TryGetValue(movieName, out quote))
- {
- IChangeToken expirationToken;
- quote = _moviesService.GetCriticsQuote(out expirationToken);
- _cache.Set(movieName, quote, new MemoryCacheEntryOptions().AddExpirationToken(expirationToken));
- }
-
- return Content(quote);
- }
}
}
\ No newline at end of file
diff --git a/samples/TagHelperSample.Web/Components/MoviesComponent.cs b/samples/TagHelperSample.Web/Components/MoviesComponent.cs
new file mode 100644
index 0000000000..064707d3e9
--- /dev/null
+++ b/samples/TagHelperSample.Web/Components/MoviesComponent.cs
@@ -0,0 +1,36 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using Microsoft.AspNet.Mvc;
+using Microsoft.Extensions.Caching.Memory;
+using Microsoft.Extensions.Primitives;
+using TagHelperSample.Web.Services;
+
+namespace TagHelperSample.Web.Components
+{
+ [ViewComponent(Name = "Movies")]
+ public class MoviesComponent : ViewComponent
+ {
+ private readonly IMemoryCache _cache;
+ private readonly MoviesService _moviesService;
+
+ public MoviesComponent(MoviesService moviesService, IMemoryCache cache)
+ {
+ _moviesService = moviesService;
+ _cache = cache;
+ }
+
+ public IViewComponentResult Invoke(string movieName)
+ {
+ string quote;
+ if (!_cache.TryGetValue(movieName, out quote))
+ {
+ IChangeToken expirationToken;
+ quote = _moviesService.GetCriticsQuote(out expirationToken);
+ _cache.Set(movieName, quote, new MemoryCacheEntryOptions().AddExpirationToken(expirationToken));
+ }
+
+ return Content(quote);
+ }
+ }
+}
\ No newline at end of file
diff --git a/samples/TagHelperSample.Web/Views/Movies/Index.cshtml b/samples/TagHelperSample.Web/Views/Movies/Index.cshtml
index 5eda5ea485..80fe8db349 100644
--- a/samples/TagHelperSample.Web/Views/Movies/Index.cshtml
+++ b/samples/TagHelperSample.Web/Views/Movies/Index.cshtml
@@ -35,7 +35,7 @@
diff --git a/samples/TagHelperSample.Web/Views/Shared/Components/FeaturedMovies/Default.cshtml b/samples/TagHelperSample.Web/Views/Shared/Components/FeaturedMovies/Default.cshtml
index 8348bffa01..1444339630 100644
--- a/samples/TagHelperSample.Web/Views/Shared/Components/FeaturedMovies/Default.cshtml
+++ b/samples/TagHelperSample.Web/Views/Shared/Components/FeaturedMovies/Default.cshtml
@@ -10,7 +10,7 @@
Critics say:
- @Component.Invoke("FeaturedMovies", movie.Name)
+ @await Component.InvokeAsync("Movies", new { movieName = movie.Name })
}
diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/IViewComponentHelper.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/IViewComponentHelper.cs
index 4d1af76dd9..6a0bc31010 100644
--- a/src/Microsoft.AspNet.Mvc.ViewFeatures/IViewComponentHelper.cs
+++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/IViewComponentHelper.cs
@@ -7,22 +7,27 @@ using Microsoft.AspNet.Html;
namespace Microsoft.AspNet.Mvc
{
+ ///
+ /// Supports the rendering of view components in a view.
+ ///
public interface IViewComponentHelper
{
- IHtmlContent Invoke(string name, params object[] args);
+ ///
+ /// Invokes a view component with the specified .
+ ///
+ /// The name of the view component.
+ /// Arguments to be passed to the invoked view component method.
+ /// A that on completion returns the rendered .
+ ///
+ Task InvokeAsync(string name, object arguments);
- IHtmlContent Invoke(Type componentType, params object[] args);
-
- void RenderInvoke(string name, params object[] args);
-
- void RenderInvoke(Type componentType, params object[] args);
-
- Task InvokeAsync(string name, params object[] args);
-
- Task InvokeAsync(Type componentType, params object[] args);
-
- Task RenderInvokeAsync(string name, params object[] args);
-
- Task RenderInvokeAsync(Type componentType, params object[] args);
+ ///
+ /// Invokes a view component of type .
+ ///
+ /// The view component .
+ /// Arguments to be passed to the invoked view component method.
+ /// A that on completion returns the rendered .
+ ///
+ Task InvokeAsync(Type componentType, object arguments);
}
}
diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/Logging/DefaultViewComponentInvokerLoggerExtensions.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/Logging/DefaultViewComponentInvokerLoggerExtensions.cs
index 9941109716..e2280c19db 100644
--- a/src/Microsoft.AspNet.Mvc.ViewFeatures/Logging/DefaultViewComponentInvokerLoggerExtensions.cs
+++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/Logging/DefaultViewComponentInvokerLoggerExtensions.cs
@@ -10,15 +10,21 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures.Logging
{
public static class DefaultViewComponentInvokerLoggerExtensions
{
- private static readonly Action _viewComponentExecuting;
+ private static readonly string[] EmptyArguments =
+#if NET451
+ new string[0];
+#else
+ Array.Empty();
+#endif
+ private static readonly Action _viewComponentExecuting;
private static readonly Action _viewComponentExecuted;
static DefaultViewComponentInvokerLoggerExtensions()
{
- _viewComponentExecuting = LoggerMessage.Define(
+ _viewComponentExecuting = LoggerMessage.Define(
LogLevel.Debug,
1,
- "Executing view component {ViewComponentName}");
+ "Executing view component {ViewComponentName} with arguments ({Arguments}).");
_viewComponentExecuted = LoggerMessage.Define(
LogLevel.Debug,
@@ -32,9 +38,29 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures.Logging
return logger.BeginScopeImpl(new ViewComponentLogScope(context.ViewComponentDescriptor));
}
- public static void ViewComponentExecuting(this ILogger logger, ViewComponentContext context)
+ public static void ViewComponentExecuting(
+ this ILogger logger,
+ ViewComponentContext context,
+ object[] arguments)
{
- _viewComponentExecuting(logger, context.ViewComponentDescriptor.DisplayName, null);
+ var formattedArguments = GetFormattedArguments(arguments);
+ _viewComponentExecuting(logger, context.ViewComponentDescriptor.DisplayName, formattedArguments, null);
+ }
+
+ private static string[] GetFormattedArguments(object[] arguments)
+ {
+ if (arguments == null || arguments.Length == 0)
+ {
+ return EmptyArguments;
+ }
+
+ var formattedArguments = new string[arguments.Length];
+ for (var i = 0; i < formattedArguments.Length; i++)
+ {
+ formattedArguments[i] = Convert.ToString(arguments[i]);
+ }
+
+ return formattedArguments;
}
public static void ViewComponentExecuted(
diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/Logging/ViewComponentResultLoggerExtensions.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/Logging/ViewComponentResultLoggerExtensions.cs
index 2ed984060c..52a829a154 100644
--- a/src/Microsoft.AspNet.Mvc.ViewFeatures/Logging/ViewComponentResultLoggerExtensions.cs
+++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/Logging/ViewComponentResultLoggerExtensions.cs
@@ -8,41 +8,29 @@ namespace Microsoft.AspNet.Mvc.Logging
{
public static class ViewComponentResultLoggerExtensions
{
- private static readonly Action _viewComponentResultExecuting;
+ private static readonly Action _viewComponentResultExecuting;
static ViewComponentResultLoggerExtensions()
{
- _viewComponentResultExecuting = LoggerMessage.Define(
+ _viewComponentResultExecuting = LoggerMessage.Define(
LogLevel.Information,
1,
- "Executing ViewComponentResult, running {ViewComponentName} with arguments ({Arguments}).");
+ "Executing ViewComponentResult, running {ViewComponentName}.");
}
- public static void ViewComponentResultExecuting(this ILogger logger, string viewComponentName, object[] arguments)
+ public static void ViewComponentResultExecuting(this ILogger logger, string viewComponentName)
{
if (logger.IsEnabled(LogLevel.Information))
{
- var formattedArguments = new string[arguments.Length];
- for (var i = 0; i < arguments.Length; i++)
- {
- formattedArguments[i] = Convert.ToString(arguments[i]);
- }
-
- _viewComponentResultExecuting(logger, viewComponentName, formattedArguments, null);
+ _viewComponentResultExecuting(logger, viewComponentName, null);
}
}
- public static void ViewComponentResultExecuting(this ILogger logger, Type viewComponentType, object[] arguments)
+ public static void ViewComponentResultExecuting(this ILogger logger, Type viewComponentType)
{
if (logger.IsEnabled(LogLevel.Information))
{
- var formattedArguments = new string[arguments.Length];
- for (var i = 0; i < arguments.Length; i++)
- {
- formattedArguments[i] = Convert.ToString(arguments[i]);
- }
-
- _viewComponentResultExecuting(logger, viewComponentType.Name, formattedArguments, null);
+ _viewComponentResultExecuting(logger, viewComponentType.Name, null);
}
}
}
diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/Microsoft.AspNet.Mvc.ViewFeatures.xproj b/src/Microsoft.AspNet.Mvc.ViewFeatures/Microsoft.AspNet.Mvc.ViewFeatures.xproj
index 4651550218..5bcc602f16 100644
--- a/src/Microsoft.AspNet.Mvc.ViewFeatures/Microsoft.AspNet.Mvc.ViewFeatures.xproj
+++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/Microsoft.AspNet.Mvc.ViewFeatures.xproj
@@ -3,6 +3,7 @@
14.0
$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
+ .resx
diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/Properties/Resources.Designer.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/Properties/Resources.Designer.cs
index 93e8b9ac97..ffd083d356 100644
--- a/src/Microsoft.AspNet.Mvc.ViewFeatures/Properties/Resources.Designer.cs
+++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/Properties/Resources.Designer.cs
@@ -27,7 +27,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
}
///
- /// The async view component method '{0}' should be declared to return Task<T>.
+ /// Method '{0}' of view component '{1}' should be declared to return {2}<T>.
///
internal static string ViewComponent_AsyncMethod_ShouldReturnTask
{
@@ -35,11 +35,11 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
}
///
- /// The async view component method '{0}' should be declared to return Task<T>.
+ /// Method '{0}' of view component '{1}' should be declared to return {2}<T>.
///
- internal static string FormatViewComponent_AsyncMethod_ShouldReturnTask(object p0)
+ internal static string FormatViewComponent_AsyncMethod_ShouldReturnTask(object p0, object p1, object p2)
{
- return string.Format(CultureInfo.CurrentCulture, GetString("ViewComponent_AsyncMethod_ShouldReturnTask"), p0);
+ return string.Format(CultureInfo.CurrentCulture, GetString("ViewComponent_AsyncMethod_ShouldReturnTask"), p0, p1, p2);
}
///
@@ -59,7 +59,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
}
///
- /// The view component method '{0}' should be declared to return a value.
+ /// Method '{0}' of view component '{1}' should be declared to return a value.
///
internal static string ViewComponent_SyncMethod_ShouldReturnValue
{
@@ -67,11 +67,11 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
}
///
- /// The view component method '{0}' should be declared to return a value.
+ /// Method '{0}' of view component '{1}' should be declared to return a value.
///
- internal static string FormatViewComponent_SyncMethod_ShouldReturnValue(object p0)
+ internal static string FormatViewComponent_SyncMethod_ShouldReturnValue(object p0, object p1)
{
- return string.Format(CultureInfo.CurrentCulture, GetString("ViewComponent_SyncMethod_ShouldReturnValue"), p0);
+ return string.Format(CultureInfo.CurrentCulture, GetString("ViewComponent_SyncMethod_ShouldReturnValue"), p0, p1);
}
///
@@ -107,7 +107,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
}
///
- /// Could not find an '{0}' method matching the parameters.
+ /// Could not find an '{0}' or '{1}' method for the view component '{2}'.
///
internal static string ViewComponent_CannotFindMethod
{
@@ -115,27 +115,11 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
}
///
- /// Could not find an '{0}' method matching the parameters.
+ /// Could not find an '{0}' or '{1}' method for the view component '{2}'.
///
- internal static string FormatViewComponent_CannotFindMethod(object p0)
+ internal static string FormatViewComponent_CannotFindMethod(object p0, object p1, object p2)
{
- return string.Format(CultureInfo.CurrentCulture, GetString("ViewComponent_CannotFindMethod"), p0);
- }
-
- ///
- /// Could not find an '{0}' or '{1}' method matching the parameters.
- ///
- internal static string ViewComponent_CannotFindMethod_WithFallback
- {
- get { return GetString("ViewComponent_CannotFindMethod_WithFallback"); }
- }
-
- ///
- /// Could not find an '{0}' or '{1}' method matching the parameters.
- ///
- internal static string FormatViewComponent_CannotFindMethod_WithFallback(object p0, object p1)
- {
- return string.Format(CultureInfo.CurrentCulture, GetString("ViewComponent_CannotFindMethod_WithFallback"), p0, p1);
+ return string.Format(CultureInfo.CurrentCulture, GetString("ViewComponent_CannotFindMethod"), p0, p1, p2);
}
///
@@ -859,7 +843,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
}
///
- /// The view component method '{0}' cannot return a {1}.
+ /// Method '{0}' of view component '{1}' cannot return a {2}.
///
internal static string ViewComponent_SyncMethod_CannotReturnTask
{
@@ -867,11 +851,27 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
}
///
- /// The view component method '{0}' cannot return a {1}.
+ /// Method '{0}' of view component '{1}' cannot return a {2}.
///
- internal static string FormatViewComponent_SyncMethod_CannotReturnTask(object p0, object p1)
+ internal static string FormatViewComponent_SyncMethod_CannotReturnTask(object p0, object p1, object p2)
{
- return string.Format(CultureInfo.CurrentCulture, GetString("ViewComponent_SyncMethod_CannotReturnTask"), p0, p1);
+ return string.Format(CultureInfo.CurrentCulture, GetString("ViewComponent_SyncMethod_CannotReturnTask"), p0, p1, p2);
+ }
+
+ ///
+ /// View component '{0}' must have exactly one public method named '{1}' or '{2}'.
+ ///
+ internal static string ViewComponent_AmbiguousMethods
+ {
+ get { return GetString("ViewComponent_AmbiguousMethods"); }
+ }
+
+ ///
+ /// View component '{0}' must have exactly one public method named '{1}' or '{2}'.
+ ///
+ internal static string FormatViewComponent_AmbiguousMethods(object p0, object p1, object p2)
+ {
+ return string.Format(CultureInfo.CurrentCulture, GetString("ViewComponent_AmbiguousMethods"), p0, p1, p2);
}
private static string GetString(string name, params string[] formatterNames)
diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/Rendering/ViewComponentHelperExtensions.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/Rendering/ViewComponentHelperExtensions.cs
index 59d73fd24a..f5513cae9e 100644
--- a/src/Microsoft.AspNet.Mvc.ViewFeatures/Rendering/ViewComponentHelperExtensions.cs
+++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/Rendering/ViewComponentHelperExtensions.cs
@@ -7,48 +7,76 @@ using Microsoft.AspNet.Html;
namespace Microsoft.AspNet.Mvc.Rendering
{
+ ///
+ /// Extension methods for .
+ ///
public static class ViewComponentHelperExtensions
{
- public static IHtmlContent Invoke(this IViewComponentHelper helper, params object[] args)
+ ///
+ /// Invokes a view component with the specified .
+ ///
+ /// The name of the view component.
+ /// A that on completion returns the rendered .
+ ///
+ public static Task InvokeAsync(this IViewComponentHelper helper, string name)
{
if (helper == null)
{
throw new ArgumentNullException(nameof(helper));
}
- return helper.Invoke(typeof(TComponent), args);
+ return helper.InvokeAsync(name, arguments: null);
}
- public static void RenderInvoke(this IViewComponentHelper helper, params object[] args)
+ ///
+ /// Invokes a view component of type .
+ ///
+ /// The view component .
+ /// A that on completion returns the rendered .
+ ///
+ public static Task InvokeAsync(this IViewComponentHelper helper, Type componentType)
{
if (helper == null)
{
throw new ArgumentNullException(nameof(helper));
}
- helper.RenderInvoke(typeof(TComponent), args);
+ return helper.InvokeAsync(componentType, arguments: null);
}
- public static Task InvokeAsync(
- this IViewComponentHelper helper,
- params object[] args)
+ ///
+ /// Invokes a view component of type .
+ ///
+ /// The .
+ /// Arguments to be passed to the invoked view component method.
+ /// The of the view component.
+ /// A that on completion returns the rendered .
+ ///
+ public static Task InvokeAsync(this IViewComponentHelper helper, object arguments)
{
if (helper == null)
{
throw new ArgumentNullException(nameof(helper));
}
- return helper.InvokeAsync(typeof(TComponent), args);
+ return helper.InvokeAsync(typeof(TComponent), arguments);
}
- public static Task RenderInvokeAsync(this IViewComponentHelper helper, params object[] args)
+ ///
+ /// Invokes a view component of type .
+ ///
+ /// The .
+ /// The of the view component.
+ /// A that on completion returns the rendered .
+ ///
+ public static Task InvokeAsync(this IViewComponentHelper helper)
{
if (helper == null)
{
throw new ArgumentNullException(nameof(helper));
}
- return helper.RenderInvokeAsync(typeof(TComponent), args);
+ return helper.InvokeAsync(typeof(TComponent), arguments: null);
}
}
}
diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/Resources.resx b/src/Microsoft.AspNet.Mvc.ViewFeatures/Resources.resx
index 81c987746f..e389b62f3a 100644
--- a/src/Microsoft.AspNet.Mvc.ViewFeatures/Resources.resx
+++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/Resources.resx
@@ -1,17 +1,17 @@
-
@@ -122,13 +122,13 @@
{1} is the newline character
- The async view component method '{0}' should be declared to return Task<T>.
+ Method '{0}' of view component '{1}' should be declared to return {2}<T>.
A view component must return a non-null value.
- The view component method '{0}' should be declared to return a value.
+ Method '{0}' of view component '{1}' should be declared to return a value.
A view component named '{0}' could not be found.
@@ -137,10 +137,7 @@
An invoker could not be created for the view component '{0}'.
- Could not find an '{0}' method matching the parameters.
-
-
- Could not find an '{0}' or '{1}' method matching the parameters.
+ Could not find an '{0}' or '{1}' method for the view component '{2}'.
View components only support returning {0}, {1} or {2}.
@@ -278,6 +275,9 @@
The collection already contains an entry with key '{0}'.
- The view component method '{0}' cannot return a {1}.
+ Method '{0}' of view component '{1}' cannot return a {2}.
+
+
+ View component '{0}' must have exactly one public method named '{1}' or '{2}'.
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponentResult.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponentResult.cs
index 0a78f946b7..de9cba9191 100644
--- a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponentResult.cs
+++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponentResult.cs
@@ -3,7 +3,9 @@
using System;
using System.Text;
+using System.Text.Encodings.Web;
using System.Threading.Tasks;
+using Microsoft.AspNet.Html;
using Microsoft.AspNet.Mvc.Internal;
using Microsoft.AspNet.Mvc.Logging;
using Microsoft.AspNet.Mvc.ModelBinding;
@@ -26,7 +28,7 @@ namespace Microsoft.AspNet.Mvc
///
/// Gets or sets the arguments provided to the view component.
///
- public object[] Arguments { get; set; }
+ public object Arguments { get; set; }
///
/// Gets or sets the representing the Content-Type header of the response.
@@ -77,6 +79,7 @@ namespace Microsoft.AspNet.Mvc
var loggerFactory = services.GetRequiredService();
var logger = loggerFactory.CreateLogger();
+ var htmlEncoder = services.GetRequiredService();
var viewData = ViewData;
if (viewData == null)
@@ -119,23 +122,29 @@ namespace Microsoft.AspNet.Mvc
htmlHelperOptions);
(viewComponentHelper as ICanHasViewContext)?.Contextualize(viewContext);
+ var result = await GetViewComponentResult(viewComponentHelper, logger);
- if (ViewComponentType == null && ViewComponentName == null)
- {
- throw new InvalidOperationException(Resources.FormatViewComponentResult_NameOrTypeMustBeSet(
- nameof(ViewComponentName),
- nameof(ViewComponentType)));
- }
- else if (ViewComponentType == null)
- {
- logger.ViewComponentResultExecuting(ViewComponentName, Arguments);
- await viewComponentHelper.RenderInvokeAsync(ViewComponentName, Arguments);
- }
- else
- {
- logger.ViewComponentResultExecuting(ViewComponentType, Arguments);
- await viewComponentHelper.RenderInvokeAsync(ViewComponentType, Arguments);
- }
+ result.WriteTo(writer, htmlEncoder);
+ }
+ }
+
+ private Task GetViewComponentResult(IViewComponentHelper viewComponentHelper, ILogger logger)
+ {
+ if (ViewComponentType == null && ViewComponentName == null)
+ {
+ throw new InvalidOperationException(Resources.FormatViewComponentResult_NameOrTypeMustBeSet(
+ nameof(ViewComponentName),
+ nameof(ViewComponentType)));
+ }
+ else if (ViewComponentType == null)
+ {
+ logger.ViewComponentResultExecuting(ViewComponentName);
+ return viewComponentHelper.InvokeAsync(ViewComponentName, Arguments);
+ }
+ else
+ {
+ logger.ViewComponentResultExecuting(ViewComponentType);
+ return viewComponentHelper.InvokeAsync(ViewComponentType, Arguments);
}
}
}
diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponents/DefaultViewComponentDescriptorProvider.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponents/DefaultViewComponentDescriptorProvider.cs
index 0cd2f12fc5..739d43f01b 100644
--- a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponents/DefaultViewComponentDescriptorProvider.cs
+++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponents/DefaultViewComponentDescriptorProvider.cs
@@ -5,7 +5,9 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
+using System.Threading.Tasks;
using Microsoft.AspNet.Mvc.Infrastructure;
+using Microsoft.AspNet.Mvc.ViewFeatures;
namespace Microsoft.AspNet.Mvc.ViewComponents
{
@@ -14,6 +16,8 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
///
public class DefaultViewComponentDescriptorProvider : IViewComponentDescriptorProvider
{
+ private const string AsyncMethodName = "InvokeAsync";
+ private const string SyncMethodName = "Invoke";
private readonly IAssemblyProvider _assemblyProvider;
///
@@ -32,7 +36,7 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
return types
.Where(IsViewComponentType)
- .Select(CreateCandidate);
+ .Select(CreateDescriptor);
}
///
@@ -47,11 +51,11 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
}
///
- /// Determines whether or not the given is a View Component class.
+ /// Determines whether or not the given is a view component class.
///
/// The .
///
- /// true if represents a View Component class, otherwise false.
+ /// true if represents a view component class, otherwise false.
///
protected virtual bool IsViewComponentType(TypeInfo typeInfo)
{
@@ -63,16 +67,70 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
return ViewComponentConventions.IsComponent(typeInfo);
}
- private static ViewComponentDescriptor CreateCandidate(TypeInfo typeInfo)
+ private static ViewComponentDescriptor CreateDescriptor(TypeInfo typeInfo)
{
- var candidate = new ViewComponentDescriptor()
+ var type = typeInfo.AsType();
+ var candidate = new ViewComponentDescriptor
{
FullName = ViewComponentConventions.GetComponentFullName(typeInfo),
ShortName = ViewComponentConventions.GetComponentName(typeInfo),
- Type = typeInfo.AsType(),
+ Type = type,
+ MethodInfo = FindMethod(type)
};
return candidate;
}
+
+ private static MethodInfo FindMethod(Type componentType)
+ {
+ var componentName = componentType.FullName;
+ var methods = componentType.GetMethods(BindingFlags.Public | BindingFlags.Instance)
+ .Where(method =>
+ string.Equals(method.Name, AsyncMethodName, StringComparison.Ordinal) ||
+ string.Equals(method.Name, SyncMethodName, StringComparison.Ordinal))
+ .ToArray();
+
+ if (methods.Length == 0)
+ {
+ throw new InvalidOperationException(
+ Resources.FormatViewComponent_CannotFindMethod(SyncMethodName, AsyncMethodName, componentName));
+ }
+ else if (methods.Length > 1)
+ {
+ throw new InvalidOperationException(
+ Resources.FormatViewComponent_AmbiguousMethods(componentName, AsyncMethodName, SyncMethodName));
+ }
+
+ var selectedMethod = methods[0];
+ if (string.Equals(selectedMethod.Name, AsyncMethodName, StringComparison.Ordinal))
+ {
+ if (!selectedMethod.ReturnType.GetTypeInfo().IsGenericType ||
+ selectedMethod.ReturnType.GetGenericTypeDefinition() != typeof(Task<>))
+ {
+ throw new InvalidOperationException(Resources.FormatViewComponent_AsyncMethod_ShouldReturnTask(
+ AsyncMethodName,
+ componentName,
+ nameof(Task)));
+ }
+ }
+ else
+ {
+ if (selectedMethod.ReturnType == typeof(void))
+ {
+ throw new InvalidOperationException(Resources.FormatViewComponent_SyncMethod_ShouldReturnValue(
+ SyncMethodName,
+ componentName));
+ }
+ else if (selectedMethod.ReturnType.IsAssignableFrom(typeof(Task)))
+ {
+ throw new InvalidOperationException(Resources.FormatViewComponent_SyncMethod_CannotReturnTask(
+ SyncMethodName,
+ componentName,
+ nameof(Task)));
+ }
+ }
+
+ return selectedMethod;
+ }
}
}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponents/DefaultViewComponentHelper.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponents/DefaultViewComponentHelper.cs
index 4de8c683c1..9a1e1efcef 100644
--- a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponents/DefaultViewComponentHelper.cs
+++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponents/DefaultViewComponentHelper.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
-using System.IO;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Microsoft.AspNet.Html;
@@ -10,9 +9,13 @@ using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Mvc.ViewFeatures;
using Microsoft.AspNet.Mvc.ViewFeatures.Buffer;
using Microsoft.AspNet.Mvc.ViewFeatures.Internal;
+using Microsoft.Extensions.Internal;
namespace Microsoft.AspNet.Mvc.ViewComponents
{
+ ///
+ /// Default implementation for .
+ ///
public class DefaultViewComponentHelper : IViewComponentHelper, ICanHasViewContext
{
private readonly IViewComponentDescriptorCollectionProvider _descriptorProvider;
@@ -22,6 +25,16 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
private readonly IViewBufferScope _viewBufferScope;
private ViewContext _viewContext;
+ ///
+ /// Initializes a new instance of .
+ ///
+ /// The
+ /// used to locate view components.
+ /// The .
+ /// The .
+ /// The .
+ /// The that manages the lifetime of
+ /// instances.
public DefaultViewComponentHelper(
IViewComponentDescriptorCollectionProvider descriptorProvider,
HtmlEncoder htmlEncoder,
@@ -61,6 +74,7 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
_viewBufferScope = viewBufferScope;
}
+ ///
public void Contextualize(ViewContext viewContext)
{
if (viewContext == null)
@@ -71,133 +85,41 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
_viewContext = viewContext;
}
- public IHtmlContent Invoke(string name, params object[] arguments)
+ ///
+ public Task InvokeAsync(string name, object arguments)
{
if (name == null)
{
throw new ArgumentNullException(nameof(name));
}
- var descriptor = SelectComponent(name);
-
- var viewBuffer = new ViewBuffer(_viewBufferScope, name);
- using (var writer = new HtmlContentWrapperTextWriter(viewBuffer, _viewContext.Writer.Encoding))
- {
- InvokeCore(writer, descriptor, arguments);
- return writer.ContentBuilder;
- }
- }
-
- public IHtmlContent Invoke(Type componentType, params object[] arguments)
- {
- if (componentType == null)
- {
- throw new ArgumentNullException(nameof(componentType));
- }
-
- var descriptor = SelectComponent(componentType);
- var viewBuffer = new ViewBuffer(_viewBufferScope, componentType.Name);
- using (var writer = new HtmlContentWrapperTextWriter(viewBuffer, _viewContext.Writer.Encoding))
- {
- InvokeCore(writer, descriptor, arguments);
- return writer.ContentBuilder;
- }
- }
-
- public void RenderInvoke(string name, params object[] arguments)
- {
- if (name == null)
- {
- throw new ArgumentNullException(nameof(name));
- }
-
- var descriptor = SelectComponent(name);
- InvokeCore(_viewContext.Writer, descriptor, arguments);
- }
-
- public void RenderInvoke(Type componentType, params object[] arguments)
- {
- if (componentType == null)
- {
- throw new ArgumentNullException(nameof(componentType));
- }
-
- var descriptor = SelectComponent(componentType);
- InvokeCore(_viewContext.Writer, descriptor, arguments);
- }
-
- public async Task InvokeAsync(string name, params object[] arguments)
- {
- if (name == null)
- {
- throw new ArgumentNullException(nameof(name));
- }
-
- var descriptor = SelectComponent(name);
-
- var viewBuffer = new ViewBuffer(_viewBufferScope, name);
- using (var writer = new HtmlContentWrapperTextWriter(viewBuffer, _viewContext.Writer.Encoding))
- {
- await InvokeCoreAsync(writer, descriptor, arguments);
- return writer.ContentBuilder;
- }
- }
-
- public async Task InvokeAsync(Type componentType, params object[] arguments)
- {
- if (componentType == null)
- {
- throw new ArgumentNullException(nameof(componentType));
- }
-
- var descriptor = SelectComponent(componentType);
-
- var viewBuffer = new ViewBuffer(_viewBufferScope, componentType.Name);
- using (var writer = new HtmlContentWrapperTextWriter(viewBuffer, _viewContext.Writer.Encoding))
- {
- await InvokeCoreAsync(writer, descriptor, arguments);
- return writer.ContentBuilder;
- }
- }
-
- public Task RenderInvokeAsync(string name, params object[] arguments)
- {
- if (name == null)
- {
- throw new ArgumentNullException(nameof(name));
- }
-
- var descriptor = SelectComponent(name);
- return InvokeCoreAsync(_viewContext.Writer, descriptor, arguments);
- }
-
- public Task RenderInvokeAsync(Type componentType, params object[] arguments)
- {
- if (componentType == null)
- {
- throw new ArgumentNullException(nameof(componentType));
- }
-
- var descriptor = SelectComponent(componentType);
- return 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 descriptor;
+ return InvokeCoreAsync(descriptor, arguments);
+ }
+
+ ///
+ public Task InvokeAsync(Type componentType, object arguments)
+ {
+ if (componentType == null)
+ {
+ throw new ArgumentNullException(nameof(componentType));
+ }
+
+ var descriptor = SelectComponent(componentType);
+ return InvokeCoreAsync(descriptor, arguments);
}
private ViewComponentDescriptor SelectComponent(Type componentType)
{
var descriptors = _descriptorProvider.ViewComponents;
- foreach (var descriptor in descriptors.Items)
+ for (var i = 0; i < descriptors.Items.Count; i++)
{
+ var descriptor = descriptors.Items[i];
if (descriptor.Type == componentType)
{
return descriptor;
@@ -208,58 +130,30 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
componentType.FullName));
}
- private Task InvokeCoreAsync(
- TextWriter writer,
+ private async Task InvokeCoreAsync(
ViewComponentDescriptor descriptor,
- object[] arguments)
+ object arguments)
{
- if (writer == null)
+ var viewBuffer = new ViewBuffer(_viewBufferScope, descriptor.FullName);
+ using (var writer = new HtmlContentWrapperTextWriter(viewBuffer, _viewContext.Writer.Encoding))
{
- throw new ArgumentNullException(nameof(writer));
+ var context = new ViewComponentContext(
+ descriptor,
+ PropertyHelper.ObjectToDictionary(arguments),
+ _htmlEncoder,
+ _viewContext,
+ writer);
+
+ var invoker = _invokerFactory.CreateInstance(context);
+ if (invoker == null)
+ {
+ throw new InvalidOperationException(
+ Resources.FormatViewComponent_IViewComponentFactory_ReturnedNull(descriptor.FullName));
+ }
+
+ await invoker.InvokeAsync(context);
+ return writer.ContentBuilder;
}
-
- if (descriptor == null)
- {
- throw new ArgumentNullException(nameof(descriptor));
- }
-
- var context = new ViewComponentContext(descriptor, arguments, _htmlEncoder, _viewContext, writer);
-
- var invoker = _invokerFactory.CreateInstance(context);
- if (invoker == null)
- {
- throw new InvalidOperationException(
- Resources.FormatViewComponent_IViewComponentFactory_ReturnedNull(descriptor.Type.FullName));
- }
-
- return invoker.InvokeAsync(context);
- }
-
- private void InvokeCore(
- TextWriter writer,
- ViewComponentDescriptor descriptor,
- object[] arguments)
- {
- if (writer == null)
- {
- throw new ArgumentNullException(nameof(writer));
- }
-
- if (descriptor == null)
- {
- throw new ArgumentNullException(nameof(descriptor));
- }
-
- var context = new ViewComponentContext(descriptor, arguments, _htmlEncoder, _viewContext, writer);
-
- var invoker = _invokerFactory.CreateInstance(context);
- if (invoker == null)
- {
- throw new InvalidOperationException(
- Resources.FormatViewComponent_IViewComponentFactory_ReturnedNull(descriptor.Type.FullName));
- }
-
- invoker.Invoke(context);
}
}
}
diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponents/DefaultViewComponentInvoker.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponents/DefaultViewComponentInvoker.cs
index 21750a1989..f0aad1a660 100644
--- a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponents/DefaultViewComponentInvoker.cs
+++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponents/DefaultViewComponentInvoker.cs
@@ -16,6 +16,9 @@ using Microsoft.Extensions.Logging;
namespace Microsoft.AspNet.Mvc.ViewComponents
{
+ ///
+ /// Default implementation for .
+ ///
public class DefaultViewComponentInvoker : IViewComponentInvoker
{
private readonly ITypeActivatorCache _typeActivatorCache;
@@ -23,6 +26,13 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
private readonly DiagnosticSource _diagnosticSource;
private readonly ILogger _logger;
+ ///
+ /// Initializes a new instance of .
+ ///
+ /// Caches factories for instantiating view component instances.
+ /// The .
+ /// The .
+ /// The .
public DefaultViewComponentInvoker(
ITypeActivatorCache typeActivatorCache,
IViewComponentActivator viewComponentActivator,
@@ -55,27 +65,7 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
_logger = logger;
}
- public void Invoke(ViewComponentContext context)
- {
- if (context == null)
- {
- throw new ArgumentNullException(nameof(context));
- }
-
- 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);
-
- result.Execute(context);
- }
-
+ ///
public async Task InvokeAsync(ViewComponentContext context)
{
if (context == null)
@@ -83,32 +73,25 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
throw new ArgumentNullException(nameof(context));
}
- IViewComponentResult result;
-
- var asyncMethod = ViewComponentMethodSelector.FindAsyncMethod(
- context.ViewComponentDescriptor.Type.GetTypeInfo(),
- context.Arguments);
- if (asyncMethod == null)
+ var methodInfo = context.ViewComponentDescriptor?.MethodInfo;
+ if (methodInfo == 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(
- context.ViewComponentDescriptor.Type.GetTypeInfo(),
- context.Arguments);
- if (syncMethod == null)
- {
- throw new InvalidOperationException(
- Resources.FormatViewComponent_CannotFindMethod_WithFallback(
- ViewComponentMethodSelector.SyncMethodName, ViewComponentMethodSelector.AsyncMethodName));
- }
- else
- {
- result = InvokeSyncCore(syncMethod, context);
- }
+ throw new InvalidOperationException(Resources.FormatPropertyOfTypeCannotBeNull(
+ nameof(ViewComponentDescriptor.MethodInfo),
+ nameof(ViewComponentDescriptor)));
+ }
+
+ var isAsync = typeof(Task).GetTypeInfo().IsAssignableFrom(methodInfo.ReturnType.GetTypeInfo());
+ IViewComponentResult result;
+ if (isAsync)
+ {
+ result = await InvokeAsyncCore(context);
}
else
{
- result = await InvokeAsyncCore(asyncMethod, context);
+ // We support falling back to synchronous if there is no InvokeAsync method, in this case we'll still
+ // execute the IViewResult asynchronously.
+ result = InvokeSyncCore(context);
}
await result.ExecuteAsync(context);
@@ -129,29 +112,20 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
return component;
}
- private async Task InvokeAsyncCore(
- MethodInfo method,
- ViewComponentContext context)
+ private async Task InvokeAsyncCore(ViewComponentContext context)
{
- if (method == null)
- {
- throw new ArgumentNullException(nameof(method));
- }
-
- if (context == null)
- {
- throw new ArgumentNullException(nameof(context));
- }
-
var component = CreateComponent(context);
using (_logger.ViewComponentScope(context))
{
+ var method = context.ViewComponentDescriptor.MethodInfo;
+ var arguments = ControllerActionExecutor.PrepareArguments(context.Arguments, method.GetParameters());
+
_diagnosticSource.BeforeViewComponent(context, component);
- _logger.ViewComponentExecuting(context);
+ _logger.ViewComponentExecuting(context, arguments);
var startTime = Environment.TickCount;
- var result = await ControllerActionExecutor.ExecuteAsync(method, component, context.Arguments);
+ var result = await ControllerActionExecutor.ExecuteAsync(method, component, arguments);
var viewComponentResult = CoerceToViewComponentResult(result);
_logger.ViewComponentExecuted(context, startTime, viewComponentResult);
@@ -161,35 +135,25 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
}
}
- public IViewComponentResult InvokeSyncCore(MethodInfo method, ViewComponentContext context)
+ private IViewComponentResult InvokeSyncCore(ViewComponentContext context)
{
- if (method == null)
- {
- throw new ArgumentNullException(nameof(method));
- }
-
- if (context == null)
- {
- throw new ArgumentNullException(nameof(context));
- }
-
var component = CreateComponent(context);
using (_logger.ViewComponentScope(context))
{
- _diagnosticSource.BeforeViewComponent(context, component);
- _logger.ViewComponentExecuting(context);
+ var method = context.ViewComponentDescriptor.MethodInfo;
+ var arguments = ControllerActionExecutor.PrepareArguments(
+ context.Arguments,
+ method.GetParameters());
+ _diagnosticSource.BeforeViewComponent(context, component);
+ _logger.ViewComponentExecuting(context, arguments);
+
+ var startTime = Environment.TickCount;
+ object result;
try
{
- var startTime = Environment.TickCount;
- var result = method.Invoke(component, context.Arguments);
-
- var viewComponentResult = CoerceToViewComponentResult(result);
- _logger.ViewComponentExecuted(context, startTime, viewComponentResult);
- _diagnosticSource.AfterViewComponent(context, viewComponentResult, component);
-
- return viewComponentResult;
+ result = method.Invoke(component, arguments);
}
catch (TargetInvocationException ex)
{
@@ -198,6 +162,12 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
exceptionInfo.Throw();
return null; // Unreachable
}
+
+ var viewComponentResult = CoerceToViewComponentResult(result);
+ _logger.ViewComponentExecuted(context, startTime, viewComponentResult);
+ _diagnosticSource.AfterViewComponent(context, viewComponentResult, component);
+
+ return viewComponentResult;
}
}
diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponents/IViewComponentDescriptorProvider.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponents/IViewComponentDescriptorProvider.cs
index e47e5b0a51..e8d41025d4 100644
--- a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponents/IViewComponentDescriptorProvider.cs
+++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponents/IViewComponentDescriptorProvider.cs
@@ -6,7 +6,7 @@ using System.Collections.Generic;
namespace Microsoft.AspNet.Mvc.ViewComponents
{
///
- /// Discovers the View Components in the application.
+ /// Discovers the view components in the application.
///
public interface IViewComponentDescriptorProvider
{
diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponents/IViewComponentInvoker.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponents/IViewComponentInvoker.cs
index 7e9e5d7f8f..02c0e9a4bb 100644
--- a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponents/IViewComponentInvoker.cs
+++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponents/IViewComponentInvoker.cs
@@ -5,10 +5,17 @@ using System.Threading.Tasks;
namespace Microsoft.AspNet.Mvc.ViewComponents
{
+ ///
+ /// Specifies the contract for execution of a view component.
+ ///
public interface IViewComponentInvoker
{
- void Invoke(ViewComponentContext context);
-
+ ///
+ /// Executes the view component specified by
+ /// of and writes the result to .
+ ///
+ /// The .
+ /// A that represents the asynchronous operation of execution.
Task InvokeAsync(ViewComponentContext context);
}
}
diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponents/IViewComponentSelector.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponents/IViewComponentSelector.cs
index d4813b4d57..6ff2ba0de2 100644
--- a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponents/IViewComponentSelector.cs
+++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponents/IViewComponentSelector.cs
@@ -4,14 +4,14 @@
namespace Microsoft.AspNet.Mvc.ViewComponents
{
///
- /// Selects a View Component based on a View Component name.
+ /// Selects a view component based on a view component name.
///
public interface IViewComponentSelector
{
///
- /// Selects a View Component based on .
+ /// Selects a view component based on .
///
- /// The View Component name.
+ /// The view component name.
/// A , or null if no match is found.
ViewComponentDescriptor SelectComponent(string componentName);
}
diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponents/ViewComponentContext.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponents/ViewComponentContext.cs
index 699fecaf89..edb9eab8cd 100644
--- a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponents/ViewComponentContext.cs
+++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponents/ViewComponentContext.cs
@@ -2,6 +2,7 @@
// 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.IO;
using System.Text.Encodings.Web;
using Microsoft.AspNet.Mvc.Rendering;
@@ -10,7 +11,7 @@ using Microsoft.AspNet.Mvc.ViewFeatures;
namespace Microsoft.AspNet.Mvc.ViewComponents
{
///
- /// A context for View Components.
+ /// A context for view components.
///
public class ViewComponentContext
{
@@ -23,7 +24,6 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
public ViewComponentContext()
{
ViewComponentDescriptor = new ViewComponentDescriptor();
- Arguments = new object[0];
ViewContext = new ViewContext();
}
@@ -31,14 +31,14 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
/// Creates a new .
///
///
- /// The for the View Component being invoked.
+ /// The for the view component being invoked.
///
- /// The View Component arguments.
+ /// The view component arguments.
/// The .
/// The for writing output.
public ViewComponentContext(
ViewComponentDescriptor viewComponentDescriptor,
- object[] arguments,
+ IDictionary arguments,
HtmlEncoder htmlEncoder,
ViewContext viewContext,
TextWriter writer)
@@ -82,15 +82,15 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
}
///
- /// Gets or sets the View Component arguments.
+ /// Gets or sets the view component arguments.
///
///
/// The property setter is provided for unit test purposes only.
///
- public object[] Arguments { get; set; }
+ public IDictionary Arguments { get; set; }
///
- /// Gets or sets the .
+ /// Gets or sets the .
///
///
/// The property setter is provided for unit test purposes only.
@@ -98,7 +98,7 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
public HtmlEncoder HtmlEncoder { get; set; }
///
- /// Gets or sets the for the View Component being invoked.
+ /// Gets or sets the for the view component being invoked.
///
///
/// The property setter is provided for unit test purposes only.
@@ -106,7 +106,7 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
public ViewComponentDescriptor ViewComponentDescriptor { get; set; }
///
- /// Gets or sets the .
+ /// Gets or sets the .
///
///
/// The property setter is provided for unit test purposes only.
diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponents/ViewComponentDescriptor.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponents/ViewComponentDescriptor.cs
index 22abe0f75d..c554e0974f 100644
--- a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponents/ViewComponentDescriptor.cs
+++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponents/ViewComponentDescriptor.cs
@@ -3,11 +3,12 @@
using System;
using System.Diagnostics;
+using System.Reflection;
namespace Microsoft.AspNet.Mvc.ViewComponents
{
///
- /// A descriptor for a View Component.
+ /// A descriptor for a view component.
///
[DebuggerDisplay("{DisplayName}")]
public class ViewComponentDescriptor
@@ -23,7 +24,7 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
}
///
- /// Gets or sets the display name of the View Component.
+ /// Gets or sets the display name of the view component.
///
public string DisplayName
{
@@ -53,8 +54,8 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
///
///
///
- /// 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
+ /// 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
/// ViewComponent as a suffix, the suffix will be omitted from the .
///
///
@@ -89,7 +90,7 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
///
///
///
- /// The short name is defaulted to the name of the View Component class. If the View Component class uses
+ /// The short name is defaulted to the name of the view component class. If the view component class uses
/// ViewComponent as a suffix, the suffix will be omitted from the .
///
///
@@ -115,8 +116,13 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
public string ShortName { get; set; }
///
- /// Gets or sets the .
+ /// Gets or sets the .
///
public Type Type { get; set; }
+
+ ///
+ /// Gets or sets the to invoke.
+ ///
+ public MethodInfo MethodInfo { get; set; }
}
}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponents/ViewComponentMethodSelector.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponents/ViewComponentMethodSelector.cs
deleted file mode 100644
index c6ef5c730b..0000000000
--- a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponents/ViewComponentMethodSelector.cs
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.Linq.Expressions;
-using System.Reflection;
-using System.Threading.Tasks;
-using Microsoft.AspNet.Mvc.ViewFeatures;
-
-namespace Microsoft.AspNet.Mvc.ViewComponents
-{
- public static class ViewComponentMethodSelector
- {
- public const string AsyncMethodName = "InvokeAsync";
- public const string SyncMethodName = "Invoke";
-
- public static MethodInfo FindAsyncMethod(TypeInfo componentType, object[] args)
- {
- if (componentType == null)
- {
- throw new ArgumentNullException(nameof(componentType));
- }
-
- var method = GetMethod(componentType, args, AsyncMethodName);
- if (method == null)
- {
- return null;
- }
-
- if (!method.ReturnType.GetTypeInfo().IsGenericType ||
- method.ReturnType.GetGenericTypeDefinition() != typeof(Task<>))
- {
- throw new InvalidOperationException(
- Resources.FormatViewComponent_AsyncMethod_ShouldReturnTask(AsyncMethodName));
- }
-
- return method;
- }
-
- public static MethodInfo FindSyncMethod(TypeInfo componentType, object[] args)
- {
- if (componentType == null)
- {
- throw new ArgumentNullException(nameof(componentType));
- }
-
- var method = GetMethod(componentType, args, SyncMethodName);
- if (method == null)
- {
- return null;
- }
-
- if (method.ReturnType == typeof(void))
- {
- throw new InvalidOperationException(
- Resources.FormatViewComponent_SyncMethod_ShouldReturnValue(SyncMethodName));
- }
- else if (method.ReturnType.IsAssignableFrom(typeof(Task)))
- {
- throw new InvalidOperationException(
- Resources.FormatViewComponent_SyncMethod_CannotReturnTask(SyncMethodName, nameof(Task)));
- }
-
- return method;
- }
-
- private static MethodInfo GetMethod(TypeInfo componentType, object[] args, string methodName)
- {
- Type[] types;
- if (args == null || args.Length == 0)
- {
- types = Type.EmptyTypes;
- }
- else
- {
- types = new Type[args.Length];
- for (var i = 0; i < args.Length; i++)
- {
- types[i] = args[i]?.GetType() ?? typeof(object);
- }
- }
-
-#if NET451
- return componentType.AsType().GetMethod(
- methodName,
- BindingFlags.Public | BindingFlags.Instance,
- binder: null,
- types: types,
- modifiers: null);
-#else
- var method = componentType.AsType().GetMethod(methodName, types: types);
- // At most one method (including static and instance methods) with the same parameter types can exist
- // per type.
- return method != null && method.IsStatic ? null : method;
-#endif
- }
- }
-}
diff --git a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponentResultTest.cs b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponentResultTest.cs
index 8fdc3eff6b..93abe8738f 100644
--- a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponentResultTest.cs
+++ b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponentResultTest.cs
@@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
+using System.Reflection;
using System.Text;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
@@ -42,13 +43,14 @@ namespace Microsoft.AspNet.Mvc
FullName = "Full.Name.Text",
ShortName = "Text",
Type = typeof(TextViewComponent),
+ MethodInfo = typeof(TextViewComponent).GetMethod(nameof(TextViewComponent.Invoke)),
};
var actionContext = CreateActionContext(descriptor);
var viewComponentResult = new ViewComponentResult
{
- Arguments = new object[] { "World!" },
+ Arguments = new { name = "World!" },
ViewData = null,
TempData = null,
ViewComponentName = "Text"
@@ -132,13 +134,43 @@ namespace Microsoft.AspNet.Mvc
FullName = "Full.Name.Text",
ShortName = "Text",
Type = typeof(TextViewComponent),
+ MethodInfo = typeof(TextViewComponent).GetMethod(nameof(TextViewComponent.Invoke)),
};
var actionContext = CreateActionContext(descriptor);
var viewComponentResult = new ViewComponentResult()
{
- Arguments = new object[] { "World!" },
+ Arguments = new { name = "World!" },
+ ViewComponentName = "Text",
+ TempData = _tempDataDictionary,
+ };
+
+ // Act
+ await viewComponentResult.ExecuteResultAsync(actionContext);
+
+ // Assert
+ var body = ReadBody(actionContext.HttpContext.Response);
+ Assert.Equal("Hello, World!", body);
+ }
+
+ [Fact]
+ public async Task ExecuteResultAsync_UsesDictionaryArguments()
+ {
+ // Arrange
+ var descriptor = new ViewComponentDescriptor()
+ {
+ FullName = "Full.Name.Text",
+ ShortName = "Text",
+ Type = typeof(TextViewComponent),
+ MethodInfo = typeof(TextViewComponent).GetMethod(nameof(TextViewComponent.Invoke)),
+ };
+
+ var actionContext = CreateActionContext(descriptor);
+
+ var viewComponentResult = new ViewComponentResult()
+ {
+ Arguments = new Dictionary { ["name"] = "World!" },
ViewComponentName = "Text",
TempData = _tempDataDictionary,
};
@@ -160,13 +192,14 @@ namespace Microsoft.AspNet.Mvc
FullName = "Full.Name.AsyncText",
ShortName = "AsyncText",
Type = typeof(AsyncTextViewComponent),
+ MethodInfo = typeof(AsyncTextViewComponent).GetMethod(nameof(AsyncTextViewComponent.InvokeAsync)),
};
var actionContext = CreateActionContext(descriptor);
var viewComponentResult = new ViewComponentResult()
{
- Arguments = new object[] { "World!" },
+ Arguments = new { name = "World!" },
ViewComponentName = "AsyncText",
TempData = _tempDataDictionary,
};
@@ -188,6 +221,7 @@ namespace Microsoft.AspNet.Mvc
FullName = "Full.Name.Text",
ShortName = "Text",
Type = typeof(TextViewComponent),
+ MethodInfo = typeof(TextViewComponent).GetMethod(nameof(TextViewComponent.Invoke)),
};
var adapter = new TestDiagnosticListener();
@@ -196,7 +230,7 @@ namespace Microsoft.AspNet.Mvc
var viewComponentResult = new ViewComponentResult()
{
- Arguments = new object[] { "World!" },
+ Arguments = new { name = "World!" },
ViewComponentName = "Text",
TempData = _tempDataDictionary,
};
@@ -226,13 +260,14 @@ namespace Microsoft.AspNet.Mvc
FullName = "Full.Name.Text",
ShortName = "Text",
Type = typeof(TextViewComponent),
+ MethodInfo = typeof(TextViewComponent).GetMethod(nameof(TextViewComponent.Invoke)),
};
var actionContext = CreateActionContext(descriptor);
var viewComponentResult = new ViewComponentResult()
{
- Arguments = new object[] { "World!" },
+ Arguments = new { name = "World!" },
ViewComponentName = "Text",
TempData = _tempDataDictionary,
};
@@ -254,13 +289,14 @@ namespace Microsoft.AspNet.Mvc
FullName = "Full.Name.Text",
ShortName = "Text",
Type = typeof(TextViewComponent),
+ MethodInfo = typeof(TextViewComponent).GetMethod(nameof(TextViewComponent.Invoke)),
};
var actionContext = CreateActionContext(descriptor);
var viewComponentResult = new ViewComponentResult()
{
- Arguments = new object[] { "World!" },
+ Arguments = new { name = "World!" },
ViewComponentName = "Full.Name.Text",
TempData = _tempDataDictionary,
};
@@ -282,13 +318,14 @@ namespace Microsoft.AspNet.Mvc
FullName = "Full.Name.Text",
ShortName = "Text",
Type = typeof(TextViewComponent),
+ MethodInfo = typeof(TextViewComponent).GetMethod(nameof(TextViewComponent.Invoke)),
};
var actionContext = CreateActionContext(descriptor);
var viewComponentResult = new ViewComponentResult()
{
- Arguments = new object[] { "World!" },
+ Arguments = new { name = "World!" },
ViewComponentType = typeof(TextViewComponent),
TempData = _tempDataDictionary,
};
@@ -310,13 +347,14 @@ namespace Microsoft.AspNet.Mvc
FullName = "Full.Name.Text",
ShortName = "Text",
Type = typeof(TextViewComponent),
+ MethodInfo = typeof(TextViewComponent).GetMethod(nameof(TextViewComponent.Invoke))
};
var actionContext = CreateActionContext(descriptor);
var viewComponentResult = new ViewComponentResult()
{
- Arguments = new object[] { "World!" },
+ Arguments = new { name = "World!" },
ViewComponentType = typeof(TextViewComponent),
StatusCode = 404,
TempData = _tempDataDictionary,
@@ -367,6 +405,7 @@ namespace Microsoft.AspNet.Mvc
FullName = "Full.Name.Text",
ShortName = "Text",
Type = typeof(TextViewComponent),
+ MethodInfo = typeof(TextViewComponent).GetMethod(nameof(TextViewComponent.Invoke)),
};
var actionContext = CreateActionContext(descriptor);
@@ -375,7 +414,7 @@ namespace Microsoft.AspNet.Mvc
var viewComponentResult = new ViewComponentResult()
{
- Arguments = new object[] { "World!" },
+ Arguments = new { name = "World!" },
ViewComponentName = "Text",
ContentType = contentType,
TempData = _tempDataDictionary,
@@ -403,6 +442,7 @@ namespace Microsoft.AspNet.Mvc
FullName = "Full.Name.Text",
ShortName = "Text",
Type = typeof(TextViewComponent),
+ MethodInfo = typeof(TextViewComponent).GetMethod(nameof(TextViewComponent.Invoke)),
};
var actionContext = CreateActionContext(descriptor);
@@ -412,7 +452,7 @@ namespace Microsoft.AspNet.Mvc
var viewComponentResult = new ViewComponentResult()
{
- Arguments = new object[] { "World!" },
+ Arguments = new { name = "World!" },
ViewComponentName = "Text",
ContentType = new MediaTypeHeaderValue("text/html") { Encoding = Encoding.UTF8 },
TempData = _tempDataDictionary,
@@ -439,6 +479,7 @@ namespace Microsoft.AspNet.Mvc
FullName = "Full.Name.Text",
ShortName = "Text",
Type = typeof(TextViewComponent),
+ MethodInfo = typeof(TextViewComponent).GetMethod(nameof(TextViewComponent.Invoke)),
};
var actionContext = CreateActionContext(descriptor);
@@ -447,7 +488,7 @@ namespace Microsoft.AspNet.Mvc
var viewComponentResult = new ViewComponentResult()
{
- Arguments = new object[] { "World!" },
+ Arguments = new { name = "World!" },
ViewComponentName = "Text",
TempData = _tempDataDictionary,
};
@@ -459,7 +500,10 @@ namespace Microsoft.AspNet.Mvc
Assert.Equal(expectedContentType, actionContext.HttpContext.Response.ContentType);
}
- private IServiceCollection CreateServices(object diagnosticListener, HttpContext context, params ViewComponentDescriptor[] descriptors)
+ private IServiceCollection CreateServices(
+ object diagnosticListener,
+ HttpContext context,
+ params ViewComponentDescriptor[] descriptors)
{
var httpContext = new DefaultHttpContext();
var diagnosticSource = new DiagnosticListener("Microsoft.AspNet");
@@ -535,12 +579,6 @@ namespace Microsoft.AspNet.Mvc
private class AsyncTextViewComponent : ViewComponent
{
- public HtmlString Invoke()
- {
- // Should never run.
- throw null;
- }
-
public Task InvokeAsync(string name)
{
return Task.FromResult(new HtmlString("Hello-Async, " + name));
diff --git a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/ContentViewComponentResultTest.cs b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/ContentViewComponentResultTest.cs
index bcad673cf9..e950168fbc 100644
--- a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/ContentViewComponentResultTest.cs
+++ b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/ContentViewComponentResultTest.cs
@@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+using System.Collections.Generic;
using System.IO;
using Microsoft.AspNet.Http.Internal;
using Microsoft.AspNet.Mvc.Abstractions;
@@ -43,7 +44,7 @@ namespace Microsoft.AspNet.Mvc
var viewContext = new ViewContext(
actionContext,
view,
- viewData,
+ viewData,
new TempDataDictionary(httpContext, new SessionStateTempDataProvider()),
TextWriter.Null,
new HtmlHelperOptions());
@@ -57,7 +58,7 @@ namespace Microsoft.AspNet.Mvc
var viewComponentContext = new ViewComponentContext(
viewComponentDescriptor,
- new object[0],
+ new Dictionary(),
new HtmlTestEncoder(),
viewContext,
writer);
diff --git a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/DefaultViewComponentActivatorTests.cs b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/DefaultViewComponentActivatorTests.cs
index 0762717b61..67957a052a 100644
--- a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/DefaultViewComponentActivatorTests.cs
+++ b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/DefaultViewComponentActivatorTests.cs
@@ -2,13 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
-using System.IO;
using System.Threading.Tasks;
-using Microsoft.AspNet.Http.Internal;
-using Microsoft.AspNet.Mvc.ModelBinding;
-using Microsoft.AspNet.Mvc.Rendering;
-using Microsoft.AspNet.Routing;
-using Moq;
using Xunit;
namespace Microsoft.AspNet.Mvc.ViewComponents
diff --git a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/DefaultViewComponentDescriptorProviderTest.cs b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/DefaultViewComponentDescriptorProviderTest.cs
index 8487a967f1..80d9df3c76 100644
--- a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/DefaultViewComponentDescriptorProviderTest.cs
+++ b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/DefaultViewComponentDescriptorProviderTest.cs
@@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
+using System.Threading.Tasks;
using Microsoft.AspNet.Mvc.Infrastructure;
using Xunit;
@@ -23,9 +24,10 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
// Assert
var descriptor = Assert.Single(descriptors);
- Assert.Equal(typeof(ConventionsViewComponent), descriptor.Type);
+ Assert.Same(typeof(ConventionsViewComponent), descriptor.Type);
Assert.Equal("Microsoft.AspNet.Mvc.ViewComponents.Conventions", descriptor.FullName);
Assert.Equal("Conventions", descriptor.ShortName);
+ Assert.Same(typeof(ConventionsViewComponent).GetMethod("Invoke"), descriptor.MethodInfo);
}
[Fact]
@@ -42,15 +44,156 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
Assert.Equal(typeof(AttributeViewComponent), descriptor.Type);
Assert.Equal("AttributesAreGreat", descriptor.FullName);
Assert.Equal("AttributesAreGreat", descriptor.ShortName);
+ Assert.Same(typeof(AttributeViewComponent).GetMethod("InvokeAsync"), descriptor.MethodInfo);
+ }
+
+ [Theory]
+ [InlineData(typeof(NoMethodsViewComponent))]
+ [InlineData(typeof(NonPublicInvokeAsyncViewComponent))]
+ [InlineData(typeof(NonPublicInvokeViewComponent))]
+ public void GetViewComponents_ThrowsIfTypeHasNoInvocationMethods(Type type)
+ {
+ // Arrange
+ var expected = $"Could not find an 'Invoke' or 'InvokeAsync' method for the view component '{type}'.";
+ var provider = CreateProvider(type);
+
+ // Act
+ var ex = Assert.Throws(() => provider.GetViewComponents().ToArray());
+ Assert.Equal(expected, ex.Message);
+ }
+
+ [Theory]
+ [InlineData(typeof(MultipleInvokeViewComponent))]
+ [InlineData(typeof(MultipleInvokeAsyncViewComponent))]
+ [InlineData(typeof(InvokeAndInvokeAsyncViewComponent))]
+ public void GetViewComponents_ThrowsIfTypeHasAmbiguousInvocationMethods(Type type)
+ {
+ // Arrange
+ var expected = $"View component '{type}' must have exactly one public method named " +
+ "'InvokeAsync' or 'Invoke'.";
+ var provider = CreateProvider(type);
+
+ // Act
+ var ex = Assert.Throws(() => provider.GetViewComponents().ToArray());
+ Assert.Equal(expected, ex.Message);
+ }
+
+ [Theory]
+ [InlineData(typeof(NonGenericTaskReturningInvokeAsyncViewComponent))]
+ [InlineData(typeof(VoidReturningInvokeAsyncViewComponent))]
+ [InlineData(typeof(NonTaskReturningInvokeAsyncViewComponent))]
+ public void GetViewComponents_ThrowsIfInvokeAsyncDoesNotHaveCorrectReturnType(Type type)
+ {
+ // Arrange
+ var expected = $"Method 'InvokeAsync' of view component '{type}' should be declared to return Task.";
+ var provider = CreateProvider(type);
+
+ // Act and Assert
+ var ex = Assert.Throws(() => provider.GetViewComponents().ToArray());
+ Assert.Equal(expected, ex.Message);
+ }
+
+ [Fact]
+ public void GetViewComponents_ThrowsIfInvokeReturnsATask()
+ {
+ // Arrange
+ var type = typeof(TaskReturningInvokeViewComponent);
+ var expected = $"Method 'Invoke' of view component '{type}' cannot return a Task.";
+ var provider = CreateProvider(type);
+
+ // Act and Assert
+ var ex = Assert.Throws(() => provider.GetViewComponents().ToArray());
+ Assert.Equal(expected, ex.Message);
+ }
+
+ [Fact]
+ public void GetViewComponents_ThrowsIfInvokeIsVoidReturning()
+ {
+ // Arrange
+ var type = typeof(VoidReturningInvokeViewComponent);
+ var expected = $"Method 'Invoke' of view component '{type}' should be declared to return a value.";
+ var provider = CreateProvider(type);
+
+ // Act and Assert
+ var ex = Assert.Throws(() => provider.GetViewComponents().ToArray());
+ Assert.Equal(expected, ex.Message);
}
private class ConventionsViewComponent
{
+ public string Invoke() => "Hello world";
}
[ViewComponent(Name = "AttributesAreGreat")]
private class AttributeViewComponent
{
+ public Task InvokeAsync() => Task.FromResult("Hello world");
+ }
+
+ private class MultipleInvokeViewComponent
+ {
+ public IViewComponentResult Invoke() => null;
+
+ public IViewComponentResult Invoke(int a) => null;
+ }
+
+ private class NoMethodsViewComponent
+ {
+ }
+
+ private class NonPublicInvokeViewComponent
+ {
+ private IViewComponentResult Invoke() => null;
+ }
+
+ private class NonPublicInvokeAsyncViewComponent
+ {
+ protected Task InvokeAsync() => null;
+ }
+
+ private class MultipleInvokeAsyncViewComponent
+ {
+ public Task InvokeAsync(string a) => null;
+
+ public Task InvokeAsync(int a) => null;
+
+ public Task InvokeAsync(int a, int b) => null;
+ }
+
+ private class InvokeAndInvokeAsyncViewComponent
+ {
+ public Task InvokeAsync(string a) => null;
+
+ public string InvokeAsync(int a) => null;
+ }
+
+ private class NonGenericTaskReturningInvokeAsyncViewComponent
+ {
+ public Task InvokeAsync() => Task.FromResult(0);
+ }
+
+ private class VoidReturningInvokeAsyncViewComponent
+ {
+ public void InvokeAsync()
+ {
+ }
+ }
+
+ public class NonTaskReturningInvokeAsyncViewComponent
+ {
+ public long InvokeAsync() => 0L;
+ }
+
+ public class TaskReturningInvokeViewComponent
+ {
+ public Task Invoke() => Task.FromResult(0);
+ }
+
+ public class VoidReturningInvokeViewComponent
+ {
+ public void Invoke(int x)
+ {
+ }
}
private DefaultViewComponentDescriptorProvider CreateProvider(Type componentType)
@@ -80,11 +223,7 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
return
GetAssemblyProvider()
.CandidateAssemblies
- .SelectMany(a => a.DefinedTypes)
-#if DNX451
- .Select(t => t.GetTypeInfo())
-#endif
- ;
+ .SelectMany(a => a.DefinedTypes);
}
private static IAssemblyProvider GetAssemblyProvider()
diff --git a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/DefaultViewComponentSelectorTest.cs b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/DefaultViewComponentSelectorTest.cs
index 4154a4207e..dc51c3338e 100644
--- a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/DefaultViewComponentSelectorTest.cs
+++ b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/DefaultViewComponentSelectorTest.cs
@@ -12,6 +12,8 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
{
public class DefaultViewComponentSelectorTest
{
+ private static readonly string Namespace = typeof(DefaultViewComponentSelectorTest).Namespace;
+
[Fact]
public void SelectComponent_ByShortNameWithSuffix()
{
@@ -22,7 +24,7 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
var result = selector.SelectComponent("Suffix");
// Assert
- Assert.Equal(typeof(SuffixViewComponent), result.Type);
+ Assert.Same(typeof(ViewComponentContainer.SuffixViewComponent), result.Type);
}
[Fact]
@@ -32,10 +34,10 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
var selector = CreateSelector();
// Act
- var result = selector.SelectComponent("Microsoft.AspNet.Mvc.ViewComponents.Suffix");
+ var result = selector.SelectComponent($"{Namespace}.Suffix");
// Assert
- Assert.Equal(typeof(SuffixViewComponent), result.Type);
+ Assert.Same(typeof(ViewComponentContainer.SuffixViewComponent), result.Type);
}
[Fact]
@@ -48,7 +50,7 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
var result = selector.SelectComponent("WithoutSuffix");
// Assert
- Assert.Equal(typeof(WithoutSuffix), result.Type);
+ Assert.Same(typeof(ViewComponentContainer.WithoutSuffix), result.Type);
}
[Fact]
@@ -58,10 +60,10 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
var selector = CreateSelector();
// Act
- var result = selector.SelectComponent("Microsoft.AspNet.Mvc.ViewComponents.WithoutSuffix");
+ var result = selector.SelectComponent($"{Namespace}.WithoutSuffix");
// Assert
- Assert.Equal(typeof(WithoutSuffix), result.Type);
+ Assert.Same(typeof(ViewComponentContainer.WithoutSuffix), result.Type);
}
[Fact]
@@ -74,7 +76,7 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
var result = selector.SelectComponent("ByAttribute");
// Assert
- Assert.Equal(typeof(ByAttribute), result.Type);
+ Assert.Same(typeof(ViewComponentContainer.ByAttribute), result.Type);
}
[Fact]
@@ -87,7 +89,7 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
var result = selector.SelectComponent("ByNamingConvention");
// Assert
- Assert.Equal(typeof(ByNamingConventionViewComponent), result.Type);
+ Assert.Same(typeof(ViewComponentContainer.ByNamingConventionViewComponent), result.Type);
}
[Fact]
@@ -98,9 +100,9 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
var expected =
"The view component name 'Ambiguous' matched multiple types:" + Environment.NewLine +
- "Type: 'Microsoft.AspNet.Mvc.ViewComponents.DefaultViewComponentSelectorTest+Ambiguous1' - " +
+ $"Type: '{typeof(ViewComponentContainer.Ambiguous1)}' - " +
"Name: 'Namespace1.Ambiguous'" + Environment.NewLine +
- "Type: 'Microsoft.AspNet.Mvc.ViewComponents.DefaultViewComponentSelectorTest+Ambiguous2' - " +
+ $"Type: '{typeof(ViewComponentContainer.Ambiguous2)}' - " +
"Name: 'Namespace2.Ambiguous'";
// Act
@@ -120,7 +122,7 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
var result = selector.SelectComponent("Namespace1.Ambiguous");
// Assert
- Assert.Equal(typeof(Ambiguous1), result.Type);
+ Assert.Same(typeof(ViewComponentContainer.Ambiguous1), result.Type);
}
[Theory]
@@ -135,44 +137,56 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
var result = selector.SelectComponent(name);
// Assert
- Assert.Equal(typeof(FullNameInAttribute), result.Type);
+ Assert.Same(typeof(ViewComponentContainer.FullNameInAttribute), result.Type);
}
private IViewComponentSelector CreateSelector()
{
- return new FilteredViewComponentSelector();
+ var provider = new DefaultViewComponentDescriptorCollectionProvider(
+ new FilteredViewComponentDescriptorProvider());
+ return new DefaultViewComponentSelector(provider);
}
- private class SuffixViewComponent : ViewComponent
+ private class ViewComponentContainer
{
- }
+ public class SuffixViewComponent : ViewComponent
+ {
+ public string Invoke() => "Hello";
+ }
- private class WithoutSuffix : ViewComponent
- {
- }
+ public class WithoutSuffix : ViewComponent
+ {
+ public string Invoke() => "Hello";
+ }
- private class ByNamingConventionViewComponent
- {
- }
+ public class ByNamingConventionViewComponent
+ {
+ public string Invoke() => "Hello";
+ }
- [ViewComponent]
- private class ByAttribute
- {
- }
+ [ViewComponent]
+ public class ByAttribute
+ {
+ public string Invoke() => "Hello";
+ }
- [ViewComponent(Name = "Namespace1.Ambiguous")]
- private class Ambiguous1
- {
- }
+ [ViewComponent(Name = "Namespace1.Ambiguous")]
+ public class Ambiguous1
+ {
+ public string Invoke() => "Hello";
+ }
- [ViewComponent(Name = "Namespace2.Ambiguous")]
- private class Ambiguous2
- {
- }
+ [ViewComponent(Name = "Namespace2.Ambiguous")]
+ public class Ambiguous2
+ {
+ public string Invoke() => "Hello";
+ }
- [ViewComponent(Name = "CoolNameSpace.FullNameInAttribute")]
- private class FullNameInAttribute
- {
+ [ViewComponent(Name = "CoolNameSpace.FullNameInAttribute")]
+ public class FullNameInAttribute
+ {
+ public string Invoke() => "Hello";
+ }
}
// This will only consider types nested inside this class as ViewComponent classes
@@ -181,10 +195,10 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
public FilteredViewComponentDescriptorProvider()
: base(GetAssemblyProvider())
{
- AllowedTypes = typeof(DefaultViewComponentSelectorTest).GetNestedTypes(BindingFlags.NonPublic);
+ AllowedTypes = typeof(ViewComponentContainer).GetNestedTypes(bindingAttr: BindingFlags.Public);
}
- public Type[] AllowedTypes { get; private set; }
+ public Type[] AllowedTypes { get; }
protected override bool IsViewComponentType(TypeInfo typeInfo)
{
@@ -208,19 +222,10 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
{
var assemblyProvider = new StaticAssemblyProvider();
assemblyProvider.CandidateAssemblies.Add(
- typeof(FilteredViewComponentSelector).GetTypeInfo().Assembly);
+ typeof(ViewComponentContainer).GetTypeInfo().Assembly);
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()))
- {
- }
- }
}
}
\ No newline at end of file
diff --git a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/HtmlContentViewComponentResultTest.cs b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/HtmlContentViewComponentResultTest.cs
index 866bf7a075..8772d5993a 100644
--- a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/HtmlContentViewComponentResultTest.cs
+++ b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/HtmlContentViewComponentResultTest.cs
@@ -1,7 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-#if MOCK_SUPPORT
+using System.Collections.Generic;
using System.IO;
using Microsoft.AspNet.Http.Internal;
using Microsoft.AspNet.Mvc.Abstractions;
@@ -57,7 +57,7 @@ namespace Microsoft.AspNet.Mvc
var viewComponentContext = new ViewComponentContext(
viewComponentDescriptor,
- new object[0],
+ new Dictionary(),
new HtmlTestEncoder(),
viewContext,
writer);
@@ -65,5 +65,4 @@ namespace Microsoft.AspNet.Mvc
return viewComponentContext;
}
}
-}
-#endif
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/JsonViewComponentResultTest.cs b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/JsonViewComponentResultTest.cs
index 7b8b90f918..6dc39da368 100644
--- a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/JsonViewComponentResultTest.cs
+++ b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/JsonViewComponentResultTest.cs
@@ -2,6 +2,7 @@
// 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.IO;
using System.Text;
using Microsoft.AspNet.Http;
@@ -85,7 +86,7 @@ namespace Microsoft.AspNet.Mvc
var viewComponentContext = new ViewComponentContext(
viewComponentDescriptor,
- new object[0],
+ new Dictionary(),
new HtmlTestEncoder(),
viewContext,
writer);
diff --git a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/ViewComponentMethodSelectorTest.cs b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/ViewComponentMethodSelectorTest.cs
deleted file mode 100644
index c3344f5826..0000000000
--- a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/ViewComponentMethodSelectorTest.cs
+++ /dev/null
@@ -1,282 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.Reflection;
-using System.Threading.Tasks;
-using Xunit;
-
-namespace Microsoft.AspNet.Mvc.ViewComponents
-{
- public class ViewComponentMethodSelectorTest
- {
- [Theory]
- [InlineData(typeof(ViewComponentWithSyncInvoke), new object[] { "" })]
- [InlineData(typeof(ViewComponentWithAsyncInvoke), new object[] { 42, false })]
- [InlineData(typeof(ViewComponentWithNonPublicNonInstanceInvokes), new object[] { })]
- [InlineData(typeof(ViewComponentWithNonPublicNonInstanceInvokes), new object[] { "" })]
- public void FindAsyncMethod_ReturnsNull_IfMatchCannotBeFound(Type type, object[] args)
- {
- // Arrange
- var typeInfo = type.GetTypeInfo();
-
- // Act
- var method = ViewComponentMethodSelector.FindAsyncMethod(typeInfo, args);
-
- // Assert
- Assert.Null(method);
- }
-
- [Theory]
- [InlineData(typeof(ViewComponentWithAsyncInvoke), new object[0])]
- [InlineData(typeof(ViewComponentWithSyncInvoke), new object[] { "" })]
- [InlineData(typeof(ViewComponentWithAsyncInvoke), new object[] { "" })]
- [InlineData(typeof(ViewComponentWithSyncInvoke), new object[] { 42 })]
- [InlineData(typeof(ViewComponentWithAsyncInvoke), new object[] { "", 42 })]
- [InlineData(typeof(ViewComponentWithNonPublicNonInstanceInvokes), new object[] { })]
- [InlineData(typeof(ViewComponentWithNonPublicNonInstanceInvokes), new object[] { "" })]
- [InlineData(typeof(BaseClass), new object[] { })]
- public void FindSyncMethod_ReturnsNull_IfMatchCannotBeFound(Type type, object[] args)
- {
- // Arrange
- var typeInfo = type.GetTypeInfo();
-
- // Act
- var method = ViewComponentMethodSelector.FindSyncMethod(typeInfo, args);
-
- // Assert
- Assert.Null(method);
- }
-
- [Theory]
- [InlineData(new object[] { new object[] { "Hello" } })]
- [InlineData(new object[] { new object[] { 4 } })]
- [InlineData(new object[] { new object[] { "", 5 } })]
- public void FindAsyncMethod_ThrowsIfInvokeAsyncDoesNotHaveCorrectReturnType(object[] args)
- {
- // Arrange
- var typeInfo = typeof(TypeWithInvalidInvokeAsync).GetTypeInfo();
-
- // Act and Assert
- var ex = Assert.Throws(
- () => ViewComponentMethodSelector.FindAsyncMethod(typeInfo, args));
- Assert.Equal("The async view component method 'InvokeAsync' should be declared to return Task.",
- ex.Message);
- }
-
- [Fact]
- public void FindSyncMethod_ThrowsIfInvokeSyncIsAVoidMethod()
- {
- // Arrange
- var expectedMessage = "The view component method 'Invoke' should be declared to return a value.";
- var typeInfo = typeof(TypeWithInvalidInvokeSync).GetTypeInfo();
-
- // Act and Assert
- var ex = Assert.Throws(
- () => ViewComponentMethodSelector.FindSyncMethod(typeInfo, new object[] { 4 }));
- Assert.Equal(expectedMessage, ex.Message);
- }
-
- [Fact]
- public void FindSyncMethod_ThrowsIfInvokeSyncReturnsTask()
- {
- // Arrange
- var expectedMessage = "The view component method 'Invoke' cannot return a Task.";
- var typeInfo = typeof(TypeWithInvalidInvokeSync).GetTypeInfo();
-
- // Act and Assert
- var ex = Assert.Throws(
- () => ViewComponentMethodSelector.FindSyncMethod(typeInfo, new object[] { "" }));
- Assert.Equal(expectedMessage, ex.Message);
- }
-
- public static TheoryData FindAsyncMethod_ReturnsMethodMatchingParametersData
- {
- get
- {
- var derivedClass = new DerivedClass();
-
- return new TheoryData
- {
- { typeof(ViewComponentWithAsyncInvoke), new object[] { "", }, "1" },
- { typeof(ViewComponentWithAsyncInvoke), new object[] { "", 2 }, "2" },
- { typeof(ViewComponentWithAsyncInvoke), new object[] { "", 0, 1 }, "3" },
- { typeof(ViewComponentWithAsyncInvoke), new object[] { 1, false, 1 }, "4" },
- { typeof(MethodsWithValueConversions), new object[] { 2, (byte)1, (byte)2 }, "2" },
- { typeof(MethodsWithValueConversions), new object[] { derivedClass, derivedClass }, "4" },
- { typeof(MethodsWithValueConversions), new object[] { CultureInfo.InvariantCulture }, "6" },
- };
- }
- }
-
- [Theory]
- [MemberData(nameof(FindAsyncMethod_ReturnsMethodMatchingParametersData))]
- public void FindAsyncMethod_ReturnsMethodMatchingParameters(Type type, object[] args, string expectedId)
- {
- // Arrange
- var typeInfo = type.GetTypeInfo();
-
- // Act
- var method = ViewComponentMethodSelector.FindAsyncMethod(typeInfo, args);
-
- // Assert
- Assert.NotNull(method);
- var data = method.GetCustomAttribute();
- Assert.Equal(expectedId, data.Data);
- }
-
- public static TheoryData FindSyncMethod_ReturnsMethodMatchingParametersData
- {
- get
- {
- var derivedClass = new DerivedAgain();
-
- return new TheoryData
- {
- { typeof(ViewComponentWithSyncInvoke), new object[] { }, "1" },
- { typeof(ViewComponentWithSyncInvoke), new object[] { 2, 3 }, "2" },
- { typeof(ViewComponentWithSyncInvoke), new object[] { "", 0, true }, "3" },
- { typeof(MethodsWithValueConversions), new object[] { 1, (byte)2, 3.0f }, "1" },
- { typeof(MethodsWithValueConversions), new object[] { derivedClass, derivedClass }, "3" },
- { typeof(MethodsWithValueConversions), new object[] { "Hello world" }, "5" },
- { typeof(DerivedClass), new object[] { }, "Derived1" },
-#if !DNXCORE50
- { typeof(DerivedAgain), new object[] { "" }, "Derived2" },
-#endif
- };
- }
- }
-
- [Theory]
- [MemberData(nameof(FindSyncMethod_ReturnsMethodMatchingParametersData))]
- public void FindSyncMethod_ReturnsMethodMatchingParameters(Type type, object[] args, string expectedId)
- {
- // Arrange
- var typeInfo = type.GetTypeInfo();
-
- // Act
- var method = ViewComponentMethodSelector.FindSyncMethod(typeInfo, args);
-
- // Assert
- Assert.NotNull(method);
- var data = method.GetCustomAttribute();
- Assert.Equal(expectedId, data.Data);
- }
-
- private class ViewComponentWithSyncInvoke
- {
- [MethodData("1")]
- public int Invoke() => 3;
-
- [MethodData("2")]
- public int Invoke(int a, int? b) => a + b.Value;
-
- [MethodData("3")]
- public int Invoke(string a, int b, bool? c) => 3;
- }
-
- private class ViewComponentWithAsyncInvoke
- {
- [MethodData("1")]
- public Task InvokeAsync(string value) => Task.FromResult(value.ToUpperInvariant());
-
- [MethodData("2")]
- public Task InvokeAsync(string a, int b) => Task.FromResult(a + b);
-
- [MethodData("3")]
- public Task InvokeAsync(string a, int? b, int c) => Task.FromResult(a + b + c);
-
- [MethodData("4")]
- public Task InvokeAsync(int? a, bool? b, int c) => Task.FromResult(a.ToString() + b + c);
-
- [MethodData("5")]
- public Task InvokeAsync(object value) => Task.FromResult(value.ToString());
- }
-
- public class MethodsWithValueConversions
- {
- [MethodData("1")]
- public int Invoke(long a, char b, double c) => 1;
-
- [MethodData("2")]
- public Task InvokeAsync(float a, float b, byte c) => Task.FromResult(1);
-
- [MethodData("3")]
- public int Invoke(BaseClass a, DerivedClass b) => 1;
-
- [MethodData("4")]
- public Task InvokeAsync(BaseClass a, DerivedClass b) => Task.FromResult(1);
-
- [MethodData("5")]
- public int Invoke(IEnumerable value) => 1;
-
- [MethodData("6")]
- public Task InvokeAsync(IFormatProvider formatProvider) => Task.FromResult(1);
- }
-
- private class ViewComponentWithNonPublicNonInstanceInvokes
- {
- public static int Invoke() => 1;
-
- private int Invoke(string a) => 2;
-
- public static Task InvokeAsync() => Task.FromResult(3);
-
- protected Task InvokeAsync(string a) => Task.FromResult(a);
- }
-
- public class BaseClass
- {
- [MethodData("Base")]
- public static int Invoke() => 1;
- }
-
- public class DerivedClass : BaseClass
- {
- [MethodData("Derived1")]
- public new int Invoke() => 1;
-
- [MethodData("Derived2")]
- public int Invoke(string x) => 2;
- }
-
- public class DerivedAgain : DerivedClass
- {
- [MethodData("DerivedAgain")]
- public new static int Invoke(string x) => 2;
- }
-
- private class TypeWithInvalidInvokeAsync
- {
- public Task InvokeAsync(string value) => Task.FromResult(value);
-
- public void InvokeAsync(int value)
- {
-
- }
-
- public long InvokeAsync(string a, int b) => b;
- }
-
- private class TypeWithInvalidInvokeSync
- {
- public Task Invoke(string value) => Task.FromResult(value);
-
- public void Invoke(int value)
- {
- }
- }
-
- private class MethodDataAttribute : Attribute
- {
- public MethodDataAttribute(string data)
- {
- Data = data;
- }
-
- public string Data { get; }
- }
- }
-}
diff --git a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/ViewViewComponentResultTest.cs b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/ViewViewComponentResultTest.cs
index 67b67e17d1..2af1d3c1a2 100644
--- a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/ViewViewComponentResultTest.cs
+++ b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/ViewViewComponentResultTest.cs
@@ -2,9 +2,11 @@
// 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.Diagnostics;
using System.IO;
using System.Linq;
+using System.Reflection;
using System.Threading.Tasks;
using Microsoft.AspNet.Http.Internal;
using Microsoft.AspNet.Mvc.Abstractions;
@@ -147,9 +149,9 @@ namespace Microsoft.AspNet.Mvc
{
// Arrange
var expected = string.Join(Environment.NewLine,
- "The view 'Components/Invoke/some-view' was not found. The following locations were searched:",
- "location1",
- "location2");
+ "The view 'Components/Invoke/some-view' was not found. The following locations were searched:",
+ "location1",
+ "location2");
var view = Mock.Of();
@@ -185,9 +187,9 @@ namespace Microsoft.AspNet.Mvc
{
// Arrange
var expected = string.Join(Environment.NewLine,
- "The view 'Components/Invoke/some-view' was not found. The following locations were searched:",
- "location1",
- "location2");
+ "The view 'Components/Invoke/some-view' was not found. The following locations were searched:",
+ "location1",
+ "location2");
var view = Mock.Of();
@@ -223,11 +225,11 @@ namespace Microsoft.AspNet.Mvc
{
// Arrange
var expected = string.Join(Environment.NewLine,
- "The view 'Components/Invoke/some-view' was not found. The following locations were searched:",
- "location1",
- "location2",
- "location3",
- "location4");
+ "The view 'Components/Invoke/some-view' was not found. The following locations were searched:",
+ "location1",
+ "location2",
+ "location3",
+ "location4");
var view = Mock.Of();
@@ -535,11 +537,12 @@ namespace Microsoft.AspNet.Mvc
{
ShortName = "Invoke",
Type = typeof(object),
+ MethodInfo = typeof(object).GetTypeInfo().DeclaredMethods.First()
};
var viewComponentContext = new ViewComponentContext(
viewComponentDescriptor,
- new object[0],
+ new Dictionary(),
new HtmlTestEncoder(),
viewContext,
TextWriter.Null);
diff --git a/test/WebSites/BasicWebSite/Views/Home/JsonTextInView.cshtml b/test/WebSites/BasicWebSite/Views/Home/JsonTextInView.cshtml
index cc60ee4e84..1424208b13 100644
--- a/test/WebSites/BasicWebSite/Views/Home/JsonTextInView.cshtml
+++ b/test/WebSites/BasicWebSite/Views/Home/JsonTextInView.cshtml
@@ -1 +1 @@
-@Component.Invoke("JsonTextInView")
\ No newline at end of file
+@await Component.InvokeAsync("JsonTextInView")
\ No newline at end of file
diff --git a/test/WebSites/BasicWebSite/Views/RequestScopedService/ViewComponent.cshtml b/test/WebSites/BasicWebSite/Views/RequestScopedService/ViewComponent.cshtml
index 1fed10c20f..4ee213cd41 100644
--- a/test/WebSites/BasicWebSite/Views/RequestScopedService/ViewComponent.cshtml
+++ b/test/WebSites/BasicWebSite/Views/RequestScopedService/ViewComponent.cshtml
@@ -1 +1 @@
-@Component.Invoke("RequestId")
\ No newline at end of file
+@await Component.InvokeAsync("RequestId")
\ No newline at end of file
diff --git a/test/WebSites/RazorWebSite/Views/InheritingInherits/Index.cshtml b/test/WebSites/RazorWebSite/Views/InheritingInherits/Index.cshtml
index d60de5c219..333e22352a 100644
--- a/test/WebSites/RazorWebSite/Views/InheritingInherits/Index.cshtml
+++ b/test/WebSites/RazorWebSite/Views/InheritingInherits/Index.cshtml
@@ -1,3 +1,3 @@
@model Person
@Model.Name
-@Component.Invoke("InheritingViewComponent", Model.Address)
\ No newline at end of file
+@await Component.InvokeAsync("InheritingViewComponent", new { address = Model.Address })
\ No newline at end of file
diff --git a/test/WebSites/RazorWebSite/Views/ViewEngine/ViewWithRelativePath.cshtml b/test/WebSites/RazorWebSite/Views/ViewEngine/ViewWithRelativePath.cshtml
index f138e7d744..6390921e2e 100644
--- a/test/WebSites/RazorWebSite/Views/ViewEngine/ViewWithRelativePath.cshtml
+++ b/test/WebSites/RazorWebSite/Views/ViewEngine/ViewWithRelativePath.cshtml
@@ -12,4 +12,4 @@
}
ViewWithRelativePath-content
@await Html.PartialAsync("../Shared/_PartialThatSetsTitle.cshtml")
-@await Component.InvokeAsync("ComponentWithRelativePath", person)
\ No newline at end of file
+@await Component.InvokeAsync("ComponentWithRelativePath", new { person })
\ No newline at end of file
diff --git a/test/WebSites/RazorWebSite/Views/ViewEngine/ViewWithTitle.cshtml b/test/WebSites/RazorWebSite/Views/ViewEngine/ViewWithTitle.cshtml
index d6e997ffd9..d90e24a409 100644
--- a/test/WebSites/RazorWebSite/Views/ViewEngine/ViewWithTitle.cshtml
+++ b/test/WebSites/RazorWebSite/Views/ViewEngine/ViewWithTitle.cshtml
@@ -2,6 +2,6 @@
ViewData["Title"] = "Page title";
// The invoked partial sets a title, but this shouldn't override the current page's ViewData \ ViewBag.
await Html.RenderPartialAsync("_PartialThatSetsTitle");
- await Component.RenderInvokeAsync("ComponentThatSetsTitle");
+ @await Component.InvokeAsync("ComponentThatSetsTitle")
Layout = "/Views/Shared/_LayoutWithTitle.cshtml";
}
\ No newline at end of file
diff --git a/test/WebSites/RazorWebSite/Views/ViewWithPaths/Index.cshtml b/test/WebSites/RazorWebSite/Views/ViewWithPaths/Index.cshtml
index 7262ab1db0..46f7e96b35 100644
--- a/test/WebSites/RazorWebSite/Views/ViewWithPaths/Index.cshtml
+++ b/test/WebSites/RazorWebSite/Views/ViewWithPaths/Index.cshtml
@@ -1,6 +1,6 @@
@ViewContext.ExecutingFilePath
@ViewContext.View.Path
- @Component.Invoke("ComponentForViewWithPaths")
+ @await Component.InvokeAsync("ComponentForViewWithPaths")
@Html.Partial("_Partial")
\ No newline at end of file
diff --git a/test/WebSites/TagHelpersWebSite/TagHelpers/TagCloudViewComponentTagHelper.cs b/test/WebSites/TagHelpersWebSite/TagHelpers/TagCloudViewComponentTagHelper.cs
index 792b4efe26..1d43dd4910 100644
--- a/test/WebSites/TagHelpersWebSite/TagHelpers/TagCloudViewComponentTagHelper.cs
+++ b/test/WebSites/TagHelpersWebSite/TagHelpers/TagCloudViewComponentTagHelper.cs
@@ -2,6 +2,7 @@
// 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.IO;
using System.Linq;
using System.Text.Encodings.Web;
@@ -58,7 +59,7 @@ namespace MvcSample.Web.Components
await result.ExecuteAsync(new ViewComponentContext(
viewComponentDescriptor,
- new object[0],
+ new Dictionary(),
_htmlEncoder,
ViewContext,
writer));
diff --git a/test/WebSites/TagHelpersWebSite/Views/Home/Index.cshtml b/test/WebSites/TagHelpersWebSite/Views/Home/Index.cshtml
index fa73aed1ec..f8edfad6d8 100644
--- a/test/WebSites/TagHelpersWebSite/Views/Home/Index.cshtml
+++ b/test/WebSites/TagHelpersWebSite/Views/Home/Index.cshtml
@@ -35,7 +35,7 @@
Current Tag Cloud from Tag Helper
Current Tag Cloud from ViewComponentHelper:
- @await Component.InvokeAsync("Tags", 15)
+ @await Component.InvokeAsync("Tags", new { count = 15 })
@{
RenderTemplate(
"Tag Cloud from Template: ",