* 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.Extensions.Options;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
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.
|
||||
/// </summary>
|
||||
/// <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>
|
||||
/// <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
|
||||
public abstract class UpdateHandlerAttribute<T> : UpdateHandlerAttributeBase 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>
|
||||
public class DescribedHandlerInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// descriptor from that handler was described from
|
||||
/// </summary>
|
||||
public readonly HandlerDescriptor From;
|
||||
|
||||
/// <summary>
|
||||
/// The update router associated with this handler.
|
||||
/// </summary>
|
||||
@@ -60,13 +65,15 @@ namespace Telegrator.MadiatorCore.Descriptors
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DescribedHandlerInfo"/> class.
|
||||
/// </summary>
|
||||
/// <param name="fromDescriptor">descriptor from that handler was described from</param>
|
||||
/// <param name="updateRouter">The update router.</param>
|
||||
/// <param name="client">The Telegram bot client.</param>
|
||||
/// <param name="handlerInstance">The handler instance.</param>
|
||||
/// <param name="filterContext">The filter execution context.</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;
|
||||
Client = client;
|
||||
HandlerInstance = handlerInstance;
|
||||
@@ -90,7 +97,26 @@ namespace Telegrator.MadiatorCore.Descriptors
|
||||
try
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -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>
|
||||
/// The set of filters associated with this handler.
|
||||
/// </summary>
|
||||
public DescriptorFiltersSet Filters
|
||||
public DescriptorFiltersSet? Filters
|
||||
{
|
||||
get;
|
||||
protected set;
|
||||
}
|
||||
|
||||
public DescriptorAspectsSet? Aspects
|
||||
{
|
||||
get;
|
||||
protected set;
|
||||
@@ -154,6 +160,7 @@ namespace Telegrator.MadiatorCore.Descriptors
|
||||
UpdateType = handlerAttribute.Type;
|
||||
Indexer = handlerAttribute.GetIndexer();
|
||||
Filters = new DescriptorFiltersSet(handlerAttribute, stateKeeperAttribute, filters);
|
||||
Aspects = HandlerInspector.GetAspects(handlerType);
|
||||
DisplayString = HandlerInspector.GetDisplayName(handlerType);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Reflection;
|
||||
using Telegram.Bot.Types;
|
||||
using Telegram.Bot.Types.Enums;
|
||||
using Telegrator.Aspects;
|
||||
using Telegrator.Attributes.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, []);
|
||||
if (!descriptor.Filters.Validate(filterContext))
|
||||
if (descriptor.Filters != null && !descriptor.Filters.Validate(filterContext))
|
||||
return null;
|
||||
|
||||
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>
|
||||
|
||||
@@ -68,7 +68,7 @@ namespace Telegrator.Providers
|
||||
public virtual IHandlersCollection AddDescriptor(HandlerDescriptor descriptor)
|
||||
{
|
||||
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);
|
||||
MightAwaitAttribute[] mightAwaits = descriptor.HandlerType.GetCustomAttributes<MightAwaitAttribute>().ToArray();
|
||||
|
||||
@@ -886,6 +886,7 @@ namespace Telegrator
|
||||
public static bool HasParameterlessCtor(this Type type)
|
||||
=> type.GetConstructors().Any(ctor => ctor.GetParameters().Length == 0);
|
||||
|
||||
/*
|
||||
/// <summary>
|
||||
/// Invokes a "<paramref name="methodName"/>" method of an object
|
||||
/// </summary>
|
||||
@@ -948,6 +949,7 @@ namespace Telegrator
|
||||
/// <returns></returns>
|
||||
public static T? InvokeGenericMethod<T>(this object obj, string methodName, Type[] genericParameters, params object[]? parameters)
|
||||
=> (T?)obj.GetType().GetMethod(methodName).InvokeGenericMethod(obj, genericParameters, parameters);
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// Checks is <paramref name="obj"/> has public properties
|
||||
|
||||
Reference in New Issue
Block a user