0

I am trying to use an abstract base class with generics on an ASP Net Core controller. While the code builds, the endpoints return 404 and do not appear in the swagger docs.

When I remove the generic base class, I am able to see the controller in the docs, but I would then have to copy and paste multiple versions of the controller, which I am trying to avoid.

Any suggestions on what I am missing?

THIS CONTROLLER WORKS

[Route("/testconcrete/employees")]
public class TestController : ControllerBase
{
    private readonly IUserService<TechDevsEmployee> _userService;

    public TestController(IUserService<TechDevsEmployee> userService)
    {
        _userService = userService;
    }

    [HttpGet("{userId}")]
    public async Task<ActionResult<User>> GetUserById([FromRoute] Guid userId)
    {
        var result = await _userService.FindById(userId);
        return new OkObjectResult(result);
    }
}

THIS CONTROLLER DOES NOT WORK (404)

[Route("/testgeneric/employees")]
public class TechDevsEmployeeController<TechDevsEmployee> : UserController<TechDevsEmployee> where TechDevsEmployee : IUser, IClientEntity
{
    public TechDevsEmployeeController(IUserService<TechDevsEmployee> userService) : base(userService)
    {
    }
}

BASE CLASS

public abstract class UserController<T> : ControllerBase where T : IUser, IClientEntity
{
    private readonly IUserService<T> _userService;

    public UserController(IUserService<T> userService)
    {
        _userService = userService;
    }

    [HttpGet("{userId}")]
    public async Task<ActionResult<User>> GetUserById([FromRoute] Guid userId)
    {
        var result = await _userService.FindById(userId);
        return new OkObjectResult(result);
    }
}
Nkosi
  • 235,767
  • 35
  • 427
  • 472
stevie6410
  • 11
  • 1
  • 4

2 Answers2

2

I believe in your subclass definition you have declared a generic type TechDevsEmployee in the class signature. The subclass does not need to specify this, you can specify the type you want the BaseClass to use directly like so:

[Route("/testgeneric/employees")]
public class TechDevsEmployeeController : UserController<TechDevsEmployee>
{
    public TechDevsEmployeeController(IUserService<TechDevsEmployee> userService) 
        : base(userService)
    {
    }
}
kyleJ
  • 368
  • 2
  • 7
1

As kyleJ mentions in his answer, you cannot have a generic parameter on the concrete class itself. MVC has no way of guessing what type you want to use for TechDevsEmployee. If you have many subclasses of TechDevsEmployee, you need to create a separate sub controller for each subclass, and remove the generic parameter from the subclass, as mentioned in the other answer https://stackoverflow.com/a/60920600/25338

Erik A. Brandstadmoen
  • 10,430
  • 2
  • 37
  • 55