Маршрутизация на основе имени параметра строки запроса

Я пытаюсь настроить маршрутизацию в своем проекте MVC4 WebAPI.

Я хочу иметь возможность искать продукты по их имени или типу, например:

/api/products?name=WidgetX — возвращает все продукты с именем WidgetX /api/products?type=gadget — возвращает все продукты типа гаджет

Маршруты настроены так:

config.Routes.MapHttpRoute(
    name: "Get by name",
    routeTemplate: "api/products/{name}",
    defaults: new { controller = "ProductSearchApi", action = "GetProductsByName", name = string.Empty }
);

config.Routes.MapHttpRoute(
    name: "Get by type",
    routeTemplate: "api/products/{type}",
    defaults: new { controller = "ProductSearchApi", action = "GetProductsByType", type = string.Empty }
);

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


person rickythefox    schedule 27.09.2012    source источник


Ответы (4)


Вам нужен только один маршрут ниже, потому что строка запроса не используется в качестве параметров маршрутизации:

config.Routes.MapHttpRoute(
    name: "Get Products",
    routeTemplate: "api/products",
    defaults: new { controller = "ProductSearchApi" }
);

Затем определите два метода, как показано ниже:

GetProductsByName(string name)
{}

GetProductsByType(string type)
{}

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

Вам может понадобиться прочитать это: http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-and-action-selection

person cuongle    schedule 27.09.2012

Вам не нужно включать параметры запроса в маршрут. Должна быть только одна простая карта маршрутов для покрытия методов Http на всех ваших ApiControllers:

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

Единственный раз, когда вам нужно настроить маршруты, - это если вы хотите переместить параметр в фактический путь, чего вы, похоже, не делаете. Тогда ваш метод GET http для поиска по двум полям будет таким:

public IEnumerable<Product> Get(string name, string type){
    //..your code will have to deal with nulls of each parameter
}

Если вы хотите явно искать по одному полю за раз, вам следует подумать об использовании разных контроллеров для разных целей. То есть, SearchProductByTypeController, у которого есть единственный метод Get(string type). Тогда маршрут будет /api/SearchProductByTypeController?type=gadget.

person Nick    schedule 27.09.2012
comment
Спасибо, иногда проблема не в коде, а в архитектуре. ;) - person rickythefox; 27.09.2012
comment
Что за ресурс SearchProductByTypeController? :П - person mo.; 01.03.2013

попробуйте заменить string.Empty на RouteParameter.Optional

person hagensoft    schedule 27.09.2012
comment
RouteParameter заставил бы меня использовать такие URL-адреса, как /products/abc, что, конечно, не соответствовало бы требованию. Мне нужно иметь возможность использовать параметры строки запроса. - person rickythefox; 27.09.2012

Вы уверены, что контроллеры в порядке? Я имею в виду название параметров.

    public string GetProductsByName(string name)
    {
        return "Requested name: " + name;
    }

    public string GetProductsByType(string type)
    {
        return "Requested type: " + type;
    }
person laszlokiss88    schedule 27.09.2012