Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion samples/EasyWay.Samples/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
await kernel
.AddModule<SampleModule>()
.BuildAsync(builder.Services);

builder.Services.AddLogging();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddEasyWayWebApi();
Expand Down
10 changes: 6 additions & 4 deletions source/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@
<PackageVersion Include="FluentValidation.DependencyInjectionExtensions" Version="11.11.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="8.0.10" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Relational" Version="8.0.10" />
<PackageVersion Include="Microsoft.Extensions.Configuration" Version="9.0.2" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Abstractions" Version="9.0.2" />
<PackageVersion Include="Microsoft.Extensions.Configuration" Version="9.0.3" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Abstractions" Version="9.0.3" />
<PackageVersion Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="9.0.2" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Json" Version="9.0.2" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="9.0.2" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="9.0.3" />
<PackageVersion Include="Microsoft.Extensions.DependencyModel" Version="9.0.2" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.2" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="9.0.3" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.3" />
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="9.0.3" />
<PackageVersion Include="Scrutor" Version="6.0.1" />
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="8.2.0" />
<PackageVersion Include="System.Text.Json" Version="9.0.2" />
Expand Down
3 changes: 3 additions & 0 deletions source/EasyWay/EasyWay.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
<PackageReference Include="Microsoft.Extensions.Configuration.Json" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" />
<PackageReference Include="Microsoft.Extensions.DependencyModel" />
<PackageReference Include="Microsoft.Extensions.Logging" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" />
<PackageReference Include="Scrutor" />
<PackageReference Include="System.Text.Json" />
</ItemGroup>
Expand Down
4 changes: 3 additions & 1 deletion source/EasyWay/Internals/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using EasyWay.Internals.DomainServices;
using EasyWay.Internals.Factories;
using EasyWay.Internals.Initializers;
using EasyWay.Internals.Loggers;
using EasyWay.Internals.Policies;
using EasyWay.Internals.Queries;
using EasyWay.Internals.Repositories;
Expand All @@ -24,9 +25,10 @@ internal static void AddEasyWay(
services
.AddClocks()
.AddContexts()
.AddLoggers(moduleType)
.AddAggregateRoots()
.AddCommands(moduleType, assemblies)
.AddQueries(moduleType, assemblies)
.AddQueries(assemblies)
.AddDomainEvents(assemblies)
.AddRepositories(assemblies)
.AddPolicies(assemblies)
Expand Down
26 changes: 26 additions & 0 deletions source/EasyWay/Internals/Loggers/EasyWayLogger.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using Microsoft.Extensions.Logging;

namespace EasyWay.Internals.Queries.Loggers
{
internal sealed partial class EasyWayLogger<TModule>
where TModule : EasyWayModule
{
private readonly ILogger _logger;

public EasyWayLogger(ILogger<TModule> logger) => _logger = logger;

//TODO scope logger CorrelationId (ScopeId)

[LoggerMessage(0, LogLevel.Information, "Executing {@component}", SkipEnabledCheck = true)]
public partial void Executing(object component);

[LoggerMessage(1, LogLevel.Information, "Executed", SkipEnabledCheck = true)]
public partial void Executed();

[LoggerMessage(2, LogLevel.Information, "Failed", SkipEnabledCheck = true)]
public partial void Failed();

[LoggerMessage(3, LogLevel.Error, "Unexpected exception", SkipEnabledCheck = true)]
public partial void UnexpectedException(Exception exception);
}
}
20 changes: 20 additions & 0 deletions source/EasyWay/Internals/Loggers/Extensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using EasyWay.Internals.Queries.Loggers;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

namespace EasyWay.Internals.Loggers
{
internal static class Extensions
{
internal static IServiceCollection AddLoggers(this IServiceCollection services, Type moduleType)
{
services.AddLogging(x => x.AddJsonConsole());

var loggerType = typeof(EasyWayLogger<>).MakeGenericType(moduleType);

services.AddSingleton(loggerType);

return services;
}
}
}
4 changes: 2 additions & 2 deletions source/EasyWay/Internals/Modules/ModuleExecutor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ public async Task<QueryResult<TReadModel>> Query<TQuery, TReadModel>(TQuery quer
var sp = scope.ServiceProvider;

result = await sp
.GetRequiredService<IQueryExecutor<TModule>>()
.Execute<TQuery, TReadModel>(query, cancellationToken);
.GetRequiredService<IQueryExecutor>()
.Execute<TModule, TQuery, TReadModel>(query, cancellationToken);
}

return result;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using Microsoft.Extensions.DependencyInjection;

namespace EasyWay.Internals.Queries.Decorators
{
internal sealed class QueryExecutorCancellationContextDecorator : IQueryExecutor
{
private readonly IQueryExecutor _decoratedQueryExecutor;

private readonly IServiceProvider _serviceProvider;

public QueryExecutorCancellationContextDecorator(
IQueryExecutor decoratedQueryExecutor,
IServiceProvider serviceProvider)
{
_decoratedQueryExecutor = decoratedQueryExecutor;
_serviceProvider = serviceProvider;
}

public Task<QueryResult<TReadModel>> Execute<TModule, TQuery, TReadModel>(TQuery query, CancellationToken cancellationToken = default)
where TModule : EasyWayModule
where TQuery : Query<TReadModel>
where TReadModel : ReadModel
{
_serviceProvider.GetRequiredService<CancellationContext>().Set(cancellationToken);

return _decoratedQueryExecutor.Execute<TModule, TQuery, TReadModel>(query, cancellationToken);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using EasyWay.Internals.Queries.Loggers;
using Microsoft.Extensions.DependencyInjection;

namespace EasyWay.Internals.Queries.Decorators
{
internal sealed class QueryExecutorLoggerDecorator : IQueryExecutor
{
private readonly IQueryExecutor _decoratedQueryExecutor;

private readonly IServiceProvider _serviceProvider;

public QueryExecutorLoggerDecorator(
IQueryExecutor decoratedQueryExecutor,
IServiceProvider serviceProvider)
{
_decoratedQueryExecutor = decoratedQueryExecutor;
_serviceProvider = serviceProvider;
}

public Task<QueryResult<TReadModel>> Execute<TModule, TQuery, TReadModel>(TQuery query, CancellationToken cancellationToken = default)
where TModule : EasyWayModule
where TQuery : Query<TReadModel>
where TReadModel : ReadModel
{
var logger = _serviceProvider.GetRequiredService<EasyWayLogger<TModule>>();

//TODO begin scope (correlation Id)

logger.Executing(query);

try
{
var result = _decoratedQueryExecutor.Execute<TModule, TQuery, TReadModel>(query, cancellationToken);

logger.Executed();

return result;
}
catch (Exception ex)
{
logger.UnexpectedException(ex);
throw;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using EasyWay.Internals.Validation;
using Microsoft.Extensions.DependencyInjection;

namespace EasyWay.Internals.Queries.Decorators
{
internal sealed class QueryExecutorValidatorDecorator : IQueryExecutor
{
private readonly IQueryExecutor _decoratedQueryExecutor;

private readonly IServiceProvider _serviceProvider;

public QueryExecutorValidatorDecorator(
IQueryExecutor decoratedQueryExecutor,
IServiceProvider serviceProvider)
{
_decoratedQueryExecutor = decoratedQueryExecutor;
_serviceProvider = serviceProvider;
}

public Task<QueryResult<TReadModel>> Execute<TModule, TQuery, TReadModel>(TQuery query, CancellationToken cancellationToken = default)
where TModule : EasyWayModule
where TQuery : Query<TReadModel>
where TReadModel : ReadModel
{
var validatorType = typeof(IEasyWayValidator<>).MakeGenericType(query.GetType());

var validator = _serviceProvider.GetService<IEasyWayValidator<TQuery>>();

if (validator is not null)
{
var errors = validator.Validate(query);

if (errors.Any())
{
return Task.FromResult(QueryResult<TReadModel>.Validation(errors));
}
}

return _decoratedQueryExecutor.Execute<TModule, TQuery, TReadModel>(query, cancellationToken);
}
}
}
21 changes: 16 additions & 5 deletions source/EasyWay/Internals/Queries/Extensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.Reflection;
using EasyWay.Internals.Queries.Decorators;
using EasyWay.Internals.Validation;
using Microsoft.Extensions.DependencyInjection;

namespace EasyWay.Internals.Queries
Expand All @@ -7,17 +9,26 @@ internal static class Extensions
{
internal static IServiceCollection AddQueries(
this IServiceCollection services,
Type moduleType,
IEnumerable<Assembly> assemblies)
{
services.AddScoped(typeof(IQueryExecutor<>).MakeGenericType(moduleType), typeof(QueryExecutor<>).MakeGenericType(moduleType));
services.AddScoped<QueryExecutor>();

services.AddAsBasedType(typeof(QueryHandler<,>), ServiceLifetime.Scoped, assemblies);
services.AddScoped<IQueryExecutor>(p =>
{
var executor = p.GetRequiredService<QueryExecutor>();

return services;
}
var cancellationContext = new QueryExecutorCancellationContextDecorator(executor, p);

var validator = new QueryExecutorValidatorDecorator(cancellationContext, p);

var logger = new QueryExecutorLoggerDecorator(validator, p);

return logger;
});

services.AddAsBasedType(typeof(QueryHandler<,>), ServiceLifetime.Scoped, assemblies);

return services;
}
}
}
6 changes: 3 additions & 3 deletions source/EasyWay/Internals/Queries/IQueryExecutor.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
namespace EasyWay.Internals.Queries
{
internal interface IQueryExecutor<TModule>
where TModule : EasyWayModule
internal interface IQueryExecutor
{
Task<QueryResult<TReadModel>> Execute<TQuery, TReadModel>(TQuery query, CancellationToken cancellationToken = default)
Task<QueryResult<TReadModel>> Execute<TModule, TQuery, TReadModel>(TQuery query, CancellationToken cancellationToken = default)
where TModule : EasyWayModule
where TQuery : Query<TReadModel>
where TReadModel : ReadModel;
}
Expand Down
41 changes: 6 additions & 35 deletions source/EasyWay/Internals/Queries/QueryExecutor.cs
Original file line number Diff line number Diff line change
@@ -1,51 +1,22 @@
using EasyWay.Internals.Contexts;
using EasyWay.Internals.Validation;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;

namespace EasyWay.Internals.Queries
{
internal sealed class QueryExecutor<TModule> : IQueryExecutor<TModule>
where TModule : EasyWayModule
internal sealed class QueryExecutor : IQueryExecutor
{
private readonly IServiceProvider _serviceProvider;

private readonly CancellationContext _cancellationContext;

public QueryExecutor(
IServiceProvider serviceProvider,
CancellationContext cancellationContext)
public QueryExecutor(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
_cancellationContext = cancellationContext;
}

public async Task<QueryResult<TReadModel>> Execute<TQuery, TReadModel>(TQuery query, CancellationToken cancellationToken = default)
public async Task<QueryResult<TReadModel>> Execute<TModule, TQuery, TReadModel>(TQuery query, CancellationToken cancellationToken = default)
where TModule : EasyWayModule
where TQuery : Query<TReadModel>
where TReadModel : ReadModel
{
_cancellationContext.Set(cancellationToken);

var queryType = query.GetType();

var validatorType = typeof(IEasyWayValidator<>).MakeGenericType(queryType);

var validator = _serviceProvider.GetService<IEasyWayValidator<TQuery>>();

if (validator is not null)
{
var errors = validator.Validate(query);

if (errors.Any())
{
return QueryResult<TReadModel>.Validation(errors);
}
}

var queryHandler = _serviceProvider.GetRequiredService<QueryHandler<TQuery, TReadModel>>();

var queryResult = await queryHandler.Handle(query);

return queryResult;
return await _serviceProvider.GetRequiredService<QueryHandler<TQuery, TReadModel>>().Handle(query);
}
}
}
Loading