Skip to content

Commit

Permalink
Clarify RenderModeAttribute inheritance. Fixes #49848
Browse files Browse the repository at this point in the history
  • Loading branch information
SteveSandersonMS committed Aug 23, 2023
1 parent 91f14fc commit 39da5b1
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/Components/Components/src/RenderModeAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace Microsoft.AspNetCore.Components;
/// be implemented to work across all render modes. Component authors should only specify
/// a fixed rendering mode when the component is incapable of running in other modes.
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public abstract class RenderModeAttribute : Attribute
{
/// <summary>
Expand Down
33 changes: 33 additions & 0 deletions src/Components/Components/test/ComponentFactoryTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,29 @@ public void InstantiateComponent_WithRenderModeOnComponent_UsesRenderModeResolve
Assert.IsType<TestRenderMode>(renderer.SuppliedRenderMode);
}

[Fact]
public void InstantiateComponent_WithDerivedRenderModeOnDerivedComponent_CausesAmbiguousMatchException()
{
// We could allow derived components to override the rendermode, but:
// [1] It's unclear how that would be legitimate. If the base specifies a rendermode, it's saying
// it only works in that mode. It wouldn't be safe for a derived type to change that.
// [2] If we did want to implement this, we'd need to implement our own inheritance chain walking
// to make sure we find the rendermode from the *closest* ancestor type. GetCustomAttributes
// on its own isn't documented to return the results in any specific order.
// Since issue [1] makes it unclear we'd want to support this, for now we don't.

// Arrange
var resolvedComponent = new ComponentWithInjectProperties();
var componentType = typeof(DerivedComponentWithRenderMode);
var renderer = new RendererWithResolveComponentForRenderMode(resolvedComponent);
var componentActivator = new DefaultComponentActivator();
var factory = new ComponentFactory(componentActivator, renderer);

// Act/Assert
Assert.Throws<AmbiguousMatchException>(
() => factory.InstantiateComponent(GetServiceProvider(), componentType, null, 1234));
}

[Fact]
public void InstantiateComponent_WithRenderModeOnCallSite_UsesRenderModeResolver()
{
Expand Down Expand Up @@ -290,6 +313,16 @@ public IComponent CreateInstance(Type componentType)
}

private class TestRenderMode : IComponentRenderMode { }
private class DerivedComponentRenderMode : IComponentRenderMode { }

[DerivedComponentRenderMode]
private class DerivedComponentWithRenderMode : ComponentWithRenderMode
{
class DerivedComponentRenderModeAttribute : RenderModeAttribute
{
public override IComponentRenderMode Mode => new DerivedComponentRenderMode();
}
}

[OwnRenderMode]
private class ComponentWithRenderMode : IComponent
Expand Down

0 comments on commit 39da5b1

Please sign in to comment.