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