Skip to content

Commit a1d1905

Browse files
authored
Dev (#34)
* - prune unused preperties - update docs * - configuration of endpoints and route groups no longer resolves components from service provider, instead uses RuntimeHelpers.GetUninitializedObject and DOES NOT resolve any of the componenets in ctor dependency injection. - remove unnecessary dependency * - add info to docs on dependencies resolved from constructor not being available during configuration. * - bump version
1 parent c18bed0 commit a1d1905

File tree

8 files changed

+62
-12
lines changed

8 files changed

+62
-12
lines changed

Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,6 @@
1818
<PackageLicenseExpression>MIT</PackageLicenseExpression>
1919
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
2020

21-
<Version>1.3.1</Version>
21+
<Version>1.3.2</Version>
2222
</PropertyGroup>
2323
</Project>

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,9 @@ Each endpoint must implement two virtual methods:
5757

5858
2. **HandleAsync**: Contains the logic to handle incoming requests. Called after the request is validated (if applicable).
5959

60-
> **Note**: `ServiceEndpoint` provides a default implementation for the `Configure` method, which can be overridden if necessary.
60+
> **Note**: Dependencies resolved from constructor are not available during configuration. To access a service from dependency injection in the configuration phase, use the `ServiceProvider` property of the configuration context parameter in the `Configure` method.
61+
62+
> **Note**: `ServiceEndpoint` provides a default implementation for the `Configure` method, and only requires `HandleAsync` method implementation.
6163
6264
---
6365

docs/EndpointTypes_MinimalEndpoint.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
>**Package**: `ModEndpoints.Core`
44
5-
MinimalEndpoint within `ModEndpoints.Core` package is closest to barebones Minimal API. Request model (if any) defined for a MinimalEndpoint is bound with [AsParameters] attribute. Its 'HandleAsync' method supports the following types of return values:
5+
MinimalEndpoint is the endpoint type that is most close to a Minimal API. Request model (if any) defined for a MinimalEndpoint is bound with [AsParameters] attribute. Its 'HandleAsync' method supports the following types of return values:
66

77
- string
88
- T (Any other type)

docs/RouteGroups.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ By default, all endpoints are mapped under root route group. It is possible to d
88

99
Following sample creates a parent route group (FeaturesRouteGroup), a child route group under it (BooksV1RouteGroup) and maps an endpoint (CreateBook) to child route group. Group configuration methods used for this particular sample are all part of Minimal APIs ecosystem and are under [Asp.Versioning](https://github.com/dotnet/aspnet-api-versioning).
1010

11+
> **Note**: Dependencies resolved from constructor are not available during configuration. To access a service from dependency injection in the configuration phase, use the `ServiceProvider` property of the configuration context parameter in the `Configure` method.
12+
1113
```csharp
1214
internal class FeaturesRouteGroup : RouteGroupConfigurator
1315
{

src/ModEndpoints.Core/DependencyInjectionExtensions.cs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Reflection;
2+
using System.Runtime.CompilerServices;
23
using Microsoft.AspNetCore.Builder;
34
using Microsoft.AspNetCore.Routing;
45
using Microsoft.Extensions.DependencyInjection;
@@ -63,12 +64,14 @@ private static IServiceCollection AddRouteGroupsCoreFromAssembly(
6364
{
6465
//Don't add RootRouteGroup, it's just a marker class to define root
6566
//Normally its assembly won't be loaded with this method anyway but just in case
66-
var serviceDescriptors = assembly
67+
var routeGroupTypes = assembly
6768
.DefinedTypes
6869
.Where(type => type is { IsAbstract: false, IsInterface: false } &&
6970
type.IsAssignableTo(typeof(IRouteGroupConfigurator)) &&
7071
type != typeof(RootRouteGroup) &&
71-
!type.GetCustomAttributes<DoNotRegisterAttribute>().Any())
72+
!type.GetCustomAttributes<DoNotRegisterAttribute>().Any());
73+
74+
var serviceDescriptors = routeGroupTypes
7275
.Select(type => ServiceDescriptor.DescribeKeyed(
7376
typeof(IRouteGroupConfigurator),
7477
type,
@@ -77,6 +80,7 @@ private static IServiceCollection AddRouteGroupsCoreFromAssembly(
7780
.ToArray();
7881

7982
services.TryAddEnumerable(serviceDescriptors);
83+
ComponentRegistry.Instance.TryAddRouteGroups(routeGroupTypes);
8084

8185
return services;
8286
}
@@ -162,6 +166,7 @@ static void AddServiceEndpoint(
162166
{
163167
services.TryAdd(descriptor);
164168
}
169+
ComponentRegistry.Instance.TryAddEndpoint(requestType, endpointType);
165170
}
166171

167172
static void AddEndpoint(
@@ -174,6 +179,7 @@ static void AddEndpoint(
174179
endpointType,
175180
endpointType,
176181
options.EndpointLifetime));
182+
ComponentRegistry.Instance.TryAddEndpoint(endpointType, endpointType);
177183
}
178184

179185
static Type[] GetGenericArgumentsOfBase(Type derivedType, Type baseType)
@@ -232,8 +238,8 @@ public static WebApplication MapModEndpointsCore(
232238
IEndpointRouteBuilder builder = app;
233239
using (var scope = builder.ServiceProvider.CreateScope())
234240
{
235-
var routeGroups = scope.ServiceProvider.GetKeyedServices<IRouteGroupConfigurator>(KeyedService.AnyKey);
236-
var endpoints = scope.ServiceProvider.GetKeyedServices<IEndpointConfigurator>(KeyedService.AnyKey);
241+
var routeGroups = ComponentRegistry.Instance.GetRouteGroups().Select(t => RuntimeHelpers.GetUninitializedObject(t) as IRouteGroupConfigurator).Where(i => i is not null).Select(i => i!); ;
242+
var endpoints = ComponentRegistry.Instance.GetEndpoints().Select(t => RuntimeHelpers.GetUninitializedObject(t) as IEndpointConfigurator).Where(i => i is not null).Select(i => i!);
237243

238244
//Items that don't have a membership to any route group or
239245
//items that have a membership to root route group (items at root)

src/ModEndpoints.Core/ModEndpoints.Core.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222

2323
<ItemGroup>
2424
<PackageReference Include="FluentValidation" Version="12.0.0" />
25-
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.5" />
2625
</ItemGroup>
2726

2827
<ItemGroup>
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
using System.Collections.Concurrent;
2+
3+
namespace ModEndpoints.Core;
4+
5+
internal class ComponentRegistry
6+
{
7+
private readonly ConcurrentDictionary<Type, Type> _routeGroups;
8+
private readonly ConcurrentDictionary<Type, Type> _endpoints;
9+
10+
private static Lazy<ComponentRegistry> _instance =
11+
new Lazy<ComponentRegistry>(
12+
() => new ComponentRegistry(),
13+
LazyThreadSafetyMode.ExecutionAndPublication);
14+
15+
public static ComponentRegistry Instance => _instance.Value;
16+
17+
private ComponentRegistry()
18+
{
19+
_routeGroups = new();
20+
_endpoints = new();
21+
}
22+
23+
public void TryAddRouteGroups(IEnumerable<Type> implementationTypes)
24+
{
25+
foreach (var type in implementationTypes)
26+
{
27+
_routeGroups[type] = type;
28+
}
29+
}
30+
31+
public void TryAddEndpoint(Type key, Type implementationType)
32+
{
33+
_endpoints[key] = implementationType;
34+
}
35+
36+
public ICollection<Type> GetRouteGroups()
37+
{
38+
return _routeGroups.Values;
39+
}
40+
41+
public ICollection<Type> GetEndpoints()
42+
{
43+
return _endpoints.Values;
44+
}
45+
}

src/ModEndpoints.Core/[Configuration]/RouteGroupConfigurator.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,6 @@ public abstract class RouteGroupConfigurator : IRouteGroupConfigurator
77
{
88
private RouteGroupConfigurationBuilder? _configurationBuilder;
99

10-
public virtual Action<RouteHandlerBuilder, ConfigurationContext<EndpointConfigurationParameters>>? EndpointConfigurationOverrides => null;
11-
12-
public virtual Action<RouteGroupBuilder, ConfigurationContext<RouteGroupConfigurationParameters>>? ConfigurationOverrides => null;
13-
1410
/// <summary>
1511
/// Entry point for route group configuration. Called by DI.
1612
/// </summary>

0 commit comments

Comments
 (0)