Skip to main content
 首页 » 编程设计

c#之Web API 2.2,具有路由覆盖的继承 Controller (这可能吗)

2024年02月05日31softidea

所以我有一个实现 CRUD 的通用基础 Controller ,它派生自 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 继承 Controller :

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 优先于通用 POST。我认为由于隐藏了通用路由/方法,这会起作用,但可惜我的想法不正确。

请您参考如下方法:

能够重现您的问题,并且通过反复试验的过程能够通过将 GenericController 设为抽象类来使其正常工作

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 的继承操作的属性,因为它们与继承的类匹配

[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 
    } 
}