* Added new namespace "Aspects" and types dedicated for aspected handlers processing, including Pre\Post processors
* Added new DescriptorAspectsSet class, used for mamanging and executing aspects of handlers * Processors can prevent handlers execution using Result.Fault() * Added field to DescribedHandlerInfo for getting descriptor from which this handler was described * Removed unused reflection extension methods
This commit is contained in:
@@ -1,6 +1,5 @@
|
|||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
|
|
||||||
namespace Telegrator.Hosting.Web
|
namespace Telegrator.Hosting.Web
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
namespace Telegrator.Aspects
|
||||||
|
{
|
||||||
|
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
|
||||||
|
public class AfterExecutionAttribute<T> : Attribute where T : IPostProcessor
|
||||||
|
{
|
||||||
|
public Type ProcessorType => typeof(T);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
namespace Telegrator.Aspects
|
||||||
|
{
|
||||||
|
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
|
||||||
|
public class BeforeExecutionAttribute<T> : Attribute where T : IPreProcessor
|
||||||
|
{
|
||||||
|
public Type ProcessorType => typeof(T);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using Telegrator.Handlers;
|
||||||
|
using Telegrator.Handlers.Components;
|
||||||
|
|
||||||
|
namespace Telegrator.Aspects
|
||||||
|
{
|
||||||
|
public interface IPostProcessor
|
||||||
|
{
|
||||||
|
public Task<Result> AfterExecution(IHandlerContainer container);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using Telegrator.Handlers;
|
||||||
|
using Telegrator.Handlers.Components;
|
||||||
|
|
||||||
|
namespace Telegrator.Aspects
|
||||||
|
{
|
||||||
|
public interface IPreProcessor
|
||||||
|
{
|
||||||
|
public Task<Result> BeforeExecution(IHandlerContainer container);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,10 +9,38 @@ namespace Telegrator.Attributes
|
|||||||
/// Provides a type-safe way to associate handler types with specific update types and importance settings.
|
/// Provides a type-safe way to associate handler types with specific update types and importance settings.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">The type of the update handler that this attribute is applied to.</typeparam>
|
/// <typeparam name="T">The type of the update handler that this attribute is applied to.</typeparam>
|
||||||
/// <param name="updateType">The type of update that this handler can process.</param>
|
public abstract class UpdateHandlerAttribute<T> : UpdateHandlerAttributeBase where T : UpdateHandlerBase
|
||||||
/// <param name="importance">The importance level for this handler (default: 0 for unlimited).</param>
|
|
||||||
public abstract class UpdateHandlerAttribute<T>(UpdateType updateType, int importance = 0)
|
|
||||||
: UpdateHandlerAttributeBase([typeof(T)], updateType, importance) where T : UpdateHandlerBase
|
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes new instance of <see cref="UpdateHandlerAttribute{T}"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="updateType">The type of update that this handler can process.</param>
|
||||||
|
protected UpdateHandlerAttribute(UpdateType updateType)
|
||||||
|
: base([typeof(T)], updateType, 0) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes new instance of <see cref="UpdateHandlerAttribute{T}"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="updateType">The type of update that this handler can process.</param>
|
||||||
|
/// <param name="importance">The importance level for this handler</param>
|
||||||
|
protected UpdateHandlerAttribute(UpdateType updateType, int importance)
|
||||||
|
: base([typeof(T)], updateType, importance) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes new instance of <see cref="UpdateHandlerAttribute{T}"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="types">Additional suported types.</param>
|
||||||
|
/// <param name="updateType">The type of update that this handler can process.</param>
|
||||||
|
protected UpdateHandlerAttribute(Type[] types, UpdateType updateType)
|
||||||
|
: base([..types, typeof(T)], updateType, 0) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes new instance of <see cref="UpdateHandlerAttribute{T}"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="types">Additional suported types.</param>
|
||||||
|
/// <param name="updateType">The type of update that this handler can process.</param>
|
||||||
|
/// <param name="importance">The importance level for this handler</param>
|
||||||
|
protected UpdateHandlerAttribute(Type[] types, UpdateType updateType, int importance)
|
||||||
|
: base([.. types, typeof(T)], updateType, importance) { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,11 @@ namespace Telegrator.MadiatorCore.Descriptors
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class DescribedHandlerInfo
|
public class DescribedHandlerInfo
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// descriptor from that handler was described from
|
||||||
|
/// </summary>
|
||||||
|
public readonly HandlerDescriptor From;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The update router associated with this handler.
|
/// The update router associated with this handler.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -60,13 +65,15 @@ namespace Telegrator.MadiatorCore.Descriptors
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="DescribedHandlerInfo"/> class.
|
/// Initializes a new instance of the <see cref="DescribedHandlerInfo"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="fromDescriptor">descriptor from that handler was described from</param>
|
||||||
/// <param name="updateRouter">The update router.</param>
|
/// <param name="updateRouter">The update router.</param>
|
||||||
/// <param name="client">The Telegram bot client.</param>
|
/// <param name="client">The Telegram bot client.</param>
|
||||||
/// <param name="handlerInstance">The handler instance.</param>
|
/// <param name="handlerInstance">The handler instance.</param>
|
||||||
/// <param name="filterContext">The filter execution context.</param>
|
/// <param name="filterContext">The filter execution context.</param>
|
||||||
/// <param name="displayString">Optional display string.</param>
|
/// <param name="displayString">Optional display string.</param>
|
||||||
public DescribedHandlerInfo(IUpdateRouter updateRouter, ITelegramBotClient client, UpdateHandlerBase handlerInstance, FilterExecutionContext<Update> filterContext, string? displayString)
|
public DescribedHandlerInfo(HandlerDescriptor fromDescriptor, IUpdateRouter updateRouter, ITelegramBotClient client, UpdateHandlerBase handlerInstance, FilterExecutionContext<Update> filterContext, string? displayString)
|
||||||
{
|
{
|
||||||
|
From = fromDescriptor;
|
||||||
UpdateRouter = updateRouter;
|
UpdateRouter = updateRouter;
|
||||||
Client = client;
|
Client = client;
|
||||||
HandlerInstance = handlerInstance;
|
HandlerInstance = handlerInstance;
|
||||||
@@ -90,7 +97,26 @@ namespace Telegrator.MadiatorCore.Descriptors
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
HandlerContainer = GetContainer(UpdateRouter.AwaitingProvider, this);
|
HandlerContainer = GetContainer(UpdateRouter.AwaitingProvider, this);
|
||||||
return await HandlerInstance.Execute(HandlerContainer, cancellationToken);
|
|
||||||
|
if (From.Aspects != null)
|
||||||
|
{
|
||||||
|
Result preResult = await From.Aspects.ExecutePre(HandlerInstance, HandlerContainer);
|
||||||
|
if (!preResult.Positive)
|
||||||
|
return preResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result execResult = await HandlerInstance.Execute(HandlerContainer, cancellationToken);
|
||||||
|
if (!execResult.Positive)
|
||||||
|
return execResult;
|
||||||
|
|
||||||
|
if (From.Aspects != null)
|
||||||
|
{
|
||||||
|
Result postResult = await From.Aspects.ExecutePost(HandlerInstance, HandlerContainer);
|
||||||
|
if (!postResult.Positive)
|
||||||
|
return postResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.Ok();
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
using Telegrator.Aspects;
|
||||||
|
using Telegrator.Handlers;
|
||||||
|
using Telegrator.Handlers.Components;
|
||||||
|
|
||||||
|
namespace Telegrator.MadiatorCore.Descriptors
|
||||||
|
{
|
||||||
|
public sealed class DescriptorAspectsSet
|
||||||
|
{
|
||||||
|
public bool SelfPre { get; private set; }
|
||||||
|
|
||||||
|
public bool SelfPost { get; private set; }
|
||||||
|
|
||||||
|
public Type? TypedPre { get; private set; }
|
||||||
|
|
||||||
|
public Type? TypedPost { get; private set; }
|
||||||
|
|
||||||
|
public DescriptorAspectsSet(bool selfPre, Type? typedPre, bool selfPost, Type? typedPost)
|
||||||
|
{
|
||||||
|
SelfPre = selfPre;
|
||||||
|
SelfPost = selfPost;
|
||||||
|
TypedPre = typedPre;
|
||||||
|
TypedPost = typedPost;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Result> ExecutePre(UpdateHandlerBase handler, IHandlerContainer container)
|
||||||
|
{
|
||||||
|
if (SelfPre)
|
||||||
|
{
|
||||||
|
if (handler is not IPreProcessor preProcessor)
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
|
||||||
|
return await preProcessor.BeforeExecution(container);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TypedPre != null)
|
||||||
|
{
|
||||||
|
IPreProcessor preProcessor = (IPreProcessor)Activator.CreateInstance(TypedPre);
|
||||||
|
return await preProcessor.BeforeExecution(container);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Result> ExecutePost(UpdateHandlerBase handler, IHandlerContainer container)
|
||||||
|
{
|
||||||
|
if (SelfPost)
|
||||||
|
{
|
||||||
|
if (handler is not IPostProcessor postProcessor)
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
|
||||||
|
return await postProcessor.AfterExecution(container);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TypedPost != null)
|
||||||
|
{
|
||||||
|
IPostProcessor postProcessor = (IPostProcessor)Activator.CreateInstance(TypedPost);
|
||||||
|
return await postProcessor.AfterExecution(container);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.Ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -76,7 +76,13 @@ namespace Telegrator.MadiatorCore.Descriptors
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The set of filters associated with this handler.
|
/// The set of filters associated with this handler.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public DescriptorFiltersSet Filters
|
public DescriptorFiltersSet? Filters
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
protected set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DescriptorAspectsSet? Aspects
|
||||||
{
|
{
|
||||||
get;
|
get;
|
||||||
protected set;
|
protected set;
|
||||||
@@ -154,6 +160,7 @@ namespace Telegrator.MadiatorCore.Descriptors
|
|||||||
UpdateType = handlerAttribute.Type;
|
UpdateType = handlerAttribute.Type;
|
||||||
Indexer = handlerAttribute.GetIndexer();
|
Indexer = handlerAttribute.GetIndexer();
|
||||||
Filters = new DescriptorFiltersSet(handlerAttribute, stateKeeperAttribute, filters);
|
Filters = new DescriptorFiltersSet(handlerAttribute, stateKeeperAttribute, filters);
|
||||||
|
Aspects = HandlerInspector.GetAspects(handlerType);
|
||||||
DisplayString = HandlerInspector.GetDisplayName(handlerType);
|
DisplayString = HandlerInspector.GetDisplayName(handlerType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Telegram.Bot.Types;
|
using Telegram.Bot.Types;
|
||||||
using Telegram.Bot.Types.Enums;
|
using Telegram.Bot.Types.Enums;
|
||||||
|
using Telegrator.Aspects;
|
||||||
using Telegrator.Attributes.Components;
|
using Telegrator.Attributes.Components;
|
||||||
using Telegrator.Filters.Components;
|
using Telegrator.Filters.Components;
|
||||||
|
|
||||||
@@ -80,5 +81,29 @@ namespace Telegrator.MadiatorCore.Descriptors
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static DescriptorAspectsSet GetAspects(Type handlerType)
|
||||||
|
{
|
||||||
|
bool selfPre = handlerType.GetInterface(nameof(IPreProcessor)) != null;
|
||||||
|
bool selfPost = handlerType.GetInterface(nameof(IPostProcessor)) != null;
|
||||||
|
Type? typedPre = null;
|
||||||
|
Type? typedPost = null;
|
||||||
|
|
||||||
|
if (!selfPre)
|
||||||
|
{
|
||||||
|
Attribute? preAttr = handlerType.GetCustomAttribute(typeof(BeforeExecutionAttribute<>));
|
||||||
|
if (preAttr != null)
|
||||||
|
typedPre = preAttr.GetType().GetGenericArguments()[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!selfPost)
|
||||||
|
{
|
||||||
|
Attribute? postAttr = handlerType.GetCustomAttribute(typeof(AfterExecutionAttribute<>));
|
||||||
|
if (postAttr != null)
|
||||||
|
typedPre = postAttr.GetType().GetGenericArguments()[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return new DescriptorAspectsSet(selfPre, typedPre, selfPost, typedPost);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -223,11 +223,11 @@ namespace Telegrator.Polling
|
|||||||
};
|
};
|
||||||
|
|
||||||
FilterExecutionContext<Update> filterContext = new FilterExecutionContext<Update>(_botInfo, update, update, data, []);
|
FilterExecutionContext<Update> filterContext = new FilterExecutionContext<Update>(_botInfo, update, update, data, []);
|
||||||
if (!descriptor.Filters.Validate(filterContext))
|
if (descriptor.Filters != null && !descriptor.Filters.Validate(filterContext))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
UpdateHandlerBase handlerInstance = provider.GetHandlerInstance(descriptor, cancellationToken);
|
UpdateHandlerBase handlerInstance = provider.GetHandlerInstance(descriptor, cancellationToken);
|
||||||
return new DescribedHandlerInfo(updateRouter, client, handlerInstance, filterContext, descriptor.DisplayString);
|
return new DescribedHandlerInfo(descriptor, updateRouter, client, handlerInstance, filterContext, descriptor.DisplayString);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ namespace Telegrator.Providers
|
|||||||
public virtual IHandlersCollection AddDescriptor(HandlerDescriptor descriptor)
|
public virtual IHandlersCollection AddDescriptor(HandlerDescriptor descriptor)
|
||||||
{
|
{
|
||||||
if (MustHaveParameterlessCtor && !descriptor.HandlerType.HasParameterlessCtor())
|
if (MustHaveParameterlessCtor && !descriptor.HandlerType.HasParameterlessCtor())
|
||||||
throw new Exception();
|
throw new Exception("This handler (" + descriptor.HandlerType.FullName + "), must contain constructor without parameters.");
|
||||||
|
|
||||||
_allowedTypes.Union(descriptor.UpdateType);
|
_allowedTypes.Union(descriptor.UpdateType);
|
||||||
MightAwaitAttribute[] mightAwaits = descriptor.HandlerType.GetCustomAttributes<MightAwaitAttribute>().ToArray();
|
MightAwaitAttribute[] mightAwaits = descriptor.HandlerType.GetCustomAttributes<MightAwaitAttribute>().ToArray();
|
||||||
|
|||||||
@@ -886,6 +886,7 @@ namespace Telegrator
|
|||||||
public static bool HasParameterlessCtor(this Type type)
|
public static bool HasParameterlessCtor(this Type type)
|
||||||
=> type.GetConstructors().Any(ctor => ctor.GetParameters().Length == 0);
|
=> type.GetConstructors().Any(ctor => ctor.GetParameters().Length == 0);
|
||||||
|
|
||||||
|
/*
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invokes a "<paramref name="methodName"/>" method of an object
|
/// Invokes a "<paramref name="methodName"/>" method of an object
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -948,6 +949,7 @@ namespace Telegrator
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static T? InvokeGenericMethod<T>(this object obj, string methodName, Type[] genericParameters, params object[]? parameters)
|
public static T? InvokeGenericMethod<T>(this object obj, string methodName, Type[] genericParameters, params object[]? parameters)
|
||||||
=> (T?)obj.GetType().GetMethod(methodName).InvokeGenericMethod(obj, genericParameters, parameters);
|
=> (T?)obj.GetType().GetMethod(methodName).InvokeGenericMethod(obj, genericParameters, parameters);
|
||||||
|
*/
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks is <paramref name="obj"/> has public properties
|
/// Checks is <paramref name="obj"/> has public properties
|
||||||
|
|||||||
Reference in New Issue
Block a user