Consolidated Data Access
The biggest feature of this release is the introduction of a new consolidated data access repository that simplifies working with Cofoundry data programmatically.
IContentRepository
IContentRepository
is the primary interface for our new data access API. It has an easily discoverable fluent API and is enriched with inline documentation to help you choose the most suitable query or command for you needs.
This example uses the fluent builder to describe the query we want and select how much detail is returned by selecting the projection type:
using Cofoundry.Domain;
public class ExampleController : Controller
{
private readonly IContentRepository _contentRepository;
public ExampleController(
IContentRepository contentRepository
)
{
_contentRepository = contentRepository;
}
[Route("/api/categories-example")]
public async Task<IActionResult> Categories()
{
var categories = await _contentRepository
.CustomEntities() // select entity type
.GetByDefinition<CategoryCustomEntityDefinition>() // select query type
.AsRenderSummary() // select projection
.ExecuteAsync(); // execute
return Json(categories);
}
}
As you build the query, you can use the intellisense hints provided by our XML comments to understand the difference between different queries or projection types:
This example uses an MVC controller, but you can use this interface anywhere that supports dependency injection just by requesting an instance of IContentRepository
.
IAdvancedContentRepository
We designed IContentRepository
to be noise-free and only include the most common queries you might use in a website, however, we have also created IAdvancedContentRepository
, which builds upon IContentRepository
and includes the full range of queries and commands available in Cofoundry.
Other Features
Both repositories can be extended via extension methods, so that plugins can light-up additional data access paths.
They also share the following features:
Here's an example combining a few of these features, which prior to this release would have required dependencies on 7 different services to be injected:
public async Task RegisterUser(string email, string password)
{
var exampleRoleId = await _advancedContentRepository
.Roles()
.GetByCode(ExampleRole.ExampleRoleCode)
.AsDetails()
.Map(r => r.RoleId)
.ExecuteAsync();
using (var scope = _advancedContentRepository
.Transactions()
.CreateScope())
{
await _advancedContentRepository
.WithElevatedPermissions()
.Users()
.AddAsync(new AddUserCommand()
{
Email = email,
Password = password,
UserAreaCode = MemberUserArea.AreaCode,
RoleId = exampleRoleId
});
// ...do some other things
await scope.CompleteAsync();
}
}
You can find out more in the data access docs.
Deprecations
Deprecated code will be removed in an upcoming release.
IAsyncCommandHandler, IAsyncQueryHandler
Handler names have been changed to remove the reference to "Async". When we used to target .NET Framework we needed sync handlers, but they are no longer necessary in .NET Core.
IAsyncQueryHandler
is nowIQueryHandler
IAsyncCommandHandler
is nowICommandHandler
Repositories
The individual entity repositories have now been replaced by IContentRepository
and are now marked as deprecated.
Breaking changes
Internal Namespace
We've started moving some code to an Internal
namespace to better indicate that these classes are not for general use. This includes classes such as handler and service implementations, which should not be referenced directly.
Although Microsoft are in the process of removing all their "Pubternal" namespaces, for us I think it's a good way to keep all our code accessible while clearly defining what is and is not part of the public API surface.
AssetFilesSettings
We've updated some of the terms used in asset file type validation to put them inline with current standards:
AssetFileTypeValidation.Whitelist
is nowAssetFileTypeValidation.Allowlist
AssetFileTypeValidation.Blacklist
is nowAssetFileTypeValidation.Blocklist
If you've customized AssetFilesSettings.FileExtensionValidation
or AssetFilesSettings.MimeTypeValidation
, you may need to update your settings.
PropertyValidationErrorException is now ValidationErrorException
We've improved some of our validation error classes in include a new ErrorCode
string property. This is useful in web APIs where the error is serialized, making it easier for JavaScript front-ends to handle specific types of validation errors.
To enable this feature we have restructured this area a little and PropertyValidationErrorException
has changed to be ValidationErrorException
TransactionScopeManager: default isolation changed from Serializable to ReadCommitted
The default transaction scope isolation of Serializable is not ideal and not aligned with the SQLServer default. We have therefore decided to change it to ReadCommited.
We've also added ways to override this behaviour by default and on a per-use basis. See the Transactions section of the docs for more information on how to do this.
Notice on .NET 5 and .NET 6
Having been burnt a little with the support cycle around .NET Core 2.2 we are now only going to target LTS .NET releases. This means that we will not move to .NET 5 and instead wait for the .NET 6 LTS release.
Bug fixes
- #383 Error loading page template detail page
Links
- Packages on NuGet
- Full 0.8.0 release notes on GitHub