Skip to content

Commit fb3fb21

Browse files
authored
Attribute names (#3)
* - simplify route group member attribute name * - add MapMethods configuration method to EndpointConfigurator * - add parentRouteGroup parameter to IUriResolverProvider.GetResolver method * - bump version
1 parent 44bdc61 commit fb3fb21

30 files changed

+81
-53
lines changed

Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@
1717
<PackageReadmeFile>README.md</PackageReadmeFile>
1818
<PackageLicenseExpression>MIT</PackageLicenseExpression>
1919

20-
<Version>0.3.3</Version>
20+
<Version>0.4.0</Version>
2121
</PropertyGroup>
2222
</Project>

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ By default, all endpoints are mapped under root route group. It is possible to d
215215

216216
- [Create a route group implementation](./samples/ShowcaseWebApi/Features/FeaturesRouteGroup.cs) by inheriting RouteGroupConfigurator and implementing 'Configure' method,
217217
- Configuration of each route group implementation starts with calling MapGroup method with a route pattern prefix. The return of 'MapGroup' method, a RouteGroupBuilder instance, can be used to further customize the route group like a regular Minimal Api route group.
218-
- Apply RouteGroupMember attribute to either other [route group](./samples/ShowcaseWebApi/Features/Books/Configuration/BooksV1RouteGroup.cs) or [endpoint](./samples/ShowcaseWebApi/Features/Books/CreateBook.cs) classes that will be mapped under created route group. Use type of the new route group implementation as ParentGroupType property of attribute.
218+
- Apply MapToGroup attribute to either other [route group](./samples/ShowcaseWebApi/Features/Books/Configuration/BooksV1RouteGroup.cs) or [endpoint](./samples/ShowcaseWebApi/Features/Books/CreateBook.cs) classes that will be mapped under created route group. Use type of the new route group implementation as GroupType parameter to the attribute.
219219

220220
Following sample creates a parent route group (FeaturesRouteGroup), a child route group (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) .
221221

@@ -236,7 +236,7 @@ internal class FeaturesRouteGroup : RouteGroupConfigurator
236236
}
237237
}
238238

239-
[RouteGroupMember(typeof(FeaturesRouteGroup))]
239+
[MapToGroup(typeof(FeaturesRouteGroup))]
240240
internal class BooksV1RouteGroup : RouteGroupConfigurator
241241
{
242242
protected override void Configure(
@@ -249,7 +249,7 @@ internal class BooksV1RouteGroup : RouteGroupConfigurator
249249
}
250250
}
251251

252-
[RouteGroupMember(typeof(BooksV1RouteGroup))]
252+
[MapToGroup(typeof(BooksV1RouteGroup))]
253253
internal class CreateBook(ServiceDbContext db, ILocationStore location)
254254
: WebResultEndpoint<CreateBookRequest, CreateBookResponse>
255255
{

samples/ShowcaseWebApi/Features/Books/Configuration/BooksV1RouteGroup.cs

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

33
namespace ShowcaseWebApi.Features.Books.Configuration;
44

5-
[RouteGroupMember(typeof(FeaturesRouteGroup))]
5+
[MapToGroup(typeof(FeaturesRouteGroup))]
66
internal class BooksV1RouteGroup : RouteGroupConfigurator
77
{
88
protected override void Configure(

samples/ShowcaseWebApi/Features/Books/Configuration/BooksV2RouteGroup.cs

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

33
namespace ShowcaseWebApi.Features.Books.Configuration;
44

5-
[RouteGroupMember(typeof(FeaturesRouteGroup))]
5+
[MapToGroup(typeof(FeaturesRouteGroup))]
66
internal class BooksV2RouteGroup : RouteGroupConfigurator
77
{
88
protected override void Configure(

samples/ShowcaseWebApi/Features/Books/CreateBook.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public CreateBookRequestValidator()
2424
}
2525
}
2626

27-
[RouteGroupMember(typeof(BooksV1RouteGroup))]
27+
[MapToGroup(typeof(BooksV1RouteGroup))]
2828
internal class CreateBook(ServiceDbContext db, ILocationStore location)
2929
: WebResultEndpoint<CreateBookRequest, CreateBookResponse>
3030
{

samples/ShowcaseWebApi/Features/Books/DeleteBook.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public DeleteBookRequestValidator()
1717
}
1818
}
1919

20-
[RouteGroupMember(typeof(BooksV1RouteGroup))]
20+
[MapToGroup(typeof(BooksV1RouteGroup))]
2121
internal class DeleteBook(ServiceDbContext db)
2222
: WebResultEndpoint<DeleteBookRequest>
2323
{

samples/ShowcaseWebApi/Features/Books/GetBookById.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public GetBookByIdRequestValidator()
2020
}
2121
}
2222

23-
[RouteGroupMember(typeof(BooksV1RouteGroup))]
23+
[MapToGroup(typeof(BooksV1RouteGroup))]
2424
internal class GetBookById(ServiceDbContext db)
2525
: WebResultEndpoint<GetBookByIdRequest, GetBookByIdResponse>
2626
{

samples/ShowcaseWebApi/Features/Books/ListBooks.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace ShowcaseWebApi.Features.Books;
1010
public record ListBooksResponse(List<ListBooksResponseItem> Books);
1111
public record ListBooksResponseItem(Guid Id, string Title, string Author, decimal Price);
1212

13-
[RouteGroupMember(typeof(BooksV1RouteGroup))]
13+
[MapToGroup(typeof(BooksV1RouteGroup))]
1414
internal class ListBooks(ServiceDbContext db)
1515
: WebResultEndpointWithEmptyRequest<ListBooksResponse>
1616
{

samples/ShowcaseWebApi/Features/Books/UpdateBook.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public UpdateBookRequestValidator()
2525
}
2626
}
2727

28-
[RouteGroupMember(typeof(BooksV1RouteGroup))]
28+
[MapToGroup(typeof(BooksV1RouteGroup))]
2929
internal class UpdateBook(ServiceDbContext db)
3030
: WebResultEndpoint<UpdateBookRequest, UpdateBookResponse>
3131
{

samples/ShowcaseWebApi/Features/Books/UploadBook.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public UploadBookRequestValidator()
2020
}
2121
}
2222

23-
[RouteGroupMember(typeof(BooksV2RouteGroup))]
23+
[MapToGroup(typeof(BooksV2RouteGroup))]
2424
internal class UploadBook
2525
: WebResultEndpoint<UploadBookRequest, UploadBookResponse>
2626
{

samples/ShowcaseWebApi/Features/Stores/Configuration/StoresRouteGroup.cs

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

33
namespace ShowcaseWebApi.Features.Stores.Configuration;
44

5-
[RouteGroupMember(typeof(FeaturesRouteGroup))]
5+
[MapToGroup(typeof(FeaturesRouteGroup))]
66
internal class StoresRouteGroup : RouteGroupConfigurator
77
{
88
protected override void Configure(

samples/ShowcaseWebApi/Features/Stores/CreateStore.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public CreateStoreRequestValidator()
2020
}
2121
}
2222

23-
[RouteGroupMember(typeof(StoresRouteGroup))]
23+
[MapToGroup(typeof(StoresRouteGroup))]
2424
internal class CreateStore(ServiceDbContext db)
2525
: BusinessResultEndpoint<CreateStoreRequest, CreateStoreResponse>
2626
{

samples/ShowcaseWebApi/Features/Stores/DeleteStore.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public DeleteStoreRequestValidator()
1717
}
1818
}
1919

20-
[RouteGroupMember(typeof(StoresRouteGroup))]
20+
[MapToGroup(typeof(StoresRouteGroup))]
2121
internal class DeleteStore(ServiceDbContext db)
2222
: BusinessResultEndpoint<DeleteStoreRequest>
2323
{

samples/ShowcaseWebApi/Features/Stores/GetStoreById.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public GetStoreByIdRequestValidator()
1919
}
2020
}
2121

22-
[RouteGroupMember(typeof(StoresRouteGroup))]
22+
[MapToGroup(typeof(StoresRouteGroup))]
2323
internal class GetStoreById(ServiceDbContext db)
2424
: BusinessResultEndpoint<GetStoreByIdRequest, GetStoreByIdResponse>
2525
{

samples/ShowcaseWebApi/Features/Stores/ListStores.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace ShowcaseWebApi.Features.Stores;
1010
public record ListStoresResponse(List<ListStoresResponseItem> Stores);
1111
public record ListStoresResponseItem(Guid Id, string Name);
1212

13-
[RouteGroupMember(typeof(StoresRouteGroup))]
13+
[MapToGroup(typeof(StoresRouteGroup))]
1414
internal class ListStores(ServiceDbContext db)
1515
: BusinessResultEndpointWithEmptyRequest<ListStoresResponse>
1616
{

samples/ShowcaseWebApi/Features/Stores/UpdateStore.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public UpdateStoreRequestValidator()
2323
}
2424
}
2525

26-
[RouteGroupMember(typeof(StoresRouteGroup))]
26+
[MapToGroup(typeof(StoresRouteGroup))]
2727
internal class UpdateStore(ServiceDbContext db)
2828
: BusinessResultEndpoint<UpdateStoreRequest, UpdateStoreResponse>
2929
{

samples/ShowcaseWebApi/Features/StoresWithServiceEndpoint/Configuration/StoresWithServiceEndpointRouteGroup.cs

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

33
namespace ShowcaseWebApi.Features.StoresWithServiceEndpoint.Configuration;
44

5-
[RouteGroupMember(typeof(FeaturesRouteGroup))]
5+
[MapToGroup(typeof(FeaturesRouteGroup))]
66
internal class StoresWithServiceEndpointRouteGroup : RouteGroupConfigurator
77
{
88
protected override void Configure(

samples/ShowcaseWebApi/Features/StoresWithServiceEndpoint/CreateStore.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public CreateStoreRequestValidator()
1616
}
1717
}
1818

19-
[RouteGroupMember(typeof(StoresWithServiceEndpointRouteGroup))]
19+
[MapToGroup(typeof(StoresWithServiceEndpointRouteGroup))]
2020
internal class CreateStore(ServiceDbContext db)
2121
: ServiceEndpoint<CreateStoreRequest, CreateStoreResponse>
2222
{

samples/ShowcaseWebApi/Features/StoresWithServiceEndpoint/DeleteStore.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public DeleteStoreRequestValidator()
1616
}
1717
}
1818

19-
[RouteGroupMember(typeof(StoresWithServiceEndpointRouteGroup))]
19+
[MapToGroup(typeof(StoresWithServiceEndpointRouteGroup))]
2020
internal class DeleteStore(ServiceDbContext db)
2121
: ServiceEndpoint<DeleteStoreRequest>
2222
{

samples/ShowcaseWebApi/Features/StoresWithServiceEndpoint/GetStoreById.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public GetStoreByIdRequestValidator()
1717
}
1818
}
1919

20-
[RouteGroupMember(typeof(StoresWithServiceEndpointRouteGroup))]
20+
[MapToGroup(typeof(StoresWithServiceEndpointRouteGroup))]
2121
internal class GetStoreById(ServiceDbContext db)
2222
: ServiceEndpoint<GetStoreByIdRequest, GetStoreByIdResponse>
2323
{

samples/ShowcaseWebApi/Features/StoresWithServiceEndpoint/ListStores.cs

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

99
namespace ShowcaseWebApi.Features.StoresWithServiceEndpoint;
1010

11-
[RouteGroupMember(typeof(StoresWithServiceEndpointRouteGroup))]
11+
[MapToGroup(typeof(StoresWithServiceEndpointRouteGroup))]
1212
internal class ListStores(ServiceDbContext db)
1313
: ServiceEndpoint<ListStoresRequest, ListStoresResponse>
1414
{

samples/ShowcaseWebApi/Features/StoresWithServiceEndpoint/UpdateStore.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public UpdateStoreRequestValidator()
1818
}
1919
}
2020

21-
[RouteGroupMember(typeof(StoresWithServiceEndpointRouteGroup))]
21+
[MapToGroup(typeof(StoresWithServiceEndpointRouteGroup))]
2222
internal class UpdateStore(ServiceDbContext db)
2323
: ServiceEndpoint<UpdateStoreRequest, UpdateStoreResponse>
2424
{

src/ModEndpoints.Core/DependencyInjectionExtensions.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -130,9 +130,9 @@ public static WebApplication MapModEndpointsCore(
130130
//Items that don't have a membership to any route group or
131131
//items that have a membership to root route group (items at root)
132132
Func<Type, bool> typeIsNotMemberOfAnyRouteGroupPredicate =
133-
x => !x.GetCustomAttributes<RouteGroupMemberAttribute>().Any() ||
134-
x.GetCustomAttributes<RouteGroupMemberAttribute>().Any(
135-
a => a.ParentGroupType == typeof(RootRouteGroup));
133+
x => !x.GetCustomAttributes<MapToGroupAttribute>().Any() ||
134+
x.GetCustomAttributes<MapToGroupAttribute>().Any(
135+
a => a.GroupType == typeof(RootRouteGroup));
136136

137137
_ = MapInternal(
138138
scope.ServiceProvider,
@@ -227,8 +227,8 @@ private static RouteGroupBuilder Map(
227227
{
228228
//Items having membership to this route group
229229
Func<Type, bool> typeIsMemberOfCurrentGroupPredicate =
230-
x => x.GetCustomAttributes<RouteGroupMemberAttribute>().Any(
231-
a => a.ParentGroupType == routeGroup.GetType());
230+
x => x.GetCustomAttributes<MapToGroupAttribute>().Any(
231+
a => a.GroupType == routeGroup.GetType());
232232

233233
//Pass this group as current route group
234234
_ = MapInternal(

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,4 +120,21 @@ protected RouteHandlerBuilder MapPatch(string pattern)
120120
: _builder.MapPatch(pattern, ExecuteDelegate);
121121
return _handlerBuilder;
122122
}
123+
124+
/// <summary>
125+
/// To be used in "Configure" overload method to add a <see cref="RouteEndpoint"/>
126+
/// to the application <see cref="IEndpointRouteBuilder"/>, that matches requests with
127+
/// specified HTTP methods for the specified pattern.
128+
/// </summary>
129+
/// <param name="pattern"></param>
130+
/// <param name="httpMethods"></param>
131+
/// <returns>A <see cref="RouteHandlerBuilder"/> that can be used to further customize the endpoint.</returns>
132+
/// <exception cref="InvalidOperationException"></exception>
133+
protected RouteHandlerBuilder MapMethods(string pattern, IEnumerable<string> httpMethods)
134+
{
135+
_handlerBuilder = _builder is null
136+
? throw new InvalidOperationException(string.Format(Constants.RouteBuilderIsNullForEndpointMessage, GetType()))
137+
: _builder.MapMethods(pattern, httpMethods, ExecuteDelegate);
138+
return _handlerBuilder;
139+
}
123140
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
namespace ModEndpoints.Core;
2+
3+
/// <summary>
4+
///
5+
/// </summary>
6+
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
7+
public class MapToGroupAttribute : Attribute
8+
{
9+
public Type GroupType { get; init; }
10+
public MapToGroupAttribute(Type GroupType)
11+
{
12+
if (!GroupType.IsAssignableTo(typeof(IRouteGroupConfigurator)))
13+
{
14+
throw new ArgumentException(
15+
Constants.ParentRouteGroupInvalidMessage,
16+
nameof(GroupType));
17+
}
18+
this.GroupType = GroupType;
19+
}
20+
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
/// <summary>
44
/// Root route marker class to let other groups and endpoints to define a membership to.
55
/// By default all groups and endpoints are members under root.
6-
/// However if a group membership is defined on them via <see cref="RouteGroupMemberAttribute"/>,
6+
/// However if a group membership is defined on them via <see cref="MapToGroupAttribute"/>,
77
/// causing them to not me a member of root anymore,
88
/// this marker is here to enable them being member of root directly
99
/// in addition to their other memberships.

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

Lines changed: 0 additions & 20 deletions
This file was deleted.

src/ModEndpoints/[ServiceEndpoint]/DefaultUriResolverProvider.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ public class DefaultUriResolverProvider :
1010
{
1111
public IServiceEndpointUriResolver GetResolver(
1212
IServiceProvider serviceProvider,
13+
IRouteGroupConfigurator? parentRouteGroup,
1314
ServiceEndpointConfigurator endpoint)
1415
{
1516
var resolverName = GetResolverName(endpoint);

src/ModEndpoints/[ServiceEndpoint]/IUriResolverProvider.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@ public interface IUriResolverProvider
1313
/// that will be used to determine the uri, endpoint will be mapped to.
1414
/// </summary>
1515
/// <param name="serviceProvider"></param>
16+
/// <param name="parentRouteGroup"></param>
1617
/// <param name="endpoint"></param>
1718
/// <returns></returns>
18-
IServiceEndpointUriResolver GetResolver(IServiceProvider serviceProvider, ServiceEndpointConfigurator endpoint);
19+
IServiceEndpointUriResolver GetResolver(
20+
IServiceProvider serviceProvider,
21+
IRouteGroupConfigurator? parentRouteGroup,
22+
ServiceEndpointConfigurator endpoint);
1923
}

src/ModEndpoints/[ServiceEndpoint]/ServiceEndpoint.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,10 @@ protected override ValueTask<Result<TResultValue>> HandleInvalidValidationResult
2929
IRouteGroupConfigurator? parentRouteGroup)
3030
{
3131
var uriResolverProvider = serviceProvider.GetRequiredService<IUriResolverProvider>();
32-
var uriResolver = uriResolverProvider.GetResolver(serviceProvider, this);
32+
var uriResolver = uriResolverProvider.GetResolver(
33+
serviceProvider,
34+
parentRouteGroup,
35+
this);
3336
var patternResult = uriResolver.Resolve<TRequest>();
3437
if (patternResult.IsOk)
3538
{
@@ -58,7 +61,10 @@ protected override ValueTask<Result> HandleInvalidValidationResultAsync(
5861
IRouteGroupConfigurator? parentRouteGroup)
5962
{
6063
var uriResolverProvider = serviceProvider.GetRequiredService<IUriResolverProvider>();
61-
var uriResolver = uriResolverProvider.GetResolver(serviceProvider, this);
64+
var uriResolver = uriResolverProvider.GetResolver(
65+
serviceProvider,
66+
parentRouteGroup,
67+
this);
6268
var patternResult = uriResolver.Resolve<TRequest>();
6369
if (patternResult.IsOk)
6470
{

0 commit comments

Comments
 (0)