Persistence & Infrastructure
This guide will cover persistence and any infrastructure not already covered in the Authorization & Authentication or Multi-Tenancy guides.
The Repository
The RepositoryAsync class in Infrastructure/Persistence/Repository, is a generic repository responsible for all low level data operations. It’s implemented via IRepositoryAsync in Application/Common and can be used by application services via dependency injection. RepositoryAsync uses the ApplicationDbContext.
All methods have multiple overrides and can return data as entities or mapped DTOs. DTO mapping is handled by Automapper using projection to efficiently map domain entities and related data onto DTOs. Mapping configuration is defined in MappingProfiles in Infrastructure/Mapper.
To query data, any service can pass a specification object to the repository methods which will then be evaluated by Ardalis specification. Specification objects can contain filters, sorting, or any kind of criteria. Using the specification pattern is a great way to encapsulate query logic, making it reusable and easy to maintain.
Pagination is another low level data operation that is handled by the repository. There are two methods for returning paginated data GetTanstackPaginatedResultsAsync and GetJQDTPaginatedResultsAsync which differ slightly in the request and response format as needed by the table plugins.
Migrations & DB Contexts
There are two DB contexts which are used for actual data persistence, BaseDbContext and ApplicationDbContext, and one auxiliary context, TenantDbContext. These contexts are explained in detail in the Multi-Tenancy guide.
Migrations are handled per context found in Infrastructure/Persistence/Migrations. Initial migrations are already created. Any pending migrations will apply automatically on app start.
When creating migrations:
- Select Infrastructure as the default project in Package Manager Console
- Use the add-migration command with -Context to specify DB context and -o to specify output.
- Running the application will apply any pending migrations. To explicitly run migrations, use the update-database with the -Context switch
add-migration -Context BaseDbContext -o Persistence/Migrations/BaseDb Base-NewMigration
add-migration -Context ApplicationDbContext -o Persistence/Migrations/AppDb App-NewMigration
If using Rider, specify –project AspNano.Infrastructure and -s AspNano.WebApi
Db Initializer
This database seeder class contains the SeedTenantAdminAndRoles method which is run on app start if no root tenant is found in the default database. This method will create a root tenant, roles, and root admin user.
Mapper
Automapper is a third party NuGet package that provides DTO to domain entity mapping. It requires rules to be defined for each DTO / entity relationship. Add mapping rules in Infrastructure/Mapper/MappingRules when you create new entities and DTOs.
Mailer
MailKit is third party NuGet package that facilitates sending emails in .NET applications. Mail settings are defined in appsettings.json. Sign up for free email testing at Ethereal and replace the provided keys with your own.
Images & Files
The CloudinaryService uses the Cloudinary .NET SDK which is a third party NuGet package. Cloudinary is a digital asset management platform, which provides programmatic control of images and files on external storage. For the majority of cases, storing images and files on an external service is better than managing locally. There are many options for managing digital assets; Cloudinary is merely one example, albeit a good one.
Cloudinary settings are found in appsettings.json. If you use Cloudinary, sign up for the free tier and replace the provided keys with your own.
Next Steps
If you’ve purchased the full version with UI projects, continue on to the Vue project or React project documentation to start learning about them. Or, check out the Razor project documentation to see what changes it brings to the .NET solution.