diff --git a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Properties/Resources.Designer.cs
index 19c9606e96..976283c6c0 100644
--- a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Properties/Resources.Designer.cs
+++ b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Properties/Resources.Designer.cs
@@ -67,7 +67,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
=> string.Format(CultureInfo.CurrentCulture, GetString("ViewComponent_SyncMethod_ShouldReturnValue"), p0, p1);
///
- /// A view component named '{0}' could not be found.
+ /// A view component named '{0}' could not be found. A view component must be a public non-abstract class, not contain any generic parameters, and either be decorated with '{1}' or have a class name ending with the '{2}' suffix. A view component must not be decorated with '{3}'.
///
internal static string ViewComponent_CannotFindComponent
{
@@ -75,10 +75,10 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
}
///
- /// A view component named '{0}' could not be found.
+ /// A view component named '{0}' could not be found. A view component must be a public non-abstract class, not contain any generic parameters, and either be decorated with '{1}' or have a class name ending with the '{2}' suffix. A view component must not be decorated with '{3}'.
///
- internal static string FormatViewComponent_CannotFindComponent(object p0)
- => string.Format(CultureInfo.CurrentCulture, GetString("ViewComponent_CannotFindComponent"), p0);
+ internal static string FormatViewComponent_CannotFindComponent(object p0, object p1, object p2, object p3)
+ => string.Format(CultureInfo.CurrentCulture, GetString("ViewComponent_CannotFindComponent"), p0, p1, p2, p3);
///
/// An invoker could not be created for the view component '{0}'.
diff --git a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Resources.resx b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Resources.resx
index 87c26e3d07..baa6c7a29b 100644
--- a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Resources.resx
+++ b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Resources.resx
@@ -131,7 +131,7 @@
Method '{0}' of view component '{1}' should be declared to return a value.
- A view component named '{0}' could not be found.
+ A view component named '{0}' could not be found. A view component must be a public non-abstract class, not contain any generic parameters, and either be decorated with '{1}' or have a class name ending with the '{2}' suffix. A view component must not be decorated with '{3}'.
An invoker could not be created for the view component '{0}'.
diff --git a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/ViewComponents/DefaultViewComponentHelper.cs b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/ViewComponents/DefaultViewComponentHelper.cs
index 19221c2916..e55e5443a4 100644
--- a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/ViewComponents/DefaultViewComponentHelper.cs
+++ b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/ViewComponents/DefaultViewComponentHelper.cs
@@ -98,7 +98,11 @@ namespace Microsoft.AspNetCore.Mvc.ViewComponents
var descriptor = _selector.SelectComponent(name);
if (descriptor == null)
{
- throw new InvalidOperationException(Resources.FormatViewComponent_CannotFindComponent(name));
+ throw new InvalidOperationException(Resources.FormatViewComponent_CannotFindComponent(
+ name,
+ nameof(ViewComponentAttribute),
+ ViewComponentConventions.ViewComponentSuffix,
+ nameof(NonViewComponentAttribute)));
}
return InvokeCoreAsync(descriptor, arguments);
@@ -129,7 +133,10 @@ namespace Microsoft.AspNetCore.Mvc.ViewComponents
}
throw new InvalidOperationException(Resources.FormatViewComponent_CannotFindComponent(
- componentType.FullName));
+ componentType.FullName,
+ nameof(ViewComponentAttribute),
+ ViewComponentConventions.ViewComponentSuffix,
+ nameof(NonViewComponentAttribute)));
}
// Internal for testing
diff --git a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/ViewComponents/ViewComponentConventions.cs b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/ViewComponents/ViewComponentConventions.cs
index d8e4ce1a61..8ad8797556 100644
--- a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/ViewComponents/ViewComponentConventions.cs
+++ b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/ViewComponents/ViewComponentConventions.cs
@@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewComponents
{
public static class ViewComponentConventions
{
- private const string ViewComponentSuffix = "ViewComponent";
+ public static readonly string ViewComponentSuffix = "ViewComponent";
public static string GetComponentName(TypeInfo componentType)
{
diff --git a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/ViewComponentResultTest.cs b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/ViewComponentResultTest.cs
index cf17cfc2ee..f7da43fc3b 100644
--- a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/ViewComponentResultTest.cs
+++ b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/ViewComponentResultTest.cs
@@ -105,7 +105,10 @@ namespace Microsoft.AspNetCore.Mvc
public async Task ExecuteResultAsync_Throws_IfViewComponentCouldNotBeFound_ByName()
{
// Arrange
- var expected = "A view component named 'Text' could not be found.";
+ var expected = "A view component named 'Text' could not be found. A view component must be " +
+ "a public non-abstract class, not contain any generic parameters, and either be decorated " +
+ "with 'ViewComponentAttribute' or have a class name ending with the 'ViewComponent' suffix. " +
+ "A view component must not be decorated with 'NonViewComponentAttribute'.";
var actionContext = CreateActionContext();
@@ -125,7 +128,10 @@ namespace Microsoft.AspNetCore.Mvc
public async Task ExecuteResultAsync_Throws_IfViewComponentCouldNotBeFound_ByType()
{
// Arrange
- var expected = $"A view component named '{typeof(TextViewComponent).FullName}' could not be found.";
+ var expected = $"A view component named '{typeof(TextViewComponent).FullName}' could not be found. " +
+ "A view component must be a public non-abstract class, not contain any generic parameters, and either be decorated " +
+ "with 'ViewComponentAttribute' or have a class name ending with the 'ViewComponent' suffix. " +
+ "A view component must not be decorated with 'NonViewComponentAttribute'.";
var actionContext = CreateActionContext();
var services = CreateServices(diagnosticListener: null, context: actionContext.HttpContext);