Наследяване на WebAPI контролер и маршрутизиране на атрибути

Имам няколко контролера, които наследяват от същия базов клас. Сред различните действия, които не споделят помежду си, те имат няколко, които са напълно идентични. Бих искал да ги имам в моя базов клас, защото всички те работят напълно еднакво, просто се осъществява достъп по различни маршрути.

Как да дефинирам тези действия с няколко различни маршрута?

Моите наследени класове също имат RoutePrefixAttribute набор върху тях, така че всеки от тях сочи към различен маршрут.

Пример

Имам базов абстрактен клас, наречен Vehicle и след това наследен Car, Bike, Bus и т.н. Всички те биха имали общо действие Move()

/bus/move
/car/move
/bike/move

Как мога да дефинирам действие Move() на моя базов клас Vehicle, така че да се изпълнява на всеки маршрут на подклас?


person Robert Koritnik    schedule 28.04.2014    source източник
comment
Опитвали ли сте да създадете базов клас, наследен от APIController, и след това вашите контролери, наследени от базовия клас. Не мисля, че наличието на различни маршрути прави разлика в този случай.   -  person Guanxi    schedule 28.05.2014
comment
И какво има? vehicle/move за всички тях?   -  person Robert Koritnik    schedule 28.05.2014
comment
Планирате ли да замените Move() в дъщерните класове?   -  person Nkosi    schedule 11.01.2016
comment
@Nkosi: Не, те ще бъдат дефинирани в базовия клас и само там, но трябва да се изпълняват по различни маршрути на дъщерните класове... Може да се окаже, че при някои специални обстоятелства ще ги отменям, но това ще се прави рядко. Замяната така или иначе ще дефинира нов маршрут, така че това не би трябвало да е проблем.   -  person Robert Koritnik    schedule 12.01.2016
comment
Тогава в такъв случай проверете отговора, който публикувах по-долу   -  person Nkosi    schedule 12.01.2016


Отговори (2)


Проверете отговора, който дадох тук WebApi2 атрибут, маршрутизиращ наследени контролери, който препраща към отговора от тази публикация .NET WebAPI Маршрутизиране и наследяване.

Това, което трябва да направите, е да презапишете DefaultDirectRouteProvider:

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

След като направите това, трябва да го конфигурирате в конфигурацията на вашия уеб API:

public static class WebApiConfig {
    public static void Register(HttpConfiguration config) {
        .....
        // Attribute routing (with inheritance).
        config.MapHttpAttributeRoutes(new WebApiCustomDirectRouteProvider());
        ....
    }
}

След това ще можете да направите това, което описахте по следния начин:

public abstract class VehicleControllerBase : ApiController {
    [Route("move")] // All inheriting classes will now have a `{controller}/move` route 
    public virtual HttpResponseMessage Move() {
        ...
    }
}

[RoutePrefix("car")] // will have a `car/move` route
public class CarController : VehicleControllerBase { 
    public virtual HttpResponseMessage CarSpecificAction() {
        ...
    }
}

[RoutePrefix("bike")] // will have a `bike/move` route
public class BikeController : VehicleControllerBase { 
    public virtual HttpResponseMessage BikeSpecificAction() {
        ...
    }
}

[RoutePrefix("bus")] // will have a `bus/move` route
public class BusController : VehicleControllerBase { 
    public virtual HttpResponseMessage BusSpecificAction() {
        ...
    }
}
person Nkosi    schedule 12.01.2016
comment
Мисля, че някои от тези сигнатури на метода са се променили в MVC 5.2.3 и този отговор изглежда вече не работи за мен. - person Jon Gunter; 04.04.2018
comment
Все още използвам това в производствения код на същата версия. Задайте нов въпрос, показващ какво не работи за вас и ни оставете да видим дали можем да разрешим проблема - person Nkosi; 04.04.2018
comment
Няма ли да работи и ако дефинирам само метода Move в основния контролер без WebApiCustomDirectRouteProvider? Опитах този подход в моя код и той проработи. - person Junlong Wang; 18.05.2020

Това направих и работи по начина, който споменахте във вашия въпрос.

Създадох базов клас ApiController и наследих всичките си API контролери от него. Дефинирах операция за изтриване в моя базов клас (който връща string „Не се поддържа“) и не дефинирах изтриване на нито един от моите дъщерни контролери. Сега, когато правя изтриване на който и да е от моите контролери, получавам съобщението „Не се поддържа“, т.е. извиква се изтриването на основния клас. (Правя заявка за изтриване на дете, а не на база, т.е. /Bike/move)

Но ако дефинирам Delete на който и да е контролер, това ми дава предупреждение за Hiding base implementation, но при извършване на Delete request за api получавам - "An error has occurred."

Не съм опитвал да направя RoutePrefix начин.

person Guanxi    schedule 30.05.2014
comment
Предполагам, че сте дефинирали вашето маршрутизиране централно по класическия начин (controller/action/id, което правехме в MVC) и не използвате декларативно маршрутизиране с помощта на атрибути? Тъй като нямам толкова голям проблем с общата функционалност на контролера, тъй като имам проблеми с декларативното маршрутизиране на моите общи функции, които трябва да са достъпни чрез дъщерни дефиниции за маршрутизиране... - person Robert Koritnik; 12.01.2016