Web API 2.2,具有路由覆盖的继承控制器(这可能吗)?
Web API 2.2, Inherited Controller with Route Overrides (Is this possible)?
所以我有一个实现 CRUD 的通用基础控制器,它派生自 APIController
。
public class GenericController<TEntity> : ApiController where TEntity : class {
private readonly GenericModel<TEntity> _model;
public IModel Model {
get { return _model; }
}
public GenericController(IGenericModel<TEntity> model) {
_model = (GenericModel<TEntity>)model;
}
[HttpPost, Route]
public IHttpActionResult Post(TEntity entity) {
TEntity newEntity = _model.Create(entity);
String urlLink = $"{Request.RequestUri}{RequestContext.VirtualPathRoot}{((IGenericEntity)newEntity).ID}";
return Created(urlLink, newEntity);
}
[HttpGet, Route]
public IHttpActionResult GetList() {
return Ok(_model.ReadList());
}
[HttpGet, Route("{ID:int}")]
public IHttpActionResult Get(Int64 ID) {
return Ok(_model.Read(ID));
}
[HttpPut, Route]
public IHttpActionResult Put(TEntity entity) {
_model.Update(entity);
return Ok();
}
[HttpDelete, Route("{ID:int}")]
public IHttpActionResult Delete(Int64 ID) {
_model.Delete(ID);
return Ok();
}
}
并且允许控制器通过 CustomDirectRouteProvider
继承:
config.MapHttpAttributeRoutes(new CustomDirectRouteProvider());
我的 CustomDirectRouteProvider 在哪里:
public class CustomDirectRouteProvider : DefaultDirectRouteProvider {
protected override IReadOnlyList<IDirectRouteFactory> GetActionRouteFactories(HttpActionDescriptor actionDescriptor) {
return actionDescriptor.GetCustomAttributes<IDirectRouteFactory> (inherit: true);
}
}
这一切都很好用,直到我想覆盖像 POST 这样的方法。例如:
[RoutePrefix(@"api/Test")]
public class DerivedController : GenericController<ConcreteEntity> {
public DerivedController (IGenericModel<ConcreteEntity> model) : base(model) {
}
[HttpPost, Route]
public new IHttpActionResult Post(ConcreteEntity entity) {
//New Post Functionality Here
}
}
此时我得到错误:
"Multiple actions were found that match the request"
所以我的问题是,如何覆盖路由本身?我基本上希望我的新 POST 优先于通用的。我认为通过隐藏通用 route/method 这会起作用,但是我的想法不正确。
能够重新创建您的问题,并且通过反复试验的过程能够通过使 GenericController
成为摘要 class
来使其正常工作
public abstract class GenericController<TEntity> : ApiController where TEntity : class {
[HttpPost, Route]
public virtual IHttpActionResult Post(TEntity entity) {
TEntity newEntity = _model.Create(entity);
String urlLink = $"{Request.RequestUri}{RequestContext.VirtualPathRoot}{((IGenericEntity)newEntity).ID}";
return Created(urlLink, newEntity);
}
}
并删除 DerivedController
的继承操作的属性,因为它们与继承的 class
相匹配
[RoutePrefix(@"api/Test")]
public class DerivedController : GenericController<ConcreteEntity> {
public DerivedController (IGenericModel<ConcreteEntity> model) : base(model) {
}
public override IHttpActionResult Post(ConcreteEntity entity) {
//New Post Functionality Here
}
}
所以我有一个实现 CRUD 的通用基础控制器,它派生自 APIController
。
public class GenericController<TEntity> : ApiController where TEntity : class {
private readonly GenericModel<TEntity> _model;
public IModel Model {
get { return _model; }
}
public GenericController(IGenericModel<TEntity> model) {
_model = (GenericModel<TEntity>)model;
}
[HttpPost, Route]
public IHttpActionResult Post(TEntity entity) {
TEntity newEntity = _model.Create(entity);
String urlLink = $"{Request.RequestUri}{RequestContext.VirtualPathRoot}{((IGenericEntity)newEntity).ID}";
return Created(urlLink, newEntity);
}
[HttpGet, Route]
public IHttpActionResult GetList() {
return Ok(_model.ReadList());
}
[HttpGet, Route("{ID:int}")]
public IHttpActionResult Get(Int64 ID) {
return Ok(_model.Read(ID));
}
[HttpPut, Route]
public IHttpActionResult Put(TEntity entity) {
_model.Update(entity);
return Ok();
}
[HttpDelete, Route("{ID:int}")]
public IHttpActionResult Delete(Int64 ID) {
_model.Delete(ID);
return Ok();
}
}
并且允许控制器通过 CustomDirectRouteProvider
继承:
config.MapHttpAttributeRoutes(new CustomDirectRouteProvider());
我的 CustomDirectRouteProvider 在哪里:
public class CustomDirectRouteProvider : DefaultDirectRouteProvider {
protected override IReadOnlyList<IDirectRouteFactory> GetActionRouteFactories(HttpActionDescriptor actionDescriptor) {
return actionDescriptor.GetCustomAttributes<IDirectRouteFactory> (inherit: true);
}
}
这一切都很好用,直到我想覆盖像 POST 这样的方法。例如:
[RoutePrefix(@"api/Test")]
public class DerivedController : GenericController<ConcreteEntity> {
public DerivedController (IGenericModel<ConcreteEntity> model) : base(model) {
}
[HttpPost, Route]
public new IHttpActionResult Post(ConcreteEntity entity) {
//New Post Functionality Here
}
}
此时我得到错误:
"Multiple actions were found that match the request"
所以我的问题是,如何覆盖路由本身?我基本上希望我的新 POST 优先于通用的。我认为通过隐藏通用 route/method 这会起作用,但是我的想法不正确。
能够重新创建您的问题,并且通过反复试验的过程能够通过使 GenericController
成为摘要 class
public abstract class GenericController<TEntity> : ApiController where TEntity : class {
[HttpPost, Route]
public virtual IHttpActionResult Post(TEntity entity) {
TEntity newEntity = _model.Create(entity);
String urlLink = $"{Request.RequestUri}{RequestContext.VirtualPathRoot}{((IGenericEntity)newEntity).ID}";
return Created(urlLink, newEntity);
}
}
并删除 DerivedController
的继承操作的属性,因为它们与继承的 class
[RoutePrefix(@"api/Test")]
public class DerivedController : GenericController<ConcreteEntity> {
public DerivedController (IGenericModel<ConcreteEntity> model) : base(model) {
}
public override IHttpActionResult Post(ConcreteEntity entity) {
//New Post Functionality Here
}
}