有没有办法在放置和渲染发生之前改变 Orchard 内容形状的显示类型?

Is there a way to alter an Orchard content shape's display type before placement and rendering happens?

我们正尝试在 Orchard 1.10 中实现一个通用的可重复使用的付费专区作为 ContentPart。目标是对非付费用户隐藏某些内容,同时保持其详细信息页面作为预告片可访问。

最初的想法是使用ShapeTableProvider检查每个"Content"形状并根据用户的权限更改其显示类型。然后就可以根据每个内容自定义我们想要在展示位置展示的内容。例如如果用户无权访问新闻文章,则仅显示 Layout_Summary 而不是完整布局。

大致如下:

builder.Describe("Content").OnDisplaying(displaying => {
    if(displaying.Shape.Metadata.DisplayType == "Detail"  && !_authorizer.Authorize(ViewPaidContent) {
        displaying.Shape.Metadata.DisplayType == "DetailPaywall";      
    }
});

--

<Placement>
    <Match DisplayType="DetailPaywall">
        <Place Parts_Layout="-"/>
        ...
    </Match>  
</Placement>

然而,事实证明 OnDisplaying 发生得太晚了,位置已经确定并且 ContentDrivers 被调用。 OnCreated 发生得太早,会再次被覆盖。我相信触发这些的相关代码是 Orchard.ContentManagement.DefaultContentDisplay 中的 BuildDisplay 方法。此处传递的 displayType 参数是最终被使用的参数。

是否有任何方法可以根据某些条件影响代码中的显示类型,或者我们可以使用不同的方法来实现类似的功能?

显示类型通常由部件的驱动程序决定。您可能应该做的是引入替代方法:

builder.Describe("Content").OnDisplaying(displaying => {
    if(displaying.Shape.Metadata.DisplayType == "Detail"  && !_authorizer.Authorize(ViewPaidContent) {
        displaying.Shape.Metadata.Alternates.Add("Content__Paywall");      
    }
});

然后您可以将 Content-Paywall.cshtml 模板覆盖添加到您的主题,您应该完成了。