Suppose you want to introduce an inheritance chain in ASP.Net Core to use some businesslogic in a baseclass :
namespace Foo.Core.Web
{
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
public class CoolBaseViewComponentDetail : ViewComponent
{
protected List<string> getItems(int itemCount)
{
List<string> items = new List<string>();
for (int i = 0; i < itemCount; i++)
{
items.Add(string.Format("string {0}", i));
}
return (items);
}
}
public class SpecializedViewComponentDetail : CoolBaseViewComponentDetail
{
public virtual IViewComponentResult Invoke(int numberOfItems)
{
List<string> items = getItems(numberOfItems);
return (View(viewName: "~/Src/ViewComponentSpecialized.Detail.cshtml", model: items));
}
}
}
ViewComponentSpecialized.Detail renders like this :
@model System.Collections.Generic.List<string>
<ul>
@foreach( string item in Model)
{
<li>@item</li>
}
</ul>
If you invoke this viewcomponent you get an exception :
@await Component.InvokeAsync( name:"SpecializedViewComponentDetail", arguments:new { numberOfItems = 3 } )
InvalidOperationException: Could not find an 'Invoke' or 'InvokeAsync' method for the view component 'Foo.Core.Web.CoolBaseViewComponentDetail'.
ASP.Net core requires an ‘Invoke’-method on every ViewComponent-specialized class, even if it is not directly called. Solution is to introduce this method but to let it throw an exception when directly called:
namespace Foo.Core.Web
{
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
public class CoolBaseViewComponentDetail : ViewComponent
{
public virtual IViewComponentResult Invoke(int numberOfItems)
{
throw new System.NotSupportedException("Specialized classes should implement this");
}
protected List<string> getItems(int itemCount)
{
List<string> items = new List<string>();
for (int i = 0; i < itemCount; i++)
{
items.Add(string.Format("string {0}", i));
}
return (items);
}
}
public class SpecializedViewComponentDetail : CoolBaseViewComponentDetail
{
public virtual IViewComponentResult Invoke(int numberOfItems)
{
List<string> items = getItems(numberOfItems);
return (View(viewName: "~/Src/ViewComponentSpecialized.Detail.cshtml", model: items));
}
}
}
Now the view renders:
o string 0 o string 1 o string 2
cheers, Stephan