在继承的 ViewComponent .net core 5.0 中覆盖 Invoke 方法
Override Invoke method in an inherited ViewComponent .net core 5.0
我正在从 ASP.NET MVC 迁移到 ASP.NET 核心 MVC。
我有一个 BasePodsWidgetController
看起来像这样:
public abstract class BasePodsWidgetController<TProperties, TConfiguration, TItem> : WidgetController<TProperties>
where TProperties : BaseWidgetProperties, new()
where TConfiguration : TreeNode, IItemsListingWidgetConfiguration, new()
where TItem : TreeNode, new()
{
protected readonly IComponentPropertiesRetriever _componentPropertiesRetriever;
protected IContentRepository<TConfiguration> _contentRepository;
protected IContentRepository<PodContainer> _parentRepository;
protected IContentRepository<TItem> _childrenRepository;
protected abstract string ViewPath { get; }
protected virtual int Limit { get; set; } = 5;
public BasePodsWidgetController(IContentRepository<TConfiguration> contentRepository, IContentRepository<PodContainer> parentRepository, IContentRepository<TItem> childrenRepository,
IComponentPropertiesRetriever componentPropertiesRetriever)
{
_contentRepository = contentRepository;
_parentRepository = parentRepository;
_childrenRepository = childrenRepository;
_componentPropertiesRetriever = componentPropertiesRetriever;
}
public virtual PartialViewResult Index()
{
var properties = _componentPropertiesRetriever.Retrieve<TProperties>();
ViewBag.MarginClass = WidgetStylingHelper.GetMarginClassFromWidgetProperties(properties.Margin);
var widgetGuid = properties.WidgetConfiguration?.FirstOrDefault()?.NodeGuid;
var widgetGuidValue = widgetGuid.HasValue ? widgetGuid.Value : Guid.Empty;
var model = new PodsListing<TConfiguration, TItem>
{
Configuration = _contentRepository.GetByNodeGuid(widgetGuidValue),
Items = new TItem[0]
};
if (null != model.Configuration)
{
var parent = _parentRepository.GetByNodeGuid(model.Configuration.ItemsParentNodeGUID);
if (null != parent)
{
model.Items = _childrenRepository.GetChildrenByPath(parent.NodeAliasPath, Limit).ToArray();
}
}
return PartialView(ViewPath, model);
}
}
然后允许我像这样继承和覆盖:
public class FeaturePodsWidgetController : BasePodsWidgetController<FeaturePodsWidgetProperties, FeaturePodsWidget, FeaturePod>
{
protected override string ViewPath => "Widgets/_FeaturePods";
public FeaturePodsWidgetController(IContentRepository<FeaturePodsWidget> contentRepository, IContentRepository<PodContainer> parentRepository, IContentRepository<FeaturePod> childrenRepository, IComponentPropertiesRetriever componentPropertiesRetriever)
: base(contentRepository, parentRepository, childrenRepository, componentPropertiesRetriever)
{
}
public override PartialViewResult Index()
{
var properties = _componentPropertiesRetriever.Retrieve<FeaturePodsWidgetProperties>();
var widgetGuid = properties.WidgetConfiguration?.FirstOrDefault()?.NodeGuid;
var widgetGuidValue = widgetGuid.HasValue ? widgetGuid.Value : Guid.Empty;
ViewBag.MarginClass = WidgetStylingHelper.GetMarginClassFromWidgetProperties(properties.Margin);
var model = new PodsListing<FeaturePodsWidget, FeaturePod>
{
Configuration = _contentRepository.GetByNodeGuid(widgetGuidValue),
Items = new FeaturePod[0]
};
if (null != model.Configuration)
{
var parent = _parentRepository.GetByNodeGuid(model.Configuration.ItemsParentNodeGUID);
if (null != parent)
{
model.Items = _childrenRepository.GetChildrenByPath(parent.NodeAliasPath, 4).ToArray();
}
}
return PartialView(ViewPath, model);
}
}
但在 ASP.NET Core 中转换为 ViewComponents 时,我收到一条错误消息,指出只允许使用一种调用方法,但无法弄清楚原因
BasePodsWidgetViewComponent
[ViewComponent()]
public abstract class BasePodsWidgetViewComponent<TProperties, TConfiguration, TItem> : ViewComponent
where TProperties : BaseWidgetProperties, new()
where TConfiguration : TreeNode, IItemsListingWidgetConfiguration, new()
where TItem : TreeNode, new()
{
protected readonly IComponentPropertiesRetriever _componentPropertiesRetriever;
protected IContentRepository<TConfiguration> _contentRepository;
protected IContentRepository<PodContainer> _parentRepository;
protected IContentRepository<TItem> _childrenRepository;
protected abstract string ViewPath { get; }
protected virtual int Limit { get; set; } = 5;
public BasePodsWidgetViewComponent(IContentRepository<TConfiguration> contentRepository, IContentRepository<PodContainer> parentRepository, IContentRepository<TItem> childrenRepository,
IComponentPropertiesRetriever componentPropertiesRetriever)
{
_contentRepository = contentRepository;
_parentRepository = parentRepository;
_childrenRepository = childrenRepository;
_componentPropertiesRetriever = componentPropertiesRetriever;
}
public virtual IViewComponentResult Invoke()
{
var properties = _componentPropertiesRetriever.Retrieve<TProperties>();
ViewBag.MarginClass = WidgetStylingHelper.GetMarginClassFromWidgetProperties(properties.Margin);
var widgetGuid = properties.WidgetConfiguration?.FirstOrDefault()?.NodeGuid;
var widgetGuidValue = widgetGuid.HasValue ? widgetGuid.Value : Guid.Empty;
var model = new PodsListing<TConfiguration, TItem>
{
Configuration = _contentRepository.GetByNodeGuid(widgetGuidValue),
Items = new TItem[0]
};
if (null != model.Configuration)
{
var parent = _parentRepository.GetByNodeGuid(model.Configuration.ItemsParentNodeGUID);
if (null != parent)
{
model.Items = _childrenRepository.GetChildrenByPath(parent.NodeAliasPath, Limit).ToArray();
}
}
return View(ViewPath, model);
}
}
已转换的 FeaturePodsWidgetViewComponent
public class FeaturePodsWidgetViewComponent : BasePodsWidgetViewComponent<FeaturePodsWidgetProperties, FeaturePodsWidget, FeaturePod>
{
public const string IDENTIFIER = "FeaturePodsWidget";
protected override string ViewPath => "_FeaturePodsWidget";
public FeaturePodsWidgetViewComponent(IContentRepository<FeaturePodsWidget> contentRepository, IContentRepository<PodContainer> parentRepository, IContentRepository<FeaturePod> childrenRepository, IComponentPropertiesRetriever componentPropertiesRetriever)
: base(contentRepository, parentRepository, childrenRepository, componentPropertiesRetriever)
{
}
public override IViewComponentResult Invoke()
{
var properties = _componentPropertiesRetriever.Retrieve<FeaturePodsWidgetProperties>();
var widgetGuid = properties.WidgetConfiguration?.FirstOrDefault()?.NodeGuid;
var widgetGuidValue = widgetGuid.HasValue ? widgetGuid.Value : Guid.Empty;
ViewBag.MarginClass = WidgetStylingHelper.GetMarginClassFromWidgetProperties(properties.Margin);
var model = new PodsListing<FeaturePodsWidget, FeaturePod>
{
Configuration = _contentRepository.GetByNodeGuid(widgetGuidValue),
Items = new FeaturePod[0]
};
if (null != model.Configuration)
{
var parent = _parentRepository.GetByNodeGuid(model.Configuration.ItemsParentNodeGUID);
if (null != parent)
{
model.Items = _childrenRepository.GetChildrenByPath(parent.NodeAliasPath, 4).ToArray();
}
}
return View(ViewPath, model);
}
}
我收到这个错误:
View component 'I3.Base.Web.ViewComponents.Widgets.FeaturePodsWidgetViewComponent' must have exactly one public method named 'Invoke' or 'InvokeAsync'
我不明白为什么:(
.NET 5 文档指出 Like controllers, view components must be public, non-nested, and non-abstract classes.
所以我认为您不能直接覆盖 Invoke 方法。
我刚刚在 Dancing Goat 示例网站上尝试了一个基本示例,如果您在抽象 ViewComponent 上使用单独的虚拟方法,您可以直接在 Invoke 方法中调用它:
namespace DancingGoat.Components.ViewComponents
{
public abstract class BasePodsWidgetViewComponent : ViewComponent
{
protected readonly IComponentPropertiesRetriever _componentPropertiesRetriever;
public BasePodsWidgetViewComponent(IComponentPropertiesRetriever componentPropertiesRetriever)
{
_componentPropertiesRetriever = componentPropertiesRetriever;
}
public virtual IViewComponentResult Example()
{
// default logic
return View("~/Components/ViewComponents/CompanyAddress/TEST.cshtml");
}
public IViewComponentResult Invoke()
{
return Example();
}
}
}
然后在您的 FeaturePodsWidgetViewComponent
上您可以覆盖虚拟方法:
namespace DancingGoat.Components.ViewComponents
{
public class FeaturePodsWidgetViewComponent : BasePodsWidgetViewComponent
{
public FeaturePodsWidgetViewComponent(IComponentPropertiesRetriever componentPropertiesRetriever) : base(componentPropertiesRetriever)
{
}
public override IViewComponentResult Example()
{
// custom logic
return View("~/Components/ViewComponents/CompanyAddress/TEST2.cshtml");
}
}
}
我正在从 ASP.NET MVC 迁移到 ASP.NET 核心 MVC。
我有一个 BasePodsWidgetController
看起来像这样:
public abstract class BasePodsWidgetController<TProperties, TConfiguration, TItem> : WidgetController<TProperties>
where TProperties : BaseWidgetProperties, new()
where TConfiguration : TreeNode, IItemsListingWidgetConfiguration, new()
where TItem : TreeNode, new()
{
protected readonly IComponentPropertiesRetriever _componentPropertiesRetriever;
protected IContentRepository<TConfiguration> _contentRepository;
protected IContentRepository<PodContainer> _parentRepository;
protected IContentRepository<TItem> _childrenRepository;
protected abstract string ViewPath { get; }
protected virtual int Limit { get; set; } = 5;
public BasePodsWidgetController(IContentRepository<TConfiguration> contentRepository, IContentRepository<PodContainer> parentRepository, IContentRepository<TItem> childrenRepository,
IComponentPropertiesRetriever componentPropertiesRetriever)
{
_contentRepository = contentRepository;
_parentRepository = parentRepository;
_childrenRepository = childrenRepository;
_componentPropertiesRetriever = componentPropertiesRetriever;
}
public virtual PartialViewResult Index()
{
var properties = _componentPropertiesRetriever.Retrieve<TProperties>();
ViewBag.MarginClass = WidgetStylingHelper.GetMarginClassFromWidgetProperties(properties.Margin);
var widgetGuid = properties.WidgetConfiguration?.FirstOrDefault()?.NodeGuid;
var widgetGuidValue = widgetGuid.HasValue ? widgetGuid.Value : Guid.Empty;
var model = new PodsListing<TConfiguration, TItem>
{
Configuration = _contentRepository.GetByNodeGuid(widgetGuidValue),
Items = new TItem[0]
};
if (null != model.Configuration)
{
var parent = _parentRepository.GetByNodeGuid(model.Configuration.ItemsParentNodeGUID);
if (null != parent)
{
model.Items = _childrenRepository.GetChildrenByPath(parent.NodeAliasPath, Limit).ToArray();
}
}
return PartialView(ViewPath, model);
}
}
然后允许我像这样继承和覆盖:
public class FeaturePodsWidgetController : BasePodsWidgetController<FeaturePodsWidgetProperties, FeaturePodsWidget, FeaturePod>
{
protected override string ViewPath => "Widgets/_FeaturePods";
public FeaturePodsWidgetController(IContentRepository<FeaturePodsWidget> contentRepository, IContentRepository<PodContainer> parentRepository, IContentRepository<FeaturePod> childrenRepository, IComponentPropertiesRetriever componentPropertiesRetriever)
: base(contentRepository, parentRepository, childrenRepository, componentPropertiesRetriever)
{
}
public override PartialViewResult Index()
{
var properties = _componentPropertiesRetriever.Retrieve<FeaturePodsWidgetProperties>();
var widgetGuid = properties.WidgetConfiguration?.FirstOrDefault()?.NodeGuid;
var widgetGuidValue = widgetGuid.HasValue ? widgetGuid.Value : Guid.Empty;
ViewBag.MarginClass = WidgetStylingHelper.GetMarginClassFromWidgetProperties(properties.Margin);
var model = new PodsListing<FeaturePodsWidget, FeaturePod>
{
Configuration = _contentRepository.GetByNodeGuid(widgetGuidValue),
Items = new FeaturePod[0]
};
if (null != model.Configuration)
{
var parent = _parentRepository.GetByNodeGuid(model.Configuration.ItemsParentNodeGUID);
if (null != parent)
{
model.Items = _childrenRepository.GetChildrenByPath(parent.NodeAliasPath, 4).ToArray();
}
}
return PartialView(ViewPath, model);
}
}
但在 ASP.NET Core 中转换为 ViewComponents 时,我收到一条错误消息,指出只允许使用一种调用方法,但无法弄清楚原因
BasePodsWidgetViewComponent
[ViewComponent()]
public abstract class BasePodsWidgetViewComponent<TProperties, TConfiguration, TItem> : ViewComponent
where TProperties : BaseWidgetProperties, new()
where TConfiguration : TreeNode, IItemsListingWidgetConfiguration, new()
where TItem : TreeNode, new()
{
protected readonly IComponentPropertiesRetriever _componentPropertiesRetriever;
protected IContentRepository<TConfiguration> _contentRepository;
protected IContentRepository<PodContainer> _parentRepository;
protected IContentRepository<TItem> _childrenRepository;
protected abstract string ViewPath { get; }
protected virtual int Limit { get; set; } = 5;
public BasePodsWidgetViewComponent(IContentRepository<TConfiguration> contentRepository, IContentRepository<PodContainer> parentRepository, IContentRepository<TItem> childrenRepository,
IComponentPropertiesRetriever componentPropertiesRetriever)
{
_contentRepository = contentRepository;
_parentRepository = parentRepository;
_childrenRepository = childrenRepository;
_componentPropertiesRetriever = componentPropertiesRetriever;
}
public virtual IViewComponentResult Invoke()
{
var properties = _componentPropertiesRetriever.Retrieve<TProperties>();
ViewBag.MarginClass = WidgetStylingHelper.GetMarginClassFromWidgetProperties(properties.Margin);
var widgetGuid = properties.WidgetConfiguration?.FirstOrDefault()?.NodeGuid;
var widgetGuidValue = widgetGuid.HasValue ? widgetGuid.Value : Guid.Empty;
var model = new PodsListing<TConfiguration, TItem>
{
Configuration = _contentRepository.GetByNodeGuid(widgetGuidValue),
Items = new TItem[0]
};
if (null != model.Configuration)
{
var parent = _parentRepository.GetByNodeGuid(model.Configuration.ItemsParentNodeGUID);
if (null != parent)
{
model.Items = _childrenRepository.GetChildrenByPath(parent.NodeAliasPath, Limit).ToArray();
}
}
return View(ViewPath, model);
}
}
已转换的 FeaturePodsWidgetViewComponent
public class FeaturePodsWidgetViewComponent : BasePodsWidgetViewComponent<FeaturePodsWidgetProperties, FeaturePodsWidget, FeaturePod>
{
public const string IDENTIFIER = "FeaturePodsWidget";
protected override string ViewPath => "_FeaturePodsWidget";
public FeaturePodsWidgetViewComponent(IContentRepository<FeaturePodsWidget> contentRepository, IContentRepository<PodContainer> parentRepository, IContentRepository<FeaturePod> childrenRepository, IComponentPropertiesRetriever componentPropertiesRetriever)
: base(contentRepository, parentRepository, childrenRepository, componentPropertiesRetriever)
{
}
public override IViewComponentResult Invoke()
{
var properties = _componentPropertiesRetriever.Retrieve<FeaturePodsWidgetProperties>();
var widgetGuid = properties.WidgetConfiguration?.FirstOrDefault()?.NodeGuid;
var widgetGuidValue = widgetGuid.HasValue ? widgetGuid.Value : Guid.Empty;
ViewBag.MarginClass = WidgetStylingHelper.GetMarginClassFromWidgetProperties(properties.Margin);
var model = new PodsListing<FeaturePodsWidget, FeaturePod>
{
Configuration = _contentRepository.GetByNodeGuid(widgetGuidValue),
Items = new FeaturePod[0]
};
if (null != model.Configuration)
{
var parent = _parentRepository.GetByNodeGuid(model.Configuration.ItemsParentNodeGUID);
if (null != parent)
{
model.Items = _childrenRepository.GetChildrenByPath(parent.NodeAliasPath, 4).ToArray();
}
}
return View(ViewPath, model);
}
}
我收到这个错误:
View component 'I3.Base.Web.ViewComponents.Widgets.FeaturePodsWidgetViewComponent' must have exactly one public method named 'Invoke' or 'InvokeAsync'
我不明白为什么:(
.NET 5 文档指出 Like controllers, view components must be public, non-nested, and non-abstract classes.
所以我认为您不能直接覆盖 Invoke 方法。
我刚刚在 Dancing Goat 示例网站上尝试了一个基本示例,如果您在抽象 ViewComponent 上使用单独的虚拟方法,您可以直接在 Invoke 方法中调用它:
namespace DancingGoat.Components.ViewComponents
{
public abstract class BasePodsWidgetViewComponent : ViewComponent
{
protected readonly IComponentPropertiesRetriever _componentPropertiesRetriever;
public BasePodsWidgetViewComponent(IComponentPropertiesRetriever componentPropertiesRetriever)
{
_componentPropertiesRetriever = componentPropertiesRetriever;
}
public virtual IViewComponentResult Example()
{
// default logic
return View("~/Components/ViewComponents/CompanyAddress/TEST.cshtml");
}
public IViewComponentResult Invoke()
{
return Example();
}
}
}
然后在您的 FeaturePodsWidgetViewComponent
上您可以覆盖虚拟方法:
namespace DancingGoat.Components.ViewComponents
{
public class FeaturePodsWidgetViewComponent : BasePodsWidgetViewComponent
{
public FeaturePodsWidgetViewComponent(IComponentPropertiesRetriever componentPropertiesRetriever) : base(componentPropertiesRetriever)
{
}
public override IViewComponentResult Example()
{
// custom logic
return View("~/Components/ViewComponents/CompanyAddress/TEST2.cshtml");
}
}
}