forked from microsoft/agent-framework
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathRouteBuilderExtensions.cs
More file actions
101 lines (85 loc) · 4.25 KB
/
RouteBuilderExtensions.cs
File metadata and controls
101 lines (85 loc) · 4.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
// Copyright (c) Microsoft. All rights reserved.
#pragma warning disable CS0618 // Type or member is obsolete - Internal use of obsolete types for backward compatibility
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using Microsoft.Shared.Diagnostics;
namespace Microsoft.Agents.AI.Workflows.Reflection;
internal static class IMessageHandlerReflection
{
private const string Nameof_HandleAsync = nameof(IMessageHandler<>.HandleAsync);
internal static readonly MethodInfo HandleAsync_1 = typeof(IMessageHandler<>).GetMethod(Nameof_HandleAsync, BindingFlags.Public | BindingFlags.Instance)!;
internal static readonly MethodInfo HandleAsync_2 = typeof(IMessageHandler<,>).GetMethod(Nameof_HandleAsync, BindingFlags.Public | BindingFlags.Instance)!;
internal static MethodInfo ReflectHandle(this Type specializedType, int genericArgumentCount)
{
Debug.Assert(specializedType.IsGenericType &&
(specializedType.GetGenericTypeDefinition() == typeof(IMessageHandler<>) ||
specializedType.GetGenericTypeDefinition() == typeof(IMessageHandler<,>)),
"specializedType must be an IMessageHandler<> or IMessageHandler<,> type.");
return genericArgumentCount switch
{
1 => specializedType.GetMethodFromGenericMethodDefinition(HandleAsync_1),
2 => specializedType.GetMethodFromGenericMethodDefinition(HandleAsync_2),
_ => throw new ArgumentOutOfRangeException(nameof(genericArgumentCount), "Must be 1 or 2.")
};
}
internal static int GenericArgumentCount(this Type type)
{
Debug.Assert(type.IsMessageHandlerType(), "type must be an IMessageHandler<> or IMessageHandler<,> type.");
return type.GetGenericArguments().Length;
}
internal static bool IsMessageHandlerType(this Type type) =>
type.IsGenericType &&
(type.GetGenericTypeDefinition() == typeof(IMessageHandler<>) ||
type.GetGenericTypeDefinition() == typeof(IMessageHandler<,>));
}
internal static class RouteBuilderExtensions
{
private static IEnumerable<MessageHandlerInfo> GetHandlerInfos(
[DynamicallyAccessedMembers(ReflectionDemands.RuntimeInterfaceDiscoveryAndInvocation)]
this Type executorType)
{
// Handlers are defined by implementations of IMessageHandler<TMessage> or IMessageHandler<TMessage, TResult>
Debug.Assert(typeof(Executor).IsAssignableFrom(executorType), "executorType must be an Executor type.");
foreach (Type interfaceType in executorType.GetInterfaces())
{
// Check if the interface is a message handler.
if (!interfaceType.IsMessageHandlerType())
{
continue;
}
// Get the generic arguments of the interface.
Type[] genericArguments = interfaceType.GetGenericArguments();
if (genericArguments.Length is < 1 or > 2)
{
continue; // Invalid handler signature.
}
Type inType = genericArguments[0];
Type? outType = genericArguments.Length == 2 ? genericArguments[1] : null;
MethodInfo? method = interfaceType.ReflectHandle(genericArguments.Length);
if (method is not null)
{
yield return new MessageHandlerInfo(method) { InType = inType, OutType = outType };
}
}
}
public static RouteBuilder ReflectHandlers<
[DynamicallyAccessedMembers(
ReflectionDemands.RuntimeInterfaceDiscoveryAndInvocation)
] TExecutor>
(this RouteBuilder builder, ReflectingExecutor<TExecutor> executor)
where TExecutor : ReflectingExecutor<TExecutor>
{
Throw.IfNull(builder);
Type executorType = typeof(TExecutor);
Debug.Assert(executorType.IsInstanceOfType(executor),
"executorType must be the same type or a base type of the executor instance.");
foreach (MessageHandlerInfo handlerInfo in executorType.GetHandlerInfos())
{
builder = builder.AddHandlerInternal(handlerInfo.InType, handlerInfo.Bind(executor, checkType: true), handlerInfo.OutType);
}
return builder;
}
}