Sebazzz/SDammann.WebApi.Versioning

Inherting from VersionedApiControllerSelector

Opened this issue · 7 comments

I'm trying to create a custom versioning scheme that will allow a controller to "fall through" to a previous version of a controller if one is not defined for a particular version. This will allow me to only make classes in the new namespace when there are actual changes to that class. anything that stays the same will continue to work from the same code.

I would like to inherit from VersionedApiControllerSelector and create my own implementation of this class. This has some issues as this is the entry point into a lot of the code and many of the classes in the library are marked as internal or private.

I would consider changing the private variables in this class to protected. also the InitializeControllerInfoCache to a protected virtual method.

I could create a pull request with some changes that would make this easier to extend (from my perspective at least)

The reason those types are either private or internal is that primary means of extension is supposed to be through IControllerVersionDetector and friends. I realise that this does not fit your use case.

Instead of changing the accessibility of those members, perhaps it is better to introduce an type or interface which would allow handling of the event when a controller is not found. Then you could for example delegate a version number back (one lower than the version as requested in the current request) and the controller selection process would start over but with that overridden version number.

Note that your scenario is actually possible by using inheritance. For example, CatController version 2 could inherit from CatController version 1. Or both CatController from the same base class.

I am having the same need.

I would like to introduce an interface which would be used by VersionedApiControllerSelector to match a cached (available controller) with the version asked by the current request. Its default implementation may be on an exact version match (as it is now in OnSelectController).

Having this one could setup the library with a custom implementation of this interface and she could do her custom logic of falling back or falling forward. It would be preferable that this interface receives an more complex data structure with cached controllers so one could get (with high performance) all versions of a controller name, which are higher or equal than 2.5 but lower than 3.

What is the exact use case? You have explained the 'how' and the 'what' but I'm missing why. Don't understand me wrong here: I am only trying to understand why you need such construction. :) Thanks.

There are two cases I'm thinking of:

  1. I would like not to move all the controllers in version namespaces from the start, but to leave the ones that didn't change in the root and to fallback to them
  2. Use SemVer somehow similar with nuget packages. First digit increases at blocking changes, second when functionality is added, but backwards compatible. Now a client that requests 2.5 I will give it any version (available) which fits the interval [2.5, 3). This may help to reduce the number of versions that I keep on the server. If I see in my logs that I am almost never give version 2.5 I can just drop it.

My use case was I have 50+ controllers, and when I make breaking changes to
1 controller, I don't want to go make 50 more controllers in a different
namespace to make a new version just to break one.
On Jun 13, 2015 4:07 AM, "Florin Coros" notifications@github.com wrote:

There are two cases I'm thinking of:

  1. I would like not to move all the controllers in version namespaces
    from the start, but to leave the ones that didn't change in the root and to
    fallback to them
  2. Use SemVer somehow similar with nuget packages. First digit
    increases at blocking changes, second when functionality is added, but
    backwards compatible. Now a client that requests 2.5 I will give it any
    version (available) which fits the interval [2.5, 3). This may help to
    reduce the number of versions I keep on the server. If I see in my logs
    that I am almost never give version 2.5 I can just drop it.


Reply to this email directly or view it on GitHub
#49 (comment)
.

Sorry for the late response, but I had some thought over this to figure out a solution.

This solution would be:

  • Possibility to handle an 'ControllerNotFound' event, let's say, covered in a IControllerNotFoundHandler. This would be called when a controller cannot be found.
  • The IControllerNotHandler.OnControllerNotFound would be passed the requested ApiVersion and ControllerIdentification, and an instance of IControllerLookup. It returns in HttpControllerDescriptor or may throw an exception.
  • IControllerLookup would be implemented by VersionedControllerSelector. It would accept a ControllerIdentification and return an HttpControllerDescriptor. If the requested controller cannot be found null is returned in this case (or call IControllerNotHandler again, I'm not sure what the best approach is here).

For you sake the implementation of an IControllerNotFoundHandler would be to decrease the version number and pass it to the supplier IControllerLookup.

Does this sound like a good approach? Any comments?

It sounds good. Maybe after we'll see some code it will be even more clear.

A few comments:

  • I'd like to be able to pass to the IControllerLookup a controller name and to get back all its versions. With this I can decide which one to return based requested version and available controllers.
  • Maybe I would make the VersionedControllerSelector to also use the IControllerLookup, rather then to implement it. And make IControllerLookup implementation to wrapp the _controllerInfoCache. This is just an implementation detail to avoid a circular a dependency.

Thank you!