Skip to content

Solution to generate dynamic APIs using the .NET Roslyn Compiler as a Service (CaaS). New CRUD APIs can be generated at runtime with calls to the entity factory service.

License

Notifications You must be signed in to change notification settings

thbst16/dotnet-roslyn-dynamic-api

Repository files navigation

dotnet-roslyn-dynamic-api

Build Status Docker Image Version (latest by date) Uptime Robot ratio (7 days)

Generates a dynamic REST-based API using the Roslyn Compiler as a Service (CaaS). API can be generated at startup by referring to an external file with class defintions or at runtime, by passing class defintions into the entity creation API. All APIs persist their data using an in-memory datastore.

Usage

The image below represents notionally how Roslyn is invoked to dynamically add new assemblies and the resultant APIs:

  • Static Allocation - Ons startup, only the Entity API is available. The API is served from the Base.dll. The Entity API contains a GET method to list the other APIs provisioned dynamically and a POST API method to create new APIs at runtime.
  • Dynamic Allocation - At process startup, a call is made to retrieve API definitions (C# classes) from a public Azure BLOB file. These service(s) are combiled by Roslyn into Dynamic.dll and served up as new APIs with their own GET and POST methods to store and access data.
  • Runtime Allocation - Calling the Entity POST method allows new APIs to be defined dynamically at runtime. The call accepts an API name and definition (C# classes) as parameters and uses Roslyn to dynamically compile these methods into a new assembly (Runtime.dll) that exposes GET and POST methods for the new API.

roslyn api allocations

In Action

The best way to understand what's going on is to look at the API documentation and invoke the API calls. All of the APIs that are generated below allow data persistence and retrieval for the resulting entites, with the API backed by an in-memory data store.

Static and Dynamic APIs

From the Swagger API documentation, you'll see that there are two APIs represented at startup time -- Entity and Book.

roslyn controller swagger

The entity controller is static and provides methods to get a listing of existing controllers or to generate new controllers. The Book controller is created dynamically using a reference to a specific public Azure BLOB file that defines all the APIs to be created dynamically at runtime. This file is read at process startup and controllers / APIs created for each of the defined classes. A GET call to the Entity API shows the current APIs.

roslyn initial apis

Runtime Generated APIs

Making a call to the POST method of the Entity API and passing a new entity name and C# class construct will cause Roslyn to create a new Controller / API at runtime.

roslyn new entity

This new entity is then reflected in the list of avaialble entities.

roslyn modified apis

And is also reflected in the Swagger API documentation.

roslyn modified controller swagger

Impact and Future

This project has, at it's kernel, all the functionality necessary to deal with rendering and managing a dynamic API with startup and runtime API definition capabilities. The hard work is done. What remains is several areas of refinement:

  • Configurability - Defining the API through an external file and requiring C# class definitions for dynamic and runtime API definition presents a very low level of abstraction for the user. These functions need to be moved to key-value pair defintions that can be passed via the API and persisted in a readily accessible online mechanism, such as a database.
  • Dynamic User Interface - The next step for dynamic generation capabilities is moving from APIs to user interfaces. Since the generation occurs at the controller level in ASP.NET Core, dynamic generation can be applied to any of the ASP.NET view technologies that use controllers. Ideally suited as a technology here is Server-hosted Blazor. This technology provides a dynamic front-end controlled by a single C# code base so that there's no need to generate seperate front-end Javascript code. Read here for a sense of what this may look like as html over websockets is exactly the technology that server-hosted Blazor uses.

Motivation and Credits

Code generation and metaprogramming with Roslyn, especially in conjuntion with ASP.NET Core, is one of the dark corners of the .NET landscape. Two articles in particular illuminated and informed me in my understanding of Roslyn:

About

Solution to generate dynamic APIs using the .NET Roslyn Compiler as a Service (CaaS). New CRUD APIs can be generated at runtime with calls to the entity factory service.

Topics

Resources

License

Stars

Watchers

Forks