@@ -9,84 +9,94 @@ namespace Microsoft.AspNetCore.Builder;
99public static class WebApplicationExtensions
1010{
1111
12- private static InstantAPIsConfig Configuration { get ; set ; } = new ( ) ;
13-
14- public static IEndpointRouteBuilder MapInstantAPIs < D > ( this IEndpointRouteBuilder app , Action < InstantAPIsConfigBuilder < D > > options = null ) where D : DbContext
15- {
16- if ( app is IApplicationBuilder applicationBuilder )
17- {
18- // Check if AddInstantAPIs was called by getting the service options and evaluate EnableSwagger property
19- var serviceOptions = applicationBuilder . ApplicationServices . GetRequiredService < IOptions < InstantAPIsServiceOptions > > ( ) . Value ;
20- if ( serviceOptions == null || serviceOptions . EnableSwagger == null )
21- {
22- throw new ArgumentException ( "Call builder.Services.AddInstantAPIs(options) before MapInstantAPIs." ) ;
23- }
24-
25- var webApp = ( WebApplication ) app ;
26- if ( serviceOptions . EnableSwagger == EnableSwagger . Always ||
27- ( serviceOptions . EnableSwagger == EnableSwagger . DevelopmentOnly && webApp . Environment . IsDevelopment ( ) ) )
28- {
29- applicationBuilder . UseSwagger ( ) ;
30- applicationBuilder . UseSwaggerUI ( ) ;
31- }
32-
33- var ctx = applicationBuilder . ApplicationServices . CreateScope ( ) . ServiceProvider . GetService ( typeof ( D ) ) as D ;
34- var builder = new InstantAPIsConfigBuilder < D > ( ctx ) ;
35- if ( options != null )
36- {
37- options ( builder ) ;
38- Configuration = builder . Build ( ) ;
39- }
40- }
41-
42- // Get the tables on the DbContext
43- var dbTables = GetDbTablesForContext < D > ( ) ;
44-
45- var requestedTables = ! Configuration . Tables . Any ( ) ?
46- dbTables :
47- Configuration . Tables . Where ( t => dbTables . Any ( db => db . Name . Equals ( t . Name , StringComparison . OrdinalIgnoreCase ) ) ) . ToArray ( ) ;
48-
49- var allMethods = typeof ( MapApiExtensions ) . GetMethods ( BindingFlags . NonPublic | BindingFlags . Static ) . Where ( m => m . Name . StartsWith ( "Map" ) ) . ToArray ( ) ;
50- var initialize = typeof ( MapApiExtensions ) . GetMethod ( "Initialize" , BindingFlags . NonPublic | BindingFlags . Static ) ;
51- foreach ( var table in requestedTables )
52- {
53-
54- // The default URL for an InstantAPI is /api/TABLENAME
55- var url = $ "/api/{ table . Name } ";
56-
57- initialize . MakeGenericMethod ( typeof ( D ) , table . InstanceType ) . Invoke ( null , null ) ;
58-
59- // The remaining private static methods in this class build out the Mapped API methods..
60- // let's use some reflection to get them
61- foreach ( var method in allMethods )
62- {
63-
64- var sigAttr = method . CustomAttributes . First ( x => x . AttributeType == typeof ( ApiMethodAttribute ) ) . ConstructorArguments . First ( ) ;
65- var methodType = ( ApiMethodsToGenerate ) sigAttr . Value ;
66- if ( ( table . ApiMethodsToGenerate & methodType ) != methodType ) continue ;
67-
68- var genericMethod = method . MakeGenericMethod ( typeof ( D ) , table . InstanceType ) ;
69- genericMethod . Invoke ( null , new object [ ] { app , url } ) ;
70- }
71-
72- }
73-
74- return app ;
75- }
76-
77- internal static IEnumerable < TypeTable > GetDbTablesForContext < D > ( ) where D : DbContext
78- {
79- return typeof ( D ) . GetProperties ( BindingFlags . Instance | BindingFlags . Public )
80- . Where ( x => x . PropertyType . FullName . StartsWith ( "Microsoft.EntityFrameworkCore.DbSet" ) )
81- . Select ( x => new TypeTable { Name = x . Name , InstanceType = x . PropertyType . GenericTypeArguments . First ( ) } )
82- . ToArray ( ) ;
83- }
84-
85- internal class TypeTable
86- {
87- public string Name { get ; set ; }
88- public Type InstanceType { get ; set ; }
89- public ApiMethodsToGenerate ApiMethodsToGenerate { get ; set ; } = ApiMethodsToGenerate . All ;
90- }
12+ private static InstantAPIsConfig Configuration { get ; set ; } = new ( ) ;
13+
14+ public static IEndpointRouteBuilder MapInstantAPIs < D > ( this IEndpointRouteBuilder app , Action < InstantAPIsConfigBuilder < D > > options = null ) where D : DbContext
15+ {
16+ if ( app is IApplicationBuilder applicationBuilder )
17+ {
18+ AddOpenAPIConfiguration ( app , options , applicationBuilder ) ;
19+ }
20+
21+ // Get the tables on the DbContext
22+ var dbTables = GetDbTablesForContext < D > ( ) ;
23+
24+ var requestedTables = ! Configuration . Tables . Any ( ) ?
25+ dbTables :
26+ Configuration . Tables . Where ( t => dbTables . Any ( db => db . Name . Equals ( t . Name , StringComparison . OrdinalIgnoreCase ) ) ) . ToArray ( ) ;
27+
28+ MapInstantAPIsUsingReflection < D > ( app , requestedTables ) ;
29+
30+ return app ;
31+ }
32+
33+ private static void MapInstantAPIsUsingReflection < D > ( IEndpointRouteBuilder app , IEnumerable < TypeTable > requestedTables ) where D : DbContext
34+ {
35+ var allMethods = typeof ( MapApiExtensions ) . GetMethods ( BindingFlags . NonPublic | BindingFlags . Static ) . Where ( m => m . Name . StartsWith ( "Map" ) ) . ToArray ( ) ;
36+ var initialize = typeof ( MapApiExtensions ) . GetMethod ( "Initialize" , BindingFlags . NonPublic | BindingFlags . Static ) ;
37+ foreach ( var table in requestedTables )
38+ {
39+
40+ // The default URL for an InstantAPI is /api/TABLENAME
41+ var url = $ "/api/{ table . Name } ";
42+
43+ initialize . MakeGenericMethod ( typeof ( D ) , table . InstanceType ) . Invoke ( null , null ) ;
44+
45+ // The remaining private static methods in this class build out the Mapped API methods..
46+ // let's use some reflection to get them
47+ foreach ( var method in allMethods )
48+ {
49+
50+ var sigAttr = method . CustomAttributes . First ( x => x . AttributeType == typeof ( ApiMethodAttribute ) ) . ConstructorArguments . First ( ) ;
51+ var methodType = ( ApiMethodsToGenerate ) sigAttr . Value ;
52+ if ( ( table . ApiMethodsToGenerate & methodType ) != methodType ) continue ;
53+
54+ var genericMethod = method . MakeGenericMethod ( typeof ( D ) , table . InstanceType ) ;
55+ genericMethod . Invoke ( null , new object [ ] { app , url } ) ;
56+ }
57+
58+ }
59+ }
60+
61+ private static void AddOpenAPIConfiguration < D > ( IEndpointRouteBuilder app , Action < InstantAPIsConfigBuilder < D > > options , IApplicationBuilder applicationBuilder ) where D : DbContext
62+ {
63+ // Check if AddInstantAPIs was called by getting the service options and evaluate EnableSwagger property
64+ var serviceOptions = applicationBuilder . ApplicationServices . GetRequiredService < IOptions < InstantAPIsServiceOptions > > ( ) . Value ;
65+ if ( serviceOptions == null || serviceOptions . EnableSwagger == null )
66+ {
67+ throw new ArgumentException ( "Call builder.Services.AddInstantAPIs(options) before MapInstantAPIs." ) ;
68+ }
69+
70+ var webApp = ( WebApplication ) app ;
71+ if ( serviceOptions . EnableSwagger == EnableSwagger . Always ||
72+ ( serviceOptions . EnableSwagger == EnableSwagger . DevelopmentOnly && webApp . Environment . IsDevelopment ( ) ) )
73+ {
74+ applicationBuilder . UseSwagger ( ) ;
75+ applicationBuilder . UseSwaggerUI ( ) ;
76+ }
77+
78+ var ctx = applicationBuilder . ApplicationServices . CreateScope ( ) . ServiceProvider . GetService ( typeof ( D ) ) as D ;
79+ var builder = new InstantAPIsConfigBuilder < D > ( ctx ) ;
80+ if ( options != null )
81+ {
82+ options ( builder ) ;
83+ Configuration = builder . Build ( ) ;
84+ }
85+ }
86+
87+ internal static IEnumerable < TypeTable > GetDbTablesForContext < D > ( ) where D : DbContext
88+ {
89+ return typeof ( D ) . GetProperties ( BindingFlags . Instance | BindingFlags . Public )
90+ . Where ( x => x . PropertyType . FullName . StartsWith ( "Microsoft.EntityFrameworkCore.DbSet" ) )
91+ . Select ( x => new TypeTable { Name = x . Name , InstanceType = x . PropertyType . GenericTypeArguments . First ( ) } )
92+ . ToArray ( ) ;
93+ }
94+
95+ internal class TypeTable
96+ {
97+ public string Name { get ; set ; }
98+ public Type InstanceType { get ; set ; }
99+ public ApiMethodsToGenerate ApiMethodsToGenerate { get ; set ; } = ApiMethodsToGenerate . All ;
100+ }
91101
92102}
0 commit comments