2018-08-16

Swashbuckle custom ordering of controllers

By default, Swagger (or rather: Swashbuckle) orders the documentation of controllers by controllername. So if you have a FooController, BarController and BazController they will be ordered as Bar, Baz, Foo in the swagger UI. Let's change that.

Swashbuckle offers an option to order the "ActionGroups" as these are called using the OrderActionGroupsBy method. However, this method expects an IComparer<string> which doesn't offer much flexibility by itself other than ordering alphabetically in ascending or descending order. There's not much more creative we can get with this rather simple interface. Or... can we?

I was hoping to be able to add some attributes to my controllers to set the order manually but couldn't find any possibilities to do so, so I implemented it. The idea is simple: we'd like to have an attribute we can slap on a controller to influence the order the controller should be documented in. That's about it.

So, first we will need to implement our attribute:

Now we can annotate our controllers with this attribute:

Now, we need a class that implements IComparer<string> but somehow, magically, knows how to get to the attributes on the controllers. The plan is as follows: we create a dictionary with controllersnames and the desired order as key/value pairs. We keep a reference to this dictionary around. When the Compare(string x, string y) method is called we first check our dictionary to see if we have a specific order for controller X and/or controller Y and compare them. If the orders are equal we fall back to comparing the names; in all other cases we simply return the result of the comparison of the order values. The question is: how do we populate this dictionary?

Well, there are 2 options actually. First, in our SwaggerControllerOrderComparer, as we'll call it, we could use some reflection to figure out all controllers in the assembly. That works quite nicely and is the simplest to use. However, another option would be that the calling code provides the controllers we want to sort using this method so we have better control of how the assembly is scanned for controllers. This resulted in a SwaggerControllerOrderComparer with two constructors; one which accepts the assembly to scan for controllers and one which accepts an IEnumerable<Type> that can be used to pass in specific controllers.

With that out of the way, all we need to do is tell Swashbuckle to use our comparer:

And that's it! Enjoy your custom ordered controllers!