Подтвердить что ты не робот

Маршрутизация и наследование атрибутов

Я играю с идеей иметь базовый контроллер, который использует общий репозиторий для предоставления базовых методов CRUD для моих контроллеров API, чтобы мне не приходилось дублировать один и тот же базовый код в каждом новом контроллере. Но у меня возникают проблемы с распознаванием атрибута маршрутизации, когда он находится в базовом контроллере. Чтобы точно показать, в чем заключается проблема, я создал действительно простой контроллер WebAPI.

Когда у меня есть метод Get в главном контроллере, и он наследуется от ApiController напрямую, у меня нет проблем, и это работает, как и ожидалось.

[RoutePrefix("admin/test")]
public class TestController : ApiController
{
    [Route("{id:int:min(1)}")]
    public string Get(int id)
    {
        return "Success";
    }
}

Когда я перемещаю метод Get в базовый контроллер, он возвращает содержимое страницы 404.

[RoutePrefix("admin/test")]
public class TestController : TestBaseController
{

}

public class TestBaseController : ApiController
{
    [Route("{id:int:min(1)}")]
    public string Get(int id)
    {
        return "Success";
    }
}

Еще несколько интересных заметок:

  • Я могу получить доступ к действию в GET /Test/1. Так что он все еще находит его на основе маршрута по умолчанию.

  • Когда я пытаюсь получить доступ к POST /admin/test, он возвращает следующий JSON

    {"Message": "Не найден ресурс HTTP, соответствующий URI запроса" http://test.com/admin/test ".", "MessageDetail": "Не найден тип, соответствующий контроллеру с именем 'admin'. " }

Кто-нибудь знает способ заставить маршрутизацию работать с атрибутами из базового контроллера?

4b9b3361

Ответ 1

Маршруты атрибутов не могут быть унаследованы. Это было преднамеренное дизайнерское решение. Мы не чувствовали себя правильно и не видели реальных сценариев, где было бы разумно наследовать их.

Не могли бы вы дать более реалистичный сценарий относительно того, где вы хотели бы использовать это?

[ Обновить (3/24/2014)]
В предстоящем выпуске веб-API MVC 5.2 будет существовать точка расширения, называемая System.Web.Http.Routing.IDirectRouteProvider, через которую вы можете включить сценарий наследования, который вы ищете здесь. Вы можете попробовать это самостоятельно, используя новейшие ночные сборки (документация о том, как использовать ночные сборки, здесь)

[ Обновить (7/31/2014)]
Пример того, как это можно сделать в Web API 2.2 release:

config.MapHttpAttributeRoutes(new CustomDirectRouteProvider());

//---------

public class CustomDirectRouteProvider : DefaultDirectRouteProvider
{
    protected override IReadOnlyList<IDirectRouteFactory> 
    GetActionRouteFactories(HttpActionDescriptor actionDescriptor)
    {
        // inherit route attributes decorated on base class controller actions
        return actionDescriptor.GetCustomAttributes<IDirectRouteFactory>
        (inherit: true);
    }
}

Ответ 2

Используя Web API 2.2, вы можете:

public class BaseController : ApiController
{
    [Route("{id:int}")]
    public string Get(int id)
    {
        return "Success:" + id;
    }
}
[RoutePrefix("api/values")]
public class ValuesController : BaseController
{
}

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

как описано здесь: http://www.asp.net/web-api/overview/releases/whats-new-in-aspnet-web-api-22

Ответ 3

Получил это.

[Route("api/baseuploader/{action}")]
public abstract class BaseUploaderController : ApiController
{
    [HttpGet] 
    public string UploadFile() 
    {
        return "UploadFile";
    }
}


[Route("api/values/{action}")]
public class ValuesController : BaseUploaderController
{
    [HttpGet]
    public string Get(int id)
    {
        return "value";
    }
}

Оговорка здесь заключается в том, что параметр действия маршрута должен быть таким же, как имя действия. Я не мог найти способ обойти это. (Вы не можете переименовать маршрут с атрибутом RouteAttribute)