Being part of a community means being inspired by other folks’ work to learn, get better, and add our value back in. When I read Jeremy Miller’s Oakton post about running development-time commands, I was inspired to contribute. Being hosted in ASP.NET, it also reminded me of Andrew Lock’s ApiExplorer about introspecting our API and learning more about the make-up of our applications.
In this post, we’ll use both Oakton and ApiExplorer to build a development-time command to list all the routes in our app directly into our console. For bonus points, we’ll also use JetBrains Rider to display them in our IDE’s terminal.
List Routes Command
We can start by cloning Jeremy’s GitHub repository sample. We’ll be supplementing the existing action with our new ListRoutesCommand
. We will also need to install ConsoleTables.
> dotnet install ConsoleTables
Let’s add the ListRoutesCommand
class now. We’ll explain the different parts afterwards.
[Description("List all routes in web api")]
public class ListRoutesCommand : OaktonCommand<NetCoreInput>
{
public override bool Execute(NetCoreInput input)
{
using var host = input.BuildHost();
var serviceType = typeof(IApiDescriptionGroupCollectionProvider);
if (!(host
.Services
.GetService(serviceType) is IApiDescriptionGroupCollectionProvider explorer))
return true;
var results = explorer
.ApiDescriptionGroups
.Items
.SelectMany(x => x.Items)
.Select(x => new
{
x.RelativePath,
x.HttpMethod,
Controller = x.ActionDescriptor.RouteValues["controller"],
Action = x.ActionDescriptor.RouteValues["action"],
Parameters = string.Join(", ", x.ParameterDescriptions.Select(p => $"{p.Name} ({p.Type.Name})"))
})
.ToList();
Console.Clear();
Console.WriteLine();
ConsoleTable
.From(results)
.Write();
return true;
}
}
The fantastic part of Oakton is that it allows us access to our ASP.NET application, which gives us access to all our dependency injection services. Having access to the ServiceCollection
means we can request an instance of IApiDescriptionGroupCollectionProvider
which describes our API endpoints.
We need to map some of the more important values of our API into a collection, which we’ll use to write out to the console output window.
var results = explorer
.ApiDescriptionGroups
.Items
.SelectMany(x => x.Items)
.Select(x => new
{
x.RelativePath,
x.HttpMethod,
Controller = x.ActionDescriptor.RouteValues["controller"],
Action = x.ActionDescriptor.RouteValues["action"],
Parameters = string.Join(", ", x.ParameterDescriptions.Select(p => $"{p.Name} ({p.Type.Name})"))
})
.ToList();
Console.Clear();
Console.WriteLine();
ConsoleTable
.From(results)
.Write();
We can now run our listroutes
command from the command-line.
> dotnet run listroutes
We can expect to see the following output.
Awesome!
JetBrains Rider Runner
If we’re users of JetBrains Rider, we can set up our IDE to run the command using a build configuration. We first need to edit our build configurations.
We follow it up by adding a new .NET Project configuration using the + symbol.
We can then add our Oakton command as one of the program arguments. In our case, it will be listroutes
.
Finally, we can run our command like we would any build command and see the results in a new run window.
The ability to push a button should make the GUI lover in all of us very happy. We could also promote our runner to a launch setting so our team can share in all this great value.
Conclusion
It’s always fun to be inspired and spike a new idea. Oakton seems like a compelling addition to any ASP.NET project, especially for those looking to automate their development process. I hope you found this post fun, and leave a comment below if you have your ideas for Oakton development commands.