1
1
using System ;
2
2
using System . Collections . Generic ;
3
3
using System . Linq ;
4
+ using System . Reflection ;
4
5
using Autofac ;
5
6
using Autofac . Builder ;
6
7
using Autofac . Core ;
8
+ using Autofac . Core . Activators . Delegate ;
7
9
8
10
namespace LazyProxy . Autofac
9
11
{
@@ -12,8 +14,24 @@ namespace LazyProxy.Autofac
12
14
/// </summary>
13
15
public static class AutofacExtensions
14
16
{
15
- private const string OpenGenericFactoryRegistrationSourceIsAlreadyAdded =
16
- nameof ( OpenGenericFactoryRegistrationSourceIsAlreadyAdded ) ;
17
+ private static readonly ConstructorInfo RegistrationBuilderConstructor ;
18
+
19
+ static AutofacExtensions ( )
20
+ {
21
+ // There is no way to create RegistrationBuilder with TypedService / KeyedService without reflection.
22
+ RegistrationBuilderConstructor = typeof ( ILifetimeScope ) . Assembly
23
+ . GetType ( "Autofac.Builder.RegistrationBuilder`3" )
24
+ . MakeGenericType (
25
+ typeof ( object ) ,
26
+ typeof ( SimpleActivatorData ) ,
27
+ typeof ( SingleRegistrationStyle ) )
28
+ . GetConstructor ( new [ ]
29
+ {
30
+ typeof ( Service ) ,
31
+ typeof ( SimpleActivatorData ) ,
32
+ typeof ( SingleRegistrationStyle )
33
+ } ) ;
34
+ }
17
35
18
36
/// <summary>
19
37
/// Is used to register interface TFrom to class TTo by creation a lazy proxy at runtime.
@@ -52,43 +70,75 @@ public static IRegistrationBuilder<object, SimpleActivatorData, SingleRegistrati
52
70
}
53
71
54
72
var registrationName = Guid . NewGuid ( ) . ToString ( ) ;
73
+ IRegistrationBuilder < object , SimpleActivatorData , SingleRegistrationStyle > registration ;
55
74
56
75
if ( typeTo . IsGenericTypeDefinition )
57
76
{
58
- if ( ! builder . Properties . ContainsKey ( OpenGenericFactoryRegistrationSourceIsAlreadyAdded ) )
59
- {
60
- builder . RegisterSource < OpenGenericFactoryRegistrationSource > ( ) ;
61
- builder . Properties . Add ( OpenGenericFactoryRegistrationSourceIsAlreadyAdded , true ) ;
62
- }
63
-
64
77
var nonLazyRegistration = builder . RegisterGeneric ( typeTo ) . Named ( registrationName , typeFrom ) ;
65
78
nonLazyRegistrationMutator ? . Mutate ( nonLazyRegistration ) ;
79
+
80
+ registration = builder . RegisterGenericFactory ( typeFrom , name ,
81
+ ( c , t , n , p ) => CreateLazyProxy ( c , t , registrationName , p ) ) ;
66
82
}
67
83
else
68
84
{
69
85
var nonLazyRegistration = builder . RegisterType ( typeTo ) . Named ( registrationName , typeFrom ) ;
70
86
nonLazyRegistrationMutator ? . Mutate ( nonLazyRegistration ) ;
71
- }
72
-
73
- var registration = builder . Register ( ( c , p ) =>
74
- {
75
- var parameters = p . ToList ( ) ;
76
- var context = c . Resolve < IComponentContext > ( ) ;
77
- var serviceType = GetServiceType ( typeFrom , parameters ) ;
78
87
79
- return LazyProxyBuilder . CreateInstance ( serviceType ,
80
- ( ) => context . ResolveNamed ( registrationName , serviceType , parameters )
81
- ) ;
82
- } ) ;
88
+ registration = builder . Register (
89
+ ( c , p ) => CreateLazyProxy ( c . Resolve < IComponentContext > ( ) , typeFrom , registrationName , p ) ) ;
90
+ }
83
91
84
92
return name == null
85
93
? registration . As ( typeFrom )
86
94
: registration . Named ( name , typeFrom ) ;
87
95
}
88
96
89
- private static Type GetServiceType ( Type type , IEnumerable < Parameter > parameters ) =>
90
- type . IsGenericType && ! type . IsConstructedGenericType
91
- ? parameters . Named < Type > ( OpenGenericFactoryRegistrationSource . ServiceType )
92
- : type ;
97
+ /// <summary>
98
+ /// Registers a delegate as a component for open generic types.
99
+ /// </summary>
100
+ /// <param name="builder">The instance of the Autofac container builder.</param>
101
+ /// <param name="type"><see cref="Type"/> of the registered component.</param>
102
+ /// <param name="name">Name of the registered component.</param>
103
+ /// <param name="factory">The delegate to register.</param>
104
+ /// <returns>Registration builder allowing the registration to be configured.</returns>
105
+ public static IRegistrationBuilder < object , SimpleActivatorData , SingleRegistrationStyle >
106
+ RegisterGenericFactory ( this ContainerBuilder builder , Type type , string name ,
107
+ Func < IComponentContext , Type , string , Parameter [ ] , object > factory )
108
+ {
109
+ var registration = ( IRegistrationBuilder < object , SimpleActivatorData , SingleRegistrationStyle > )
110
+ RegistrationBuilderConstructor . Invoke ( new [ ]
111
+ {
112
+ string . IsNullOrEmpty ( name )
113
+ ? ( object ) new TypedService ( type )
114
+ : new KeyedService ( name , type ) ,
115
+
116
+ new SimpleActivatorData ( new DelegateActivator ( type ,
117
+ ( c , p ) =>
118
+ {
119
+ var parameters = p . ToArray ( ) ;
120
+ var serviceType = parameters . Named < Type > ( OpenGenericFactoryRegistrationSource . ServiceType ) ;
121
+ var context = c . Resolve < IComponentContext > ( ) ;
122
+
123
+ return factory ( context , serviceType , name , parameters ) ;
124
+ } ) ) ,
125
+
126
+ new SingleRegistrationStyle ( )
127
+ } ) ;
128
+
129
+ registration . RegistrationData . DeferredCallback = builder . RegisterCallback (
130
+ cr => cr . AddRegistrationSource (
131
+ new OpenGenericFactoryRegistrationSource (
132
+ registration . RegistrationData ,
133
+ registration . ActivatorData ) ) ) ;
134
+
135
+ return registration ;
136
+ }
137
+
138
+ private static object CreateLazyProxy (
139
+ IComponentContext context , Type type , string name , IEnumerable < Parameter > parameters ) =>
140
+ LazyProxyBuilder . CreateInstance ( type ,
141
+ ( ) => context . ResolveNamed ( name , type , parameters )
142
+ ) ;
93
143
}
94
144
}
0 commit comments