Source generators and a boilerplate code
Source generators first were introduced in C# 9.0 in Spring 2020 as a new compiler feature that lets developers to generate new C# source code that can be added to a compilation. Using it you can inspect code with all of the rich metadata that the compiler builds up during compilation, then emit C# code back into the same compilation that is based on the data you’ve analyzed. If you’re familiar with Roslyn Analyzers, you can think of Source Generators as analyzers that can emit C# source code. It is a powerfull developers tool, that can augment you code starting from generation custom serializations and ending with generated fast dependency injection containers.
Code refactoring is one of the processes when developers maintain applications to minimize technical debth, refresh libraries used or maintain code readability. The main drawback of the boilerplate code is blackout the business logic: instead of analysis of functionality programmers need also to find it among overall code.
Here I’d like to introduce 3 libraries written by myself that are based on Source Generators features: SourceMapper, SourceConfig and SourceApi and are aimed to decrease boilerplate code in solution. An idea of each of the packages is to autogenerate code with some functionalities that can be used in code.
During my work on different cloud-native applications with a various tech stacks I’ve paid attention to Java’s widely used mapping library MapStruct, where developers define mappings using Java annotations (in C# we call it attributes). Using Source Generators we can implement mapper, that generates mappings based on C# attributes actually during coding. It can be installed using Nuget Package Manager:
For example, definition of UserDao mapping to UserInfo object can be defined in interface, ClassName — defines the target mapper class name that is generated:
Destination code for UserMapper class than generated and can be used in solution:
Dependency injection extension code for various .NET containers also generated based on the Dependency Injection container you’ve been used in project. In this way you can inject mappers in your services, controllers or repositories and stay clean with Domain, DTO and DAO transformations in solution.
More about using, extending can be found on GitHub.
SourceConfig package uses Source Generators Additional File Transaformation feature to generate additional code. The idea of this package is simple: instead of creating POCO classes for configuration in you project, the package generates these objects intead of you. First lets intall it:
After that, even if you have few configs for different enviromnets, thay are merged in one class. Lets assume, that you have appsettings.json configuration file:
and for development environment appsettings.development.json:
All you need, is to add them as C# analyzer additional file in Visual Studio:
or in your *.cproj file:
This will generate object for you configuration and you do not need to stay in sync when new configuration properties will be added to teh files: thay will apppear in you class automatically!:
Source code and more, of course, on SourceConfig GitHub.
There are two approaches when implemening Web API: code first, that most of developers prefer: to create Web API controllers, DTO’s, to add Swagger UI and that’s all!; and API first, when API needs to be designed or discussed and only after that we start to implement it. In distributed systems with a various technologies and consumers of our API it is good to have language agnostic tools to agree and share API between the consumers. Open API Specification has been created for that:
The OpenAPI Specification (OAS) defines a standard, language-agnostic interface to RESTful APIs which allows both humans and computers to discover and understand the capabilities of the service without access to source code, documentation, or through network traffic inspection.
The third library, that I called SourceApi created for API first approach: you (or your team) define API in yaml or json format, add it to Web API project and the package generates Controller base classes with DTO’s and documentations for your API. All you need, is to implement logic in controllers. You even do not need to create DTO’s, since it already generated.
For example, for Opan API defined in
thus, StoreControllerBase class is generated as:
and can be used as base abstract class for your Web API controller. You only need to concentrate on implementation logic instead of definitions of response codes, stay in sync with DTO’s, etc. When you change Open API definition file, the base abstract class and DTO’s are refreshed.
Some configuration properties also added to the package: you can define the namespace of your base controllers, or you can generate only DTO’s in a case when you are the consumer of some REST API.
Source code and documentation can be found on SourceApi GitHub.