WebApi2 attribute routing inherited controllers

2019-04-10 08:22发布

I'm trying to create basic REST api with a base controller like so:

Base class:

public abstract class WebApiEntityController<TEntity> : ApiController
    where TEntity : EntityBase<TEntity, int>
{
    private readonly IRepository<TEntity> _repository; 
    protected WebApiEntityController(IRepository<TEntity> repository)
    {
        _repository = repository;
    }

    [Route("")]
    [WebApiUnitOfWork]
    public HttpResponseMessage Get()
    {
        return Request.CreateResponse(HttpStatusCode.OK, _repository.ToList());
    }
    [..........]

Derived class:

[RoutePrefix("api/TimesheetTask")]
public class TimesheetTaskController : WebApiEntityController<TimesheetTask>
{
    private readonly IRepository<TimesheetTask> _timeSheetTaskRepository;

    public TimesheetTaskController(IRepository<TimesheetTask> timeSheetTaskRepository) : base(timeSheetTaskRepository)
    {
        _timeSheetTaskRepository = timeSheetTaskRepository;
    }
}

but calling GET on the route ~/api/TimesheetTask/ results in a 404 not found.

According to this answer, attribute routes cannot be inherited. So my question is, how can I write a consistent API for all my domain models without having to copy and paste code?

I know I can do convention routing with this configuration:

config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{action}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );

but then I'll have to specify the action, and my endpoints will be

/api/{controller]/Get
/api/{controller]/Post

and I don't want that. I can also remove the {action} part of the routeTemplate, but then how will I route to custom actions?

If anyone can help, that would be appreciated. Also, the next step for my domain model API would involve supporting querying, and that can easily get complicated. Is there a library that generates these routes for you? If anyone can help me find such a library it would be much appreciated.

1条回答
做个烂人
2楼-- · 2019-04-10 09:15

The answer you quoted has since been updated. As of WebApi 2.2 they created an extensibility point to allow the feature you wanted. Attribute rout can be inherited, but you need to configure it. I had the same requirement for a base API controller and after searching came across the same answer you quoted.

.NET WebAPI Attribute Routing and inheritance

You need to overwrite the DefaultDirectRoutePrivider:

public class WebApiCustomDirectRouteProvider : DefaultDirectRouteProvider {
    protected override System.Collections.Generic.IReadOnlyList<IDirectRouteFactory>
        GetActionRouteFactories(System.Web.Http.Controllers.HttpActionDescriptor actionDescriptor) {
        // inherit route attributes decorated on base class controller's actions
        return actionDescriptor.GetCustomAttributes<IDirectRouteFactory>(inherit: true);
    }
}

With that done you then need to configure it in your web api configuration

public static class WebApiConfig {
    public static void Register(HttpConfiguration config) {
        .....
        // Attribute routing. (with inheritance)
        config.MapHttpAttributeRoutes(new WebApiCustomDirectRouteProvider());
        ....
    }
}
查看更多
登录 后发表回答