Provides at structured and streamlined way of organizing .NET applications / webapis / console applications ect. In this way it is very easy to focus on the business and less on the technical details arround it via decorators to handle all cross cutting concerns. The framework is covered by unittests.
public void StartUp()
{
Assert.Equal(expectedNumber, result);
}
It is build on principles like
- immutability
- CQS
- SOLID
Features guides the strukturen but is unaware of the implementation details
It is easy to use a feature. Just follow below steps:
- Add below to your services configuration (eg. Startup.cs for web applications)
services.AddStrongHeart(x => //Extension method from namespace StrongHeart.Features.DependencyInjection
{
x.AddPipelineExtensions(GetPipeLineExtensions());
//or x.AddDefaultPipeline(...); which will apply the default pipeline with all decorators in the recommended order from StrongHeart
}, typeof(NameOfAFeatureType).Assembly);
- Add below method
public IEnumerable<IPipelineExtension> GetPipeLineExtensions()
{
yield return new AuthorizationExtension();
//yield more results to extend your pipeline
}
- Create a caller to get started (you can make it more grannular when you are confortable). The caller may be a physical person, a system or similar.
public class MyCaller : ICaller
{
public Guid Id { get; } = new Guid("ae463a0e-60ff-429f-a1f5-decd36f17e1d");
public IReadOnlyList<Claim> Claims { get; } = new List<Claim>()
{
StrongHeart.Features.Core.AdminClaim.Instance
}.AsReadOnly();
}
- Add your feature as dependency to your service/class with this syntax
public class MyClass
{
private readonly IQueryFeature<MyQueryFeatureRequest, MyQueryFeatureResponse> _feature;
public MyClass(IQueryFeature<MyQueryFeatureRequest, MyQueryFeatureResponse> feature)
{
_feature = feature;
}
}
or with ASP NET Core Webapi
public async IActionResult GetSomeThing([FromServices] IQueryFeature<MyQueryFeatureRequest, MyQueryFeatureResponse> feature)
{
MyQueryFeatureResponse result = await feature.Execute(new MyQueryFeatureRequest(new MyCaller(), /*other arguments*/));
/*return proper data*/
}
Pipeline extension | Setup | Interface to implement on your feature |
---|---|---|
Authorization: Ensures that the caller has sufficient permissions to execute a feature | yield return new AuthorizationExtension(...) | IAuthorizable |
ExceptionLogging: will log all exceptions which a feature may throw | yield return new ExceptionLoggerExtension(...) | n/a |
Filtering: will filter data in the response dependent on who calls | yield return new FilterExtension(...) | IFilterable'TResponse' |
RequestValidation: Will validate every request in a streamlines way | yield return new RequestValidatorExtension(...) | IRequestValidatable |
TimeAlert: Will log to a custom logger of feature execution exceeds specified thredshold | yield return new TimeAlertExtension(...) | ITimeAlert |
Retry: will rerun the feature is speficied criteria is met | yield return new RetryExtension(...) | IRetryable |
There are many candidates for custom pipeline extension. Just to name a few:
- Transaction (ensures that the subtasks in a command executes in a transaction)
- Audit (ensures that all calls to a feature is logged for audit purposes. Usually only relevant on commands, but might also be interesting on queries)
- Cache (ensures to cache return values on queries)
Implement interface to your feature: IDocumentationDescriber
- Why not middleware?