We have designed and developed this library as an abstract base wrapper around the existing EntityFramework DbContext implementation to provide the following values:
- Meaningful exceptions for error codes
- Simplified integrations
- Test-friendly implementation
This solution consists of the following core projects:
- A STX.EFxceptions.Abstractions : Standardized .NET library that provides interfaces for the core components to capture exceptions thrown by EntityFramework and converts them into meaningful exceptions.
- A STX.EFxceptions.Core : Standardized .NET library that provides an abstract DBContext to capture exceptions thrown by EntityFramework and converts them into meaningful exceptions.
- A STX.EFxceptions.Identity.Core : Standardized .NET library that provides an abstract DBContext that implements AspNetCore.Identity to captures exceptions thrown by EntityFramework and converts them into meaningful exceptions.
This library was built according to The Standard. The library follows engineering principles, patterns and tooling as recommended by The Standard.
This library is also a community effort which involved many nights of pair-programming, test-driven development and in-depth exploration research and design discussions.
The most important fulfillment aspect in a Standard complaint system is aimed towards contributing to people, its evolution, and principles. An organization that systematically honors an environment of learning, training, and sharing knowledge is an organization that learns from the past, makes calculated risks for the future, and brings everyone within it up to speed on the current state of things as honestly, rapidly, and efficiently as possible.
We believe that everyone has the right to privacy, and will never do anything that could violate that right. We are committed to writing ethical and responsible software, and will always strive to use our skills, coding, and systems for the good. We believe that these beliefs will help to ensure that our software(s) are safe and secure and that it will never be used to harm or collect personal data for malicious purposes.
The Standard Community as a promise to you is in upholding these values.
This library provides the interfaces which are used by the core components to get error codes and provide meaningful exceptions.
This library provides an abstract DBContext which is used to capture exceptions thrown by EntityFramework and converts them into meaningful exceptions. Custom implementations for the various Entity Framework database providers should inherit from this abstract class.
This library provides an abstract DBContext that inherits from Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityDbContext
which is used to capture exceptions thrown by EntityFramework and converts them into meaningful exceptions.
Custom implementations for the various Entity Framework database providers that make use of Microsoft.AspNetCore.Identity should inherit from this abstract class.
These core libraries are designed to be used as a base class for your DbContext implementation. If you would like to create your own custom DbContext implementation, you can inherit from the abstract base class provided by this library.
Lets use SQL Server as an example. If you would like to create a custom implementation that uses SQL Server, you can inherit from the abstract base class provided by this library.
public class EFxceptionsContext : DbContextBase<SqlException>
{
protected override IDbErrorBroker<SqlException> CreateErrorBroker()
{
return new SqlErrorBroker();
}
protected override IDbErrorBroker<SqlException> CreateErrorBroker() =>
new SqlServerErrorBroker();
protected override IEFxceptionService CreateEFxceptionService(IDbErrorBroker<SqlException> errorBroker)
{
return new SqlServerEFxceptionService<SqlException>(errorBroker);
}
}
Next we will have to do an implementation of the IDbErrorBroker
interface. This broker is used to get the error code for the exceptions that can be thrown by EntityFramework.
public interface ISqlServerErrorBroker : IDbErrorBroker<SqlException>
{ }
public class SqlServerErrorBroker : ISqlServerErrorBroker
{
public int GetErrorCode(SqlException exception) => exception.Number;
}
Finally, we will have to do an implementation of the IEFxceptionService
interface and service. This interface and service is used to provide the meaningful exceptions for the various error codes that can be thrown by EntityFramework.
public interface ISqlServerEFxceptionService : IEFxceptionService<SqlException>
{ }
public class SqlServerEFxceptionService<TException> : ISqlServerEFxceptionService
{
public SqlServerEFxceptionService(IDbErrorBroker<TException> errorBroker) : base(errorBroker)
{ }
public void ThrowMeaningfulException(SqlException sqlException)
{
ValidateInnerException(sqlException);
SqlException innerException = GetException(sqlException.InnerException);
int errorCode = this.errorBroker.GetErrorCode(innerException);
ConvertAndThrowMeaningfulException(sqlErrorCode, dbException.Message);
throw dbUpdateException;
}
private void ValidateInnerException(SqlException sqlException)
{
if (SqlException.InnerException == null)
{
throw sqlException;
}
}
private void ConvertAndThrowMeaningfulException(int code, string message)
{
switch (code)
{
case 207:
throw new InvalidColumnNameSqlServerException(message);
case 208:
throw new InvalidObjectNameSqlServerException(message);
case 547:
throw new ForeignKeyConstraintConflictSqlServerException(message);
case 2601:
throw new DuplicateKeyWithUniqueIndexSqlServerException(message);
case 2627:
throw new DuplicateKeySqlServerException(message);
}
}
private SqlException GetSqlException(Exception exception) => (SqlException)exception;
If you have any suggestions, comments or questions, please feel free to contact me on:
A special thanks to Mr. Hassan Habib and Mr. Christo du Toit for their continuing dedicated contributions.