Один контроллер с несколькими методами GET в ASP.NET Web API - PullRequest
148 голосов
/ 29 февраля 2012

В Web API у меня был класс схожей структуры:

public class SomeController : ApiController
{
    [WebGet(UriTemplate = "{itemSource}/Items")]
    public SomeValue GetItems(CustomParam parameter) { ... }

    [WebGet(UriTemplate = "{itemSource}/Items/{parent}")]
    public SomeValue GetChildItems(CustomParam parameter, SomeObject parent) { ... }
}

Поскольку мы могли отображать отдельные методы, было очень просто получить правильный запрос в нужном месте.Для аналогичного класса, который имел только один метод GET, но также имел параметр Object, я успешно использовал IActionValueBinder.Однако в описанном выше случае я получаю следующую ошибку:

Multiple actions were found that match the request: 

SomeValue GetItems(CustomParam parameter) on type SomeType

SomeValue GetChildItems(CustomParam parameter, SomeObject parent) on type SomeType

Я пытаюсь решить эту проблему, переопределив метод ExecuteAsync для ApiController, но пока безуспешно.Любой совет по этому вопросу?

Редактировать: я забыл упомянуть, что сейчас я пытаюсь переместить этот код в ASP.NET Web API, который имеет другой подход к маршрутизации.Вопрос в том, как заставить работать код на ASP.NET Web API?

Ответы [ 14 ]

239 голосов
/ 29 августа 2012

Это лучший способ, который я нашел для поддержки дополнительных методов GET и поддержки обычных методов REST.Добавьте следующие маршруты в ваш WebApiConfig:

routes.MapHttpRoute("DefaultApiWithId", "Api/{controller}/{id}", new { id = RouteParameter.Optional }, new { id = @"\d+" });
routes.MapHttpRoute("DefaultApiWithAction", "Api/{controller}/{action}");
routes.MapHttpRoute("DefaultApiGet", "Api/{controller}", new { action = "Get" }, new { httpMethod = new HttpMethodConstraint(HttpMethod.Get) });
routes.MapHttpRoute("DefaultApiPost", "Api/{controller}", new {action = "Post"}, new {httpMethod = new HttpMethodConstraint(HttpMethod.Post)});

Я проверил это решение с помощью тестового класса ниже.Мне удалось успешно выполнить каждый метод в моем контроллере ниже:

public class TestController : ApiController
{
    public string Get()
    {
        return string.Empty;
    }

    public string Get(int id)
    {
        return string.Empty;
    }

    public string GetAll()
    {
        return string.Empty;
    }

    public void Post([FromBody]string value)
    {
    }

    public void Put(int id, [FromBody]string value)
    {
    }

    public void Delete(int id)
    {
    }
}

Я проверил, что он поддерживает следующие запросы:

GET /Test
GET /Test/1
GET /Test/GetAll
POST /Test
PUT /Test/1
DELETE /Test/1

Примечание Что если вашдополнительные действия GET не начинаются с 'Get', возможно, вы захотите добавить атрибут HttpGet к методу.

55 голосов
/ 17 апреля 2012

Перейти к этому:

config.Routes.MapHttpRoute("API Default", "api/{controller}/{id}",
            new { id = RouteParameter.Optional });

К этому:

config.Routes.MapHttpRoute("API Default", "api/{controller}/{action}/{id}",
            new { id = RouteParameter.Optional });

Следовательно, теперь вы можете указать, на какое действие (метод) вы хотите отправить свой HTTP-запрос.

отправка на "http://localhost:8383/api/Command/PostCreateUser" вызывает:

public bool PostCreateUser(CreateUserCommand command)
{
    //* ... *//
    return true;
}

и отправка на " http://localhost:8383/api/Command/PostMakeBooking" вызывает:

public bool PostMakeBooking(MakeBookingCommand command)
{
    //* ... *//
    return true;
}

Я пробовал это всамообслуживаемое приложение службы WEB API, и оно работает как шарм:)

29 голосов
/ 26 марта 2014

Я считаю, что атрибуты удобнее использовать, чем добавлять их вручную с помощью кода.Вот простой пример.

[RoutePrefix("api/example")]
public class ExampleController : ApiController
{
    [HttpGet]
    [Route("get1/{param1}")] //   /api/example/get1/1?param2=4
    public IHttpActionResult Get(int param1, int param2)
    {
        Object example = null;
        return Ok(example);
    }

}

Вам также нужно это в вашем webapiconfig

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

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

Некоторые полезные ссылки http://www.asp.net/web-api/overview/getting-started-with-aspnet-web-api/tutorial-your-first-web-api Этот лучше объясняет маршрутизацию.http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-in-aspnet-web-api

11 голосов
/ 29 февраля 2012

Вам нужно определить дальнейшие маршруты в global.asax.cs следующим образом:

routes.MapHttpRoute(
    name: "Api with action",
    routeTemplate: "api/{controller}/{action}/{id}",
    defaults: new { id = RouteParameter.Optional }
);

routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional }
);
5 голосов
/ 05 февраля 2017

С более новым Web Api 2 стало проще иметь несколько методов get.

Если параметр, передаваемый в методы GET, достаточно отличается для системы маршрутизации атрибутов, чтобы различать их типы, как в случае с int s и Guid s, вы можете указать ожидаемый тип в [Route...] атрибут

Например -

[RoutePrefix("api/values")]
public class ValuesController : ApiController
{

    // GET api/values/7
    [Route("{id:int}")]
    public string Get(int id)
    {
       return $"You entered an int - {id}";
    }

    // GET api/values/AAC1FB7B-978B-4C39-A90D-271A031BFE5D
    [Route("{id:Guid}")]
    public string Get(Guid id)
    {
       return $"You entered a GUID - {id}";
    }
} 

Подробнее об этом подходе см. Здесь http://nodogmablog.bryanhogan.net/2017/02/web-api-2-controller-with-multiple-get-methods-part-2/

Другой вариант - предоставить GET методам разные маршруты.

    [RoutePrefix("api/values")]
    public class ValuesController : ApiController
    {
        public string Get()
        {
            return "simple get";
        }

        [Route("geta")]
        public string GetA()
        {
            return "A";
        }

        [Route("getb")]
        public string GetB()
        {
            return "B";
        }
   }

Подробнее см. Здесь - http://nodogmablog.bryanhogan.net/2016/10/web-api-2-controller-with-multiple-get-methods/

3 голосов
/ 15 января 2018

В ASP.NET Core 2.0 вы можете добавить атрибут Маршрут к контроллеру:

[Route("api/[controller]/[action]")]
public class SomeController : Controller
{
    public SomeValue GetItems(CustomParam parameter) { ... }

    public SomeValue GetChildItems(CustomParam parameter, SomeObject parent) { ... }
}
3 голосов
/ 19 марта 2012

Я не уверен, что вы нашли ответ, но я сделал это, и он работает

public IEnumerable<string> Get()
{
    return new string[] { "value1", "value2" };
}

// GET /api/values/5
public string Get(int id)
{
    return "value";
}

// GET /api/values/5
[HttpGet]
public string GetByFamily()
{
    return "Family value";
}

Теперь в global.asx

routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

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

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

routes.MapRoute(
    name: "Default",
    url: "{controller}/{action}/{id}",
    defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
3 голосов
/ 29 февраля 2012

Вы пытались переключиться на WebInvokeAttribute и установить метод для «GET»?

Я полагаю, что у меня была похожая проблема, и я переключился на явное указание, какой метод (GET / PUT / POST / DELETE) ожидается в большинстве, если не во всех моих методах.

public class SomeController : ApiController
{
    [WebInvoke(UriTemplate = "{itemSource}/Items"), Method="GET"]
    public SomeValue GetItems(CustomParam parameter) { ... }

    [WebInvoke(UriTemplate = "{itemSource}/Items/{parent}", Method = "GET")]
    public SomeValue GetChildItems(CustomParam parameter, SomeObject parent) { ... }
}

WebGet должен справиться с этим, но я видел, что у него есть некоторые проблемы с множеством Получить намного меньше, несколько Получить с тем же типом возврата.

[Редактировать: все это недопустимо в случае заката WCF WebAPI и перехода на ASP.Net WebAPI в стеке MVC]

2 голосов
/ 05 июня 2017

Я пытался использовать атрибуты маршрутизации Web Api 2 для обеспечения нескольких методов Get, и я включил полезные предложения из предыдущих ответов, но в Controller я только украсил «специальный» метод (пример):

[Route( "special/{id}" )]
public IHttpActionResult GetSomethingSpecial( string id ) {

... также без размещения [RoutePrefix] в верхней части контроллера:

[RoutePrefix("api/values")]
public class ValuesController : ApiController

Я получаю ошибки, утверждающие, что не найдено ни одного маршрута, соответствующего представленному URI. Как только у меня было [Route], украшающее метод, так и [RoutePrefix], украшающее Контроллер в целом, это работало.

0 голосов
/ 30 апреля 2018

Простая альтернатива

Просто используйте строку запроса.

Маршрутизация

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

Контроллер

public class TestController : ApiController
{
    public IEnumerable<SomeViewModel> Get()
    {
    }

    public SomeViewModel GetById(int objectId)
    {
    }
}

Запросы

GET /Test
GET /Test?objectId=1

Примечание

Имейте в виду, что параметр строки запроса не долженбыть "id" или любым другим параметром в настроенном маршруте.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...