【问题标题】:Override Invoke method in an inherited ViewComponent .net core 5.0在继承的 ViewComponent .net core 5.0 中覆盖 Invoke 方法
【发布时间】:2021-12-06 17:01:59
【问题描述】:

我正在从 ASP.NET MVC 迁移到 ASP.NET Core 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,我得到一个错误,说只允许一个 Invoke 方法并且不知道为什么

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);
    }
}

我收到此错误:

视图组件“I3.Base.Web.ViewComponents.Widgets.FeaturePodsWidgetViewComponent”必须只有一个名为“Invoke”或“InvokeAsync”的公共方法

我不知道为什么:(

【问题讨论】:

  • 是否允许创建虚拟Invoke方法?否则,您应该将 Invoke 放在基类中并调用另一个可以在派生类中覆盖的抽象方法。

标签: c# asp.net-core-mvc kentico asp.net-core-viewcomponent


【解决方案1】:

.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");
        }
    }
}

【讨论】:

  • 嗨,利亚姆——干得不错,干杯:)
猜你喜欢
  • 1970-01-01
  • 2012-11-20
  • 2016-06-04
  • 2016-01-25
  • 1970-01-01
  • 1970-01-01
  • 2013-08-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多