Nano ASP.NET SaaS Boilerplate
Please allow a few seconds if the app is booting from a cold start.
Admin credentials (all tenants): admin@email.com / Password123!
Sample data resets every hour
Nano ASP.NET SaaS Boilerplate
General
.NET Solution
Vue UI
React UI
Razor Pages
.NET Solution

Application Services

Taking a look at an application CRUD service, the Product Service is a good way to quickly gain a familiarity with the project. Application services consist of business logic and are found in Application within /Services folder.

The Product Service

The Product Service is a sample CRUD service. Within /Services/ProductService, you’ll find the ProductSevice class and the interface IProductService. Classes which support this service are contained in subfolders DTOs, Filters, and Specifications. While you aren’t forced to organize services in any particular way, this way can serve as guide for creating your own.

The Product Service contains the following methods:

GetProductsAsync

Method to return a full list. Accepts a keyword string filter

GetProductsTanstackPaginatedAsync

Method to return a paginated list. Accepts a ProductTableFilterTanstack and returns a PaginatedResponseTanstack. The request and return formats are specific to Tanstack Table v8, which is the table component used in Vue / React projects.

GetProductsJQDTPaginatedAsync

Method to return a paginated list. Accepts a ProductTableFilterJQDT and returns a PaginatedResponseJQDT. The request and return formats are specific to JQuery Datatables which is the table component used in the Razor project.

GetProductAsync

Method to get a single product by ID. Accepts a Guid, returns Response with a ProductDTO

CreateProductAsync

Method to create a new product. Accepts a CreateProductRequest and returns Response with a Guid of the newly created product

UpdateProductAsync

Method to update a product. Accepts an UpdateProductRequest and returns Response with a Guid of the updated product

DeleteProductAsync

Method to delete a product. Accepts a Guid and returns Response with a Guid of the deleted product.

Service Registration

By inheriting IProductService from ITransientService, the Product Service is dynamically registered as a transient service.

Response Objects

All responses are wrapped with either a Response or a PaginatedResponse class, which can be found in Application/Common. These objects contain a data property for the actual response data in addition to metadata like error messages, success or fail, or pagination data. Using response objects make API responses consistent and easy to manage on the front-end.

Querying Data

Data retrieval and persistence is the responsibility of the generic repository in Infrastracture/Persistence. Application services use the repository via IRepositoryAsync and dependency injection. Low level data operations like mapping entity to DTO classes, pagination, sorting and filtering is contained within the generic repository and doesn’t need to be repeated in services.

This boilerplate uses the specification pattern. To query data, build an Ardalis specification class with the filter criteria and pass that to the repository method. The repository will evaluate the specifications and return filtered data. Using specifications allows you to encapsulate and reuse query code.

Paginated Data

The reason for there being two pagination methods is that the React / Vue projects use Tanstack Table v8. Due to framework limitations, the Razor project uses JQuery Datatables.

For client-side pagination, both table libraries paginate data the same way, using a full list. For server-side pagination however, the tables differ slightly in the way they expect data and return a response. For that reason, table-specific methods are present with their own filters and response wrappers.

Column sorting is also particular to each table. Both table libraries allow a user to dynamically sort columns and even select multiple columns for sorting. In Application/Utility a NanoHelpers class contains methods specific to each kind of table to parse sort order into a generic string.  An extension method in Ardalis specification can evaluate these generic strings and dynamically build the query with sorting.

If you know that you will only need Tanstack Table, you can remove everything related to JQuery Datatables, or vice versa.

Next Steps

Continue on with the following guides: Authentication & Authorization, Multi-Tenancy, and Persistence & Infrastructure.