EndpointMapper 2.0.0-prerelease.2
EndpointMapper 2.0.0-prerelease.3
Additional DetailsThis version has been deprecated in favor or 2.0.0-prerelease.3
See the version list below for details.
dotnet add package EndpointMapper --version 2.0.0-prerelease.2
NuGet\Install-Package EndpointMapper -Version 2.0.0-prerelease.2
<PackageReference Include="EndpointMapper" Version="2.0.0-prerelease.2" />
paket add EndpointMapper --version 2.0.0-prerelease.2
#r "nuget: EndpointMapper, 2.0.0-prerelease.2"
// Install EndpointMapper as a Cake Addin #addin nuget:?package=EndpointMapper&version=2.0.0-prerelease.2&prerelease // Install EndpointMapper as a Cake Tool #tool nuget:?package=EndpointMapper&version=2.0.0-prerelease.2&prerelease
EndpointMapper
Build on top of Minimal APIs and designed to be as easy to use as possible
Installation
Add the package to your ASP.NET Core project
dotnet add package EndpointMapper
Requirements
- .NET 7
- ASP.NET Core 7
Usage
Add into the Program.cs
builder.Services.AddEndpointMapper<T>();
app.UseEndpointMapper();
Then create a public class that implements IEndpoint
and add a method with attribute HttpMapGet
or one of the variants for each HTTP verb
Note: see Samples for an example
Note:
If you want to use bind parameters to the method function see this section
If you want to use dependency injection see this section
If you want to use Swagger see this section
Sample
Program.cs:
using EndpointMapper;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddEndpointMapper<Program>();
var app = builder.Build();
app.UseEndpointMapper();
app.Run();
Then create a file, in this case it's the root of the project but could be any folder
ExampleEndpoint.cs:
using EndpointMapper;
public class ExampleEndpoint : IEndpoint
{
[HttpMapGet("/example")]
public Ok<string> Handle()
{
return TypedResults.Ok("Hello world from EndpointMapper");
}
}
Note: If you want to bind values from the request into params of the request see this
Parameters Binding and function return
Since EndpointMapper uses the native ASP.NET delegate system to map your endpoint and make them work, so you can threat
your method like the inline delegate to the app.MapGet(...)
method.
So you can do
- Http Body, Query, Route, Headers binding into the function arguments
- Dependency Injection (for more details see this section)
- Attributes like
[FromBody]
or[FromQuery]
to explicitly map the required values into arguments - Return using the
Results
orTypedResults
methods or directly astring
or any other values that ASP.NET automatically can translate into a valid HTTP response body
An example of this can be seen in the example where it's used TypedResults to send an 200 Status code
response back with attached a body that contains a string saying Hello world from EndpointMapper
Dependency Injection
While you can use the method parameters to inject your services to be used, if you prefer you still can use the constructor of the class you created to resolve your services and map them to a private readonly field for example.
This is done by EndpointMapper using a middleware, the middleware is registered by-default when using the
.UseEndpointMapper()
on the WebApplication
, but if you don't want to add it to the middleware pipeline and you
don't want to use the constructor based DI then you can pass a false
to the method like this:
.UseEndpointMapper(addMiddleware: false)
Warning As sayed above setting this to false will skip the DI resolution using the middleware, and since EndpointMapper creates the endpoint classes during the
.UseEndpointMapper()
method, and the classes are created uninitialized all the fields will be null (unless the field has a default value) and the non static constructor wont be called. So if you need to use a constructor to initialize something and for some reason you can't do it using a default value then setting addMiddleware to false may cause unexpected behaviour, keep in mind that static constructor will be called and will function as normal, as them are called by the .NET runtime
Note You could just pass false and don't add the "addMiddleware: " part, but for readability purposes it's kept in here to make it easier to understand what this false actually means
OpenAPI support (swagger)
EndpointMapper only supports Swashbuckle.AspNetCore
[^template], but it's support is out-of-the-box and don't require
any additional package to work (except Swashbuckle.AspNetCore
obviously)
Warning For authentication or XML documentation you may need to add some code to your
.AddSwaggerGen(...)
call
XML documentation
You will need to add:
To your
.csproj
<GenerateDocumentationFile>true</GenerateDocumentationFile>
to generate the XML file to use- Optionally,
<NoWarn>$(NoWarn);CS1591</NoWarn>
to disable the warningMissing XML comment for publicly visible type or member 'Type_or_Member'
To the
.AddSwaggerGen()
call
// Get the XML file path from the Assembly
var xmlFilename = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
// Add the comments into the generation for the OpenApi scheme
config.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename), includeControllerXmlComments: true);
Note You may need to add
using System.Reflection;
because we use theAssembly
class that lives in theSystem.Reflection
namespace
Note In the code you need to add the action passed as first argument to
.AddSwaggerGen()
,config
it's the name of the variable to witch theSwaggerGenOption
instance is bound, if you named it in another way you need to change the code accordingly, if you are unsure there is an example of the complete call to.AddSwaggerGen()
to the end of the swagger section
[^template]: That in .NET 7 the ASP.NET template also uses Microsoft.AspNetCore.OpenApi
Authentication requirements
If you have authentication in your application you need to let swagger known how to authenticate against it, so you
need to add to the .AddSwaggerGen()
call the registration of Security Definition and if you use the ASP.NET
[Authorize]
attribute you may also need to add some code to detect the attribute and add the requirement
EndpointMapper provides you an operation filter to add those requirements automatically when it detects the
[Authorize]
attribute, if you manually check for authentication using a Filter or something else then this is not
needed, and you will need something else to add the requirements
The only code you will need to add to your .AddSwaggerGen()
call is the following
// Add the security definition with name Bearer and the following options
config.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Name = "Bearer JWT",
Type = SecuritySchemeType.Http,
In = ParameterLocation.Header,
Scheme = "Bearer"
});
// Add the operationFilter to add the authentication requirements where needed
config.OperationFilter<AuthenticationRequirementOperationFilter>();
Note In the code you need to add the action passed as first argument to
.AddSwaggerGen()
,config
it's the name of the variable to witch theSwaggerGenOption
instance is bound, if you named it in another way you need to change the code accordingly, if you are unsure there is an example of the complete call to.AddSwaggerGen()
to the end of the swagger section
AddSwaggerGen example call
This is an example call to the .AddSwaggerGen()
method witch has both XML comments integration and user authentication
This call is here to help understand the code snippet(s) in the context of the whole call, you may not copy-paste all
the function as (especially the authentication stuff) requires edits based on your application needs, if you want more
context you can refer to the EndpointMapper.TestApplication/Program.cs
file
// builder is the variable assigned to the return value of "WebApplication.CreateBuilder()"
builder.Services.AddSwaggerGen(config =>
{
// Add the security definition with name Bearer and the following options
config.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Name = "Bearer JWT",
Type = SecuritySchemeType.Http,
In = ParameterLocation.Header,
Scheme = "Bearer"
});
// Add the operationFilter to add the authentication requirements where needed
config.OperationFilter<AuthenticationRequirementOperationFilter>();
// Get the XML file path from the Assembly
var xmlFilename = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
// Add the comments into the generation for the OpenApi scheme
config.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename), includeControllerXmlComments: true);
});
Advanced
Method based configuration
You may want to add a OutputCaching policy, but there is a problem: since parameters to attributes can only be compile-time constant value, we can't pass an action to configure the caching and for this reason we would need to define a policy for each and every endpoint
That is not practical at all. It will bloat your application with policies used in 1 or maybe 2 places, that in some context can be totally fine, as it gives a central access to all the policies, but you may not want this
For this reason EndpointMapper when maps an endpoint first checks for attributes extending
EndpointConfigurationAttribute
to add some attribute that may be missing in ASP.NET, like [Filter<T>]
and then runs
the Configure
method that is in your class, where you have the RouteHandlerBuilder
and you can do
whatever you want with it, for example, setting a policy for OutputCaching, the only thing you need to do is creating
the Configure(RouteHandlerBuilder)
method and add your own logic for configuring the endpoint
Warning If you registered your endpoint with the
Register(IEndpointRouteBuilder)
method EndpointMapper won't call theConfigure(RouteHandlerBuilder)
and you will need to do your configuration in theRegister
method
Note Since this method is for class and with EndpointMapper you can add more then one handler function to the class, even though it is not recommended, the
Configure
method will be called for each endpoint mapped independently from if it's a different function[^different-function], if it's is for the second / third / ... route of the attribute[^multiple-routes] or if it's the same method with 2 different mapping attributes that map to different HTTP methods[^different-attributes], all of there 3 cases mixes, so let's assume you have 2 method, each with 3 routes and 2 attribute, then theConfigure
will be called 12 times in total[^explanation-for-12-call].To get more control on what configuration is applied where, you could split the endpoints in multiple files or using one of the
Configure
overloads that gives information about the current endpoint that is being configured, there are 3 overload in total, ignoring the base one, each one adds one information on top of the builder, the route, the HTTP methods and finally the MethodInfo
[^different-function]: example, you have 2 methods, Handle
and HandleButDifferent
and you map both with an
[HttpMapGet]
, EndpointMapper will call the Configure
first for Handle
and its Get mapping, then for
HandleButDifferent
and its Get mapping
[^multiple-routes]: example, you have a Handle
method with [HttpMapGet("/a", "/b")]
,
EndpointMapper will call the Configure
first for /a, then for /b again
[^different-attributes]: example, you have a Handle
method with [HttpMapGet("/"), HttpMapPost("/")]
, EndpointMapper
will call the Configure
first for the Get mapping, then for the Post mapping, BUT if the attribute that you use for
mapping implies multiple HTTP verb, like an attribute named [HttpMapGetAndPost("/")]
that bind your endpoint to
both Get and Post then EndpointMapper will call Configure
only once for this method because it's in fact a single
attribute
[^explanation-for-12-call]: explanation of why 12, first we get the first method, it has 2 attributes, we take the
first, we get the 3 routes and as stated in the second rule[^multiple-routes] we call it 3 times total, then we get the
second attributes and call the Configure
other 3 times for the second rule[^multiple-routes], and this was the third
rule[^different-attributes] (the 2 attributes) and we have already called the Configure
6 times, then to respect the
first rule[^different-function] we need to this again, and we get another 6 calls, up to a total of 12
Method based registration
If you don't like the fact that EndpointMapper uses attributes to map your endpoints or you need to map to a HTTP verb
that does not have an attribute then you can override the Register
method on the class implementing IEndpoint
that gives you the IEndpointRouteBuilder
witch has access to methods like .MapGet()
Warning Don't use
Register(IEndpointRouteBuilder)
if you need to configure stuff like OutputCaching that can accept an action to configure it's behaviour without creating a policy, for this there is theConfigure(RouteHandlerBuilder)
method instead, you can see more about this here
Note EndpointMapper checks for both Attributes and
Register
to register your endpoints
Note If you use a debugger, you will see that the actual type that EndpointMapper uses to call the method is
RouteGroupBuilder
, this is because to respect the configuration ofRoutePrefix
EndpointMapper uses a minimal api group to map all your endpoint, you could cast the type back toRouteGroupBuilder
using an hard cast and use the builder to, for example, configure the group with some behaviour settings, for example setting a default output cache policy, although this is NOT encouraged because it can be pretty easy to forget about this code and since it's in a endpoint class you are configuring the group from and endpoint witch is not that great, since you may still want to configure some behaviour in the group, in the.AddEndpointMapper()
call you can pass an action witch gives you the ability to configure EndpointMapper configuration and in there you can set theConfigureGroupBuilder
action to configure the group, it gives you the fullRouteGroupBuilder
without having to cast it and it wont "belong" to any Endpoint that may be deleted later for any reason
Create your own EndpointConfigurationAttribute
Simple create a class that extends EndpointConfigurationAttribute
EndpointConfigurationAttribute
requires you to implement a method called Configure
where you have access to the
RouteHandlerBuilder
from ASP.NET to configure the route, the rest is handled automatically
Create your own HttpMapAttribute
Simple create a class that extends HttpMapAttribute
and use : base()
on the constructor to pass the route(s)
and overload the Methods
propriety to set the list of HTTP Verb that the attribute correspond to, the verb MUST be
supported by ASP.NET or else it wont work, the rest is handled automatically
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net7.0 is compatible. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
-
net7.0
- JetBrains.Annotations (>= 2022.3.1)
- Microsoft.OpenApi (>= 1.6.3)
- Swashbuckle.AspNetCore.SwaggerGen (>= 6.5.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated | |
---|---|---|---|
2.0.0 | 2,267 | 11/14/2023 | |
2.0.0-prerelease.4 | 104 | 10/24/2023 | |
2.0.0-prerelease.3 | 122 | 8/15/2023 | |
2.0.0-prerelease.2 | 123 | 3/29/2023 | |
2.0.0-prerelease.1 | 135 | 3/25/2023 | |
1.0.1 | 302 | 12/8/2022 | |
1.0.0 | 287 | 12/8/2022 |