14

I have few controllers that inherit from the same base class. Among the different actions that they don't share with each other, they do have a few that are completely identical. I would like to have these on my base class because they all work completely the same it's just that they're accessed through different routes.

How should I define these actions with several different routes?

My inherited classes also have a RoutePrefixAttribute set on them so each of them is pointing to a different route.

Example

I have base abstract class called Vehicle and then inherited Car, Bike, Bus etc. All of them would have common action Move()

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

How can I define action Move() on my base class Vehicle so that it will be executed on each subclass route?

5
  • Have you tried creating a base class inherited from APIController, and then your controllers inherited from the base class. I don't think having different routes make a difference in this case. Commented May 28, 2014 at 18:48
  • And have it what? vehicle/move for all of them? Commented May 28, 2014 at 19:27
  • Are you planning to override the Move() in the child classes? Commented Jan 11, 2016 at 17:05
  • @Nkosi: No they would be defined on the base class and there only, but should be executed under different routes of the child classes... It may be that in some special circumstances I would be overriding those but that will be seldom done. Overriding would define new route anyway so that shouldn't be a problem. Commented Jan 12, 2016 at 10:31
  • Then in that case check the answer I posted below Commented Jan 12, 2016 at 11:47

2 Answers 2

20

Check the answer I gave here WebApi2 attribute routing inherited controllers, which references the answer from this post .NET WebAPI Attribute Routing and inheritance.

What you need to do is overwrite the 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);
    }
}

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());
        ....
    }
}

You will then be able to do what you described like this:

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() {
        ...
    }
}
Sign up to request clarification or add additional context in comments.

3 Comments

I think some of these method signatures have changed in MVC 5.2.3 and this answer no longer seems to work for me.
I am still using this in production code on that same version. Ask a new question showing what is not working for you and let us see if we can solve the problem
Wouldn't it also work if I only define the Move method in the base controller without the WebApiCustomDirectRouteProvider? I tried this approach in my code and it worked.
0

This is what I did and it worked the way you mentioned in your question.

I created base ApiController class and inherited all my API controllers from it. I defined Delete operation in my Base class (which returns string "Not Supported") and didn't define delete on any of my child controller. Now when I do a delete on any of my controller I get the message "Not Supported" i.e. Base class's delete is called. ( I am doing Delete request on Child, and not on base i.e. /Bike/move)

But if I define a Delete on any of the controller it gives me warning of Hiding base implementation, but on doing Delete request for api I get - "An error has occurred."

I haven't tried doing RoutePrefix way.

1 Comment

I suppose you've defined your routing centrally in the classic way (the controller/action/id we used to do in MVC) and not using declarative routing using attributes? Because I'm not having that much of a problem with common controller functionality as I have problems with declarative routing of my common functions that should be accessible through child routing definitions...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.