dotnet/runtime

Methods were covariant return types applies does not inherit attributes

Open

#92.047 aperta il 14 set 2023

Vedi su GitHub
 (4 commenti) (0 reazioni) (0 assegnatari)C# (5445 fork)batch import
area-System.Reflectionhelp wanted

Metriche repository

Star
 (17.886 star)
Metriche merge PR
 (Merge medio 12g 11h) (661 PR mergiate in 30 g)

Descrizione

Description

Today my coworker encountered an issue with Asp.Net Core 7.0 were an abstract controller base class contained an endpoint which return type were just Task. The controller that implemented it was returning Task<IActionResult>, but the endpoint was not being found. When i slapped the HttpPostAttribute on the overriden method it suddenly worked.

In the reproduction steps i have prepared a simple example code which shows, that GetCustomAttributes(inherit: true) is not giving the attribute. I assume this is the reason, why Asp.Net Core does not find it. I expect this is not an bug in Asp.Net Core, but more in the compiler or GetCustomAttributes implementation.

I have not found any hint in all dotnet repositories, that for covariant return types all attributes of the method of the base class must be omitted. So i think the actual behavior is not by design. If this is by design, should libraries and user code manually find the overriden methods and pick the attributes from there?

Reproduction Steps

Here is an example code which demonstrates it. I have prepared an example sharplab.io for it.

using System;
using System.Linq;
using System.Threading.Tasks;

Console.WriteLine("Does AController.PostThis have HttpPost attribute? "
  + typeof(AController).GetMethod("PostThis")!.GetCustomAttributes(true).OfType<HttpPostAttribute>().Any());
Console.WriteLine("Does BController.PostThis have HttpPost attribute? "
  + typeof(BController).GetMethod("PostThis")!.GetCustomAttributes(true).OfType<HttpPostAttribute>().Any());

abstract class BaseController 
{
    [HttpPost]
    public abstract Task PostThis();   
}

class AController : BaseController
{
    public override Task<object?> PostThis()
    {
        return Task.FromResult<object?>(null);
    }
}

class BController : BaseController
{
    public override Task PostThis()
    {
        return Task.FromResult<object?>(null);
    }
}

class HttpPostAttribute : Attribute 
{

}

Expected behavior

I expected following output

Does AController.PostThis have HttpPost attribute? True
Does BController.PostThis have HttpPost attribute? True

Actual behavior

But it was following output

Does AController.PostThis have HttpPost attribute? False
Does BController.PostThis have HttpPost attribute? True

Regression?

I think this is like this since the first release of the covariant return type feature.

Known Workarounds

  1. Not using the covariant return type feature when using attributes.
  2. Copy all attributes over to every implementation.

Configuration

.NET 7.0 x86 and x64 on Windows 10 but as you can see is also on sharplab.io reproducible.

Other information

No response

Guida contributor