ASP.NET核心控制器路由属性继承和抽象控制器操作-不明确的ActionException



我正在从事ASP.NET Core Webapi项目。我想为每个控制器通用的所有方法(例如CRUD方法(实现某种Base/Abstract通用控制器,并在所有其他控制器中继承此控制器。我在下面附上示例代码:

public abstract class BaseApiController : Controller 
{
[HttpGet]
[Route("")]
public virtual IActionResult GetAll() 
{
...
}
[HttpGet]
[Route("{id}")]
public virtual IActionResult GetById(int id)
{
...
}
[HttpPost]
[Route("")]
public virtual IActionResult Insert(myModel model)
{
...
}
}

[Route("api/Student")]
public class StudentController : BaseApiController 
{
// Inherited endpoints:
// GetAll method is available on api/Student [GET]
// GetById method is available on api/Student/{id} [GET]
// Insert method is available on api/Student [POST]
//
// Additional endpoints:
// ShowNotes is available on api/Student/{id}/ShowNotes [GET]
[HttpGet]
[Route("{id}/ShowNotes")]
public virtual IActionResult ShowNotes(int id) 
{
...
}
}
[Route("api/Teacher")]
public class TeacherController : BaseApiController 
{
// Inherited endpoints:
// GetAll method is available on api/Teacher [GET]
// GetById method is available on api/Teacher/{id} [GET]
// Insert method is available on api/Teacher [POST]
//
// Additional endpoints:
// ShowHours is available on api/Teacher/{id}/ShowHours [GET]
[HttpGet]
[Route("{id}/ShowHours")]
public virtual IActionResult ShowHours(int id) 
{
...
}
}

我在.NET Framework WebApi中看到过这种解决方案,带有额外的自定义RouteProvider,例如:

public class WebApiCustomDirectRouteProvider : DefaultDirectRouteProvider
{
protected override IReadOnlyList<IDirectRouteFactory> GetActionRouteFactories(HttpActionDescriptor actionDescriptor)
{
return actionDescriptor.GetCustomAttributes<IDirectRouteFactory>(inherit: true);
}
}

每次我试图到达派生控制器中的Endpoint时,我都会得到模棱两可的ActionException:

Multiple actions matched. The following actions matched route data and had all constraints satisfied:
XXX.WebApi.Controllers.CommonAppData.TeacherController.GetById
XXX.WebApi.Controllers.CommonAppData.StudentController.GetById

有可能在.NET Core WebApi中创建这样的基本控制器吗?在不在派生的Controller中显式声明它的情况下,我应该如何编写它以到达Action Methods?我应该如何配置这种解决方案?启动类中有其他配置吗?

因为这个主题很好,所以很有价值,我解释了我是如何做到的。你可以创建一个Generic控制器,如下所示:

[Route("api/[controller]/[action]")]
[ApiController]
public class BaseController<TEntity> : Controller where TEntity : class, new()
{
private readonly YourDbContext _db;

public BaseController(YourDbContext db)
{
_db=db;
}

public virtual async Task<IActionResult> GetAll()
{
var data= await _db.Set<TEntity>().ToListAsync();
return View(data);
}

public virtual IActionResult GetById(int id)
{
var data= await _db.Set<TEntity>().FindAsync(e=>e.Id == id);
return View(data);
}
.....

}

然后你可以这样使用它:

public class StudentController : BaseController<Student> 
{
}

当然,你可以用这样的可选参数写得更好:

public virtual async Task<IActionResult> GetAll(Expression<Func<TEntity, bool>>? predicate = null)
{
var data= await _db.Set<TEntity>().Where(predicate).ToListAsync();
....
}

甚至可以根据您的喜好覆盖继承控制器中的每个动作,并为您的动作添加必要的参数

public override Task<IActionResult> Get(....

我希望喜欢它;(别忘了投票

最新更新