I was attempting to use Interfaces with default implementation methods to add common methods to WebAPI controllers by simply implementing the interface. Implementing the interface compiles and builds, but ultimately the API methods are not created for the controller
Perhaps this isn't possible or for some reason the attributes of Interface methods aren't being read by something?
I was really hoping this would work, but it may not be possible. Hopefully someone has a suggestion or has done this before.
Thanks!
additional though:
I was using inheritance of a base controller class to implement common methods, but for some controllers I may only want to have Read methods, and another controller have Create Read Update and Delete or any combination of those methods.
Controller code
using App.Core;
using App.Service;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using Microsoft.Extensions.Logging;
using System;
using Microsoft.Extensions.Configuration;
using App.RestApi.Common;
namespace App.RestApi.Controllers
{
[ApiVersion("1")]
[Route("api/v{version:apiVersion}/def/associate")]
[Authorize(Roles = "Read,Edit,Admin")]
[ProducesResponseType(typeof(AccessControlRejection), 401)]
[ProducesResponseType(typeof(AccessControlRejection), 403)]
[ApiController]
public class AssociateController : Controller, IQueryController<Associate>
{
//This Method gets created
[HttpPost]
[Route("query2")]
[ApiConventionMethod(typeof(DefaultApiConventions), nameof(DefaultApiConventions.Post))]
[Authorize(Roles = "Edit,Admin")]
public IActionResult Query2([FromServices] IConfiguration config,
[FromServices] ILogger<Associate> logger,
[FromServices] IBaseService service,
List<QueryParam> listQueryParams)
{
ControllerBase ctrlBase = (ControllerBase)this;
List<Associate> listEntity = service.Query<Associate>(listQueryParams);
logger.LogInformation(LoggingEvents.GetItem, $"Query: {listQueryParams}");
return ctrlBase.Ok(listEntity);
}
}
}
Interface code
using Microsoft.AspNetCore.Mvc;
using App.Core;
using System.Collections.Generic;
using Microsoft.AspNetCore.Authorization;
using App.Service;
using Microsoft.Extensions.Logging;
using FluentValidation;
using App.RestApi.Common;
using System.Net;
using Microsoft.Extensions.Configuration;
namespace App.RestApi.Controllers
{
public interface IQueryController<T>
where T : BaseEntity
{
//This Method does not get created.
[HttpPost]
[Route("query")]
[ApiConventionMethod(typeof(DefaultApiConventions), nameof(DefaultApiConventions.Post))]
[Authorize(Roles = "Edit,Admin")]
public IActionResult Query([FromServices] IConfiguration config,
[FromServices] ILogger<T> logger,
[FromServices] IBaseService service,
List<QueryParam> listQueryParams)
{
ControllerBase ctrlBase = (ControllerBase)this;
List<T> listEntity = service.Query<T>(listQueryParams);
logger.LogInformation(LoggingEvents.GetItem, $"Query: {listQueryParams}");
return ctrlBase.Ok(listEntity);
}
}
}
CodePudding user response:
I would say that is expected according to the convention described in the documentation:
Public methods on a controller, except those with the
[NonAction]
attribute, are actions.
Concrete method in interface is not a method of class implementing the interface (unless it's explicitly implements it), it's a method of the interface:
Note that a class does not inherit members from its interfaces; that is not changed by this feature
i.e. it can't be accessed by reference typed to the class, only by reference typed to the interface:
public interface IInterface
{
int Do() => 1;
}
public class Implementation : IInterface
{
// public int Do() => 2;
}
var asInstance = new Implementation();
// var i = asInstance.Do(); // will not compile unless the implementation in class is uncommented
var i1 = ((IInterface)asInstance).Do(); // compiles