2020-11-18 15:55:18 +01:00
|
|
|
using FluentValidation;
|
2021-08-26 13:39:30 +02:00
|
|
|
using Microsoft.Extensions.Logging;
|
2020-11-18 15:55:18 +01:00
|
|
|
using System;
|
2021-08-26 13:39:30 +02:00
|
|
|
using System.Collections.Concurrent;
|
2020-11-18 15:55:18 +01:00
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Linq.Expressions;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using zero.Core.Entities;
|
2021-08-26 13:39:30 +02:00
|
|
|
using zero.Core.Utils;
|
2020-11-18 15:55:18 +01:00
|
|
|
|
2020-11-19 00:14:52 +01:00
|
|
|
namespace zero.Core.Collections
|
2020-11-18 15:55:18 +01:00
|
|
|
{
|
2020-11-19 00:14:52 +01:00
|
|
|
public class CollectionInterceptorHandler : ICollectionInterceptorHandler
|
2020-11-18 15:55:18 +01:00
|
|
|
{
|
2021-08-26 13:39:30 +02:00
|
|
|
protected ConcurrentBag<InterceptorRef> Interceptors { get; private set; } = new();
|
|
|
|
|
|
|
|
|
|
protected ILogger<ICollectionInterceptorHandler> Logger { get; set; }
|
2020-11-18 15:55:18 +01:00
|
|
|
|
|
|
|
|
|
2021-08-26 13:39:30 +02:00
|
|
|
public CollectionInterceptorHandler(IEnumerable<ICollectionInterceptor> items, ILogger<ICollectionInterceptorHandler> logger)
|
2020-11-18 15:55:18 +01:00
|
|
|
{
|
2021-08-26 13:39:30 +02:00
|
|
|
Logger = logger;
|
|
|
|
|
Interceptors = new();
|
|
|
|
|
|
|
|
|
|
foreach (ICollectionInterceptor item in items)
|
|
|
|
|
{
|
|
|
|
|
Interceptors.Add(new()
|
|
|
|
|
{
|
|
|
|
|
Interceptor = item,
|
|
|
|
|
Hash = IdGenerator.Create(),
|
|
|
|
|
Name = item.GetType().Name,
|
|
|
|
|
Gravity = item.Gravity
|
|
|
|
|
});
|
|
|
|
|
}
|
2020-11-18 15:55:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
2021-08-26 13:39:30 +02:00
|
|
|
public InterceptorInstruction<T, TParameters> Create<T, TParameters>(string operationName, TParameters parameters)
|
|
|
|
|
where T : ZeroEntity
|
|
|
|
|
where TParameters : CollectionInterceptor.Parameters<T>
|
2020-11-18 15:55:18 +01:00
|
|
|
{
|
2021-08-26 13:39:30 +02:00
|
|
|
InterceptorInstruction<T, TParameters> instruction = new(parameters);
|
|
|
|
|
instruction.Operation = operationName;
|
|
|
|
|
instruction.BeforeOperationHandler = async expression => await HandleBefore(expression, instruction);
|
|
|
|
|
instruction.AfterOperationHandler = async expression => await HandleAfter(expression, instruction);
|
2020-11-18 15:55:18 +01:00
|
|
|
|
2021-08-26 13:39:30 +02:00
|
|
|
return instruction;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Calls all matching interceptors with the specified expression
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal async Task HandleBefore<T, TParameters>(Expression<Func<ICollectionInterceptor, Task<InterceptorResult<T>>>> expression, InterceptorInstruction<T, TParameters> instruction)
|
|
|
|
|
where T : ZeroEntity
|
|
|
|
|
where TParameters : CollectionInterceptor.Parameters<T>
|
|
|
|
|
{
|
|
|
|
|
Func<ICollectionInterceptor, Task<InterceptorResult<T>>> func = default;
|
|
|
|
|
|
|
|
|
|
foreach (InterceptorRef interceptorRef in ForType(typeof(T)))
|
2020-11-18 15:55:18 +01:00
|
|
|
{
|
|
|
|
|
if (func == default)
|
|
|
|
|
{
|
2021-08-26 13:39:30 +02:00
|
|
|
func = expression.Compile();
|
2020-11-18 15:55:18 +01:00
|
|
|
}
|
|
|
|
|
|
2021-08-26 13:39:30 +02:00
|
|
|
Logger.LogDebug("Run interceptor {interceptor} before operation {operation}", interceptorRef.Name, instruction.Operation);
|
2020-11-18 15:55:18 +01:00
|
|
|
|
2021-08-26 13:39:30 +02:00
|
|
|
InterceptorResult<T> result = await func(interceptorRef.Interceptor);
|
|
|
|
|
|
|
|
|
|
if (result == default)
|
2020-11-18 15:55:18 +01:00
|
|
|
{
|
2021-08-26 13:39:30 +02:00
|
|
|
result = new();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result.InterceptorHash = interceptorRef.Hash;
|
|
|
|
|
instruction.Results.Add(result);
|
|
|
|
|
|
|
|
|
|
if (result.Result != null)
|
|
|
|
|
{
|
|
|
|
|
instruction.EntityResult = result.Result;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (result.Prevent)
|
|
|
|
|
{
|
|
|
|
|
break;
|
2020-11-18 15:55:18 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2021-08-26 13:39:30 +02:00
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Calls all matching interceptors with the specified expression
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal async Task HandleAfter<T, TParameters>(Expression<Func<ICollectionInterceptor, Task>> expression, InterceptorInstruction<T, TParameters> instruction)
|
|
|
|
|
where T : ZeroEntity
|
|
|
|
|
where TParameters : CollectionInterceptor.Parameters<T>
|
2020-11-18 15:55:18 +01:00
|
|
|
{
|
2020-11-19 00:14:52 +01:00
|
|
|
Func<ICollectionInterceptor, Task> func = default;
|
2021-08-26 13:39:30 +02:00
|
|
|
instruction ??= new();
|
2020-11-18 15:55:18 +01:00
|
|
|
|
2021-08-26 13:39:30 +02:00
|
|
|
foreach (InterceptorRef interceptorRef in ForType(typeof(T)))
|
2020-11-18 15:55:18 +01:00
|
|
|
{
|
2021-08-26 13:39:30 +02:00
|
|
|
InterceptorResult<T> beforeResult = instruction?.Results.FirstOrDefault(res => res.InterceptorHash == interceptorRef.Hash);
|
|
|
|
|
|
2020-11-18 15:55:18 +01:00
|
|
|
if (func == default)
|
|
|
|
|
{
|
2021-08-26 13:39:30 +02:00
|
|
|
func = expression.Compile();
|
2020-11-18 15:55:18 +01:00
|
|
|
}
|
|
|
|
|
|
2021-08-26 13:39:30 +02:00
|
|
|
Logger.LogDebug("Run interceptor {interceptor} after operation {operation}", interceptorRef.Name, instruction.Operation);
|
|
|
|
|
|
|
|
|
|
await func(interceptorRef.Interceptor);
|
2020-11-18 15:55:18 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Get all interceptors for a certain type
|
|
|
|
|
/// </summary>
|
2021-08-26 13:39:30 +02:00
|
|
|
IEnumerable<InterceptorRef> ForType(Type targetType)
|
2020-11-18 15:55:18 +01:00
|
|
|
{
|
2021-08-26 13:39:30 +02:00
|
|
|
return Interceptors.Where(map => map.Interceptor.CanHandle(targetType)).OrderByDescending(x => x.Gravity);
|
|
|
|
|
// return Interceptors.Where(item => item.Types.Count == 0 || item.Types.Any(type => targetType.IsAssignableFrom(type)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected class InterceptorRef
|
|
|
|
|
{
|
|
|
|
|
public string Hash { get; set; }
|
|
|
|
|
|
|
|
|
|
public ICollectionInterceptor Interceptor { get; set; }
|
|
|
|
|
|
|
|
|
|
public string Name { get; set; }
|
|
|
|
|
|
|
|
|
|
public int Gravity { get; set; }
|
2020-11-18 15:55:18 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2020-11-19 00:14:52 +01:00
|
|
|
public interface ICollectionInterceptorHandler
|
2020-11-18 15:55:18 +01:00
|
|
|
{
|
|
|
|
|
/// <summary>
|
2021-08-26 13:39:30 +02:00
|
|
|
/// Creates a new interceptor instruction
|
2020-11-18 15:55:18 +01:00
|
|
|
/// </summary>
|
2021-08-26 13:39:30 +02:00
|
|
|
InterceptorInstruction<T, TParameters> Create<T, TParameters>(string operationName, TParameters parameters)
|
|
|
|
|
where T : ZeroEntity
|
|
|
|
|
where TParameters : CollectionInterceptor.Parameters<T>;
|
2020-11-18 15:55:18 +01:00
|
|
|
}
|
|
|
|
|
}
|