Adding a New Feature
Let's explore how to add a new feature to your project.
If you have any questions, you can ask them at GitHub Discussions or wiki.bitplatform.dev.
1. Creating the Entity (Server.Api project)
The process begins by creating an Entity in the Server.Api project. The model we're considering here is Category.cs in the Models folder. You can move Models out of the API project if you wish, their presence there is not mandatory.2. Adding to DbContext & Configuration (Server.Api project)
Next, add it as a DbSet to AppDbContext in the Data folder of the Server.Api project:public DbSet<Category> Categories { get; set; } = default!;
3. Creating the DTO (Shared project)
The next step is to create CategoryDto.cs in the Dtos folder of the Shared project. This is where multi-language support becomes important. You can simplify this using DtoResourceType, which has explanatory comments on the class itself. For example, the Name property is defined as follows:[Required(ErrorMessage = nameof(AppStrings.RequiredAttribute_ValidationError))] [Display(Name = nameof(AppStrings.Name))] [MaxLength(64, ErrorMessage = nameof(AppStrings.MaxLengthAttribute_InvalidMaxLength))] public string? Name { get; set; }
This Required validation, stating that Name cannot be empty, is checked both on the server and on the client, and the error on the form is displayed in the user's selected language. By default, you only need to enter your primary language in AppStrings.resx in the Resources folder of the Shared project (default is English, but you can change its content entirely). Translation for other languages is not necessary. If you look at the cd.yml file in the .github/workflows or .azure-devops/workflows folder, it will handle the translation of other languages using an OpenAI API Key from Gemini, GTP, or DeepSeek, based on the Bit.ResxTranslator.json file located in the project root. Thus, the project can support multiple languages when published. If you're not satisfied with the automatic translation, you only need to correct that specific item for that language. For instance, if you look at the Swedish language file, it has far fewer items.
More details can be found here: Bit Resx Translator
4. Adding DTO to AppJsonContext (Shared project)
The next step is to add CategoryDto to AppJsonContext.cs. This is done to improve application performance.[JsonSerializable(typeof(CategoryDto))]
5. Creating the Controller Interface (Shared project)
The next step is to add ICategoriesController.cs in the Controllers folder of the Shared project. The philosophy behind having these controllers in the Shared project is explained in the Shared/Controllers/ReadMe.md file.6. Creating the Mapper (Server.Api project)
The next task is to create a Mapper on the server side. This project uses Mapperly, but you can perform mappings between DTOs and Models manually or with other libraries. To do this, add the corresponding mapper in the Mappers folder of the Server.Api project. The ReadMe.md file in that folder contains helpful explanations.7. Creating the Controller (Server.Api)
The next step is to create the Controller in the Controllers folder of the Server.Api project, which uses Entity Framework Core DbContext and OData. If you intend to move the application logic to a Service layer, use Onion Architecture, or employ MediatR, the choice is yours. The default code in the Boilerplate project focuses on providing features and on architectural aspects where C# .NET Developers might have less experience, such as writing code once for multiple platforms or the necessary structure for writing E2E / UI tests. The backend code architecture is left to you.Regarding OData, note that it does not use the old, highly complex OData model where you must inherit from ODataController. Instead, it uses a new, lightweight, and simple way of using OData. To get started, simply add [EnableQuery] above your Get actions, allowing you to query them from the client side.
By returning an IQueryable from Entity Framework Core, in the Data Grid and Pagination example, only the necessary amount of data is retrieved from the database. Using ProjectTo (or `Select` with manual projection) instead of mapping after fetching entities ensures that only CategoryDto objects are created and streamed to the client, providing the highest possible performance.
8. Client-Side: Adding the Page URL
For the client side, first, add the desired page address to Urls.cs (typically in the Client.Core project).9. Client-Side: Creating Page Files
Then, you add the CategoriesPage.razor, CategoriesPage.razor.cs, and CategoriesPage.razor.scss files (typically in the Client.Core/Pages folder).In CategoriesPage.razor.cs, you can fetch data from the server-side Controller using ICategoriesController, eliminating the need to use HttpClient directly.
Final Notes & Further Help
If you have any questions, you can ask them at GitHub Discussions or wiki.bitplatform.dev.A deeper understanding of Blazor, ASP.NET Core Web API, Entity Framework Core, HTML, and SCSS can greatly help in better understanding the bit Boilerplate code. Note that the feature you add will work on all platforms from day one. For Android, the only optional step is to add the page URL to the MainActivity.cs file in the Client.Maui project, under the Platforms/Android folder to enable universal deep web links for the new page.