A light-weight REST API development framework for ASP.NET 6 and newer.
FastEndpoints needs sponsorship to sustain the project. Please help out if you can.
Please see the documentation for details of this feature.
Please see the documentation for details of this feature.
By default, deprecated endpoint versions are not included in swagger docs. Now you have the choice of including/displaying them in the doc so they'll be displayed greyed out like this:
Please see this usage example on how to enable it.
It is now possible to deliver an event to only just one of the connected remote subscribers in a round-robin fashion. Comes in handy when you need to distribute the workload among a pool of subscribers/workers and ensure that a single event is only processed by a single remote subscriber. See the documentation for more info.
The TestResult<TResponse>.Result
property is no longer a nullable property. This change enables us to get rid of the null-forgiving operator !
from our integration test code.
Existing test code wouldn't have to change. You just don't need to use the !
to hide the compiler warnings anymore. If/when the value of the property is actually null
, the tests will
just fail with a NRE, which is fine in the context of test code.
The type discovery generator is now highly efficient and only generates the source when any of the target types changes or new ones are added.
Authorization policy building is moved to the MapFastEndpoints
stage avoiding the need to iterate the discovered endpoint collection twice. This also avoids any potential race conditions due to different middleware pipeline config/ordering edge cases.
v5.16 had introduced a bug of not being able to inject IAuthorizationService
into endpoint classes, which has now been fixed.
Since you can override the exclusion list by doing:
.AddFastEndpoints(o.Assemblies = new[] { typeof(SomeClass).Assembly });
This was not working if the assembly name didn't have a dot (.) in the namespace.
The swagger operation processor was creating an example field with an empty string when there's no example provided by the user like the following:
"parameters": [
{
...
"example": ""
}
The swagger operation processor was creating an example field with the default value when there's no example or DefaultValue
provided by the user like the following:
"parameters": [
{
...
"example": 0
}
See code example and related issue: #480
Due to the startup optimization mentioned above, you will now be greeted with the following exception if your app is using authorization middleware:
Unhandled exception. System.InvalidOperationException: Unable to find the required services. Please add all the required services by calling 'IServiceCollection.AddAuthorization' in the application startup code.
It's because AddFastEndpoints()
used to do the AddAuthorization()
call internally which it no longer does. Simply add this call yourself to the middleware pipeline.
FastEndpoints needs sponsorship to sustain the project. Please help out if you can.
The auth policy builder was not being run when an endpoint only specifies a Policies(...)
config call.
TestFixture
type.FastEndpoints needs sponsorship to sustain the project. Please help out if you can.
Please see the documentation for details.
Swagger schema example was being auto generated for request parameters even if the field (DTO property) is nullable. See bug report here. Which is not the desired behavior.
Now the examples are only auto generated if developer hasn't decorated the property with a XML example or [DefaultValue(...)]
attribute for nullable properties.
Non-nullable properties will always get the example/default values filled in the following order: [DefaultValue(...)]
attribute > XML Comment > Auto generated example
The source generator no longer automatically discovers types from referenced assemblies/projects.
You now have to add the FastEndpoints.Generator
package to each project you'd like to use type discovery with and register the discovered types per assembly like so:
builder.Services.AddFastEndpoints(o =>
{
o.SourceGeneratorDiscoveredTypes.AddRange(MyApplication.DiscoveredTypes.All);
o.SourceGeneratorDiscoveredTypes.AddRange(SomeClassLib.DiscoveredTypes.All);
})
FastEndpoints needs sponsorship to sustain the project. Please help out if you can.
Both In-Proc
and RPC
based messaging functionality can now be easily integration tested by registering fake/test handlers during testing. See below links for examples of each:
Any auto discovered types (endpoints/commands/events/etc.) can be annotated with the attribute [DontRegister]
if you'd like it to be skipped while assembly scanning for auto registration.
public override void Configure()
{
...
SerializerContext<UpdateAddressCtx>();
}
By specifying just the type of the serializer context, instead of supplying an instance as with the existing method, the context will be created using the SerializerOptions
that you've configured at startup using the UseFastEndpoints(...)
call.
Take the following example request DTO:
sealed class MyRequest
{
[QueryParam]
public Nested ComplexObject { get; set; }
}
sealed class Nested
{
[DefaultValue(100)]
public int Id { get; set; }
[DefaultValue("John Doe")]
public string Name { get; set; }
[DefaultValue(new[] { 1, 2, 3 })]
public int[] Numbers { get; set; }
}
The following swagger spec example
will now be auto generated by default:
{
"paths": {
"/my-endpoint": {
"get": {
"parameters": [
{
"example": {
"id": 100,
"name": "John Doe",
"numbers": [ 1,2,3 ]
}
}
]
}
}
}
}
This behavior can be turned off like so:
builder.Services.SwaggerDocument(o =>
{
o.DocumentSettings = s =>
{
s.GenerateExamples = false;
};
});
Since NSwag still uses Newtonsoft internally, it is sometimes necessary to register custom converters for the NewtonSoft serializer, which can now be achieved like so:
.SwaggerDocument(o =>
{
o.NewtonsoftSettings = s =>
{
s.Converters.Add(new MyCustomConverter());
};
});
Any other Newtonsoft settings that needs to be tuned can also be accessed via the s
parameter.
See here for details about new project scaffolding with the Template Pack
.
EndpointData
when running concurrent integration testsEvent Handlers
when integration testingServiceResolver
is null due to incorrect unit test setupNested endpoints were previously ignored by the type discovery source generator. Thanks to Tomasz Chacuk we now have a more streamlined source generator that discovers nested types as well.
Due to an oversight in IEnumerable
iteration, the event handler constructor was being called twice per execution. Thank you Wahid Bitar for reporting it.
SerializerContext<TContext>()
was not properly making a copy of the global JsonSerializerOptions
when the serializer context was being instantiated; leading to the same global options instance being bound to multiple serializer contexts, which is not supported by the SDK as of .NET 7.0.
If app.MapControllers()
call was placed before the app.UseFastEndpoints()
call, the app would randomly throw a cryptic exception at startup. Now when this misconfiguration is detected, a clear exception would be thrown instructing the user to change the middleware order.
FastEndpoints needs sponsorship to sustain the project. Please help out if you can.
Please see the documentation here for details.
Please see the documentation here for details.
You can now use any IResult
returned from Results
static class of minimal apis.
[HttpGet("bad-result"), AllowAnonymous]
sealed class MyEndpoint : EndpointWithoutRequest
{
public override async Task HandleAsync(CancellationToken c)
{
await SendResultAsync(Results.BadRequest());
}
}
If you're are using the default in-memory event storage providers, the size limit of their internal queues can now be specified like so:
InMemoryEventQueue.MaxLimit = 1000;
This limit is applied per queue. Each event type in the system has it's own independent queue. If there's 10 events in the system, there will be 10X the number of events held in memory if they aren't being dequeued in a timely manner.
void
commands by utilizing a static EmptyObject
instance.SemaphoreSlim
s instead of Task.Delay(...)
for message pumpThere has been several implementation changes to the custom storage providers to provide a more user-friendly experience. Please see the updated doc page for the current usage.
FastEndpoints needs sponsorship to sustain the project. Please help out if you can.
Please see the documentation here for details.
Please see the documentation here for details.
You can now register your own TimeProvider implementation in the IOC container and the FastEndpoints.Security
package will use that implementation to obtain the current time for token creation. If no TimeProvider
is registered, the TimeProvider.System
default implementation is used. There's no need to wait for .NET 8.0 release since the TimeProvider
abstract class is already in a netstandard2.0
BCL package on nuget. #458
Please see the documentation here for details.
Thanks to Davor Rilko we now have a VSCode Extension for quickly scaffolding/expanding code snippets similarly to the VS Extension which has also been updated to bring the functionality up to par.
FastEndpoints needs sponsorship to sustain the project. Please help out if you can.
Remote procedure calls via ICommand
& ICommandHandler<TCommand>
is now possible which the initial RPC feature did not support. Command/Handler registration is done the same way:
//SERVER
app.MapHandlers(h =>
{
h.Register<SayHelloCommand, SayHelloHandler>();
});
//CLIENT
app.MapRemote("http://localhost:6000", c =>
{
c.Register<SayHelloCommand>();
});
//COMMAND EXECUTION
await new SayHelloCommand { From = "mars" }.RemoteExecuteAsync();
Please refer to the documentation for details of this feature.
Validator code such as the following was preventing the validator from being unit tested via the Factory.CreateValidator<T>()
method, which has now been fixed.
public class IdValidator : Validator<RequestDto>
{
public IdValidator()
{
using var scope = CreateScope();
var idChecker = scope.Resolve<IdValidationService>();
RuleFor(x => x.Id).Must((id)
=> idChecker.IsValidId(id));
}
}
Due to the introduction of remote Pub/Sub messaging (see new features above), it no longer made sense to call the method MapRemoteHandlers
as it now supports both remote handlers and event hubs.
app.MapRemoteHandlers(...) -> app.MapRemote(...)
FastEndpoints needs sponsorship to sustain the project. Please help out if you can.
Please refer to the documentation for details of this feature.
It's now possible to unit test endpoints (including dependencies) that use the Resolve<T>()
methods to resolve services from DI. This is especially helpful when resolving Scoped
services in Mapper
classes. Just register the services that need to be "Resolved" like so:
var ep = Factory.Create<Endpoint>(ctx =>
{
ctx.AddTestServices(s => s.AddTransient<MyService>());
});
An example mapper that uses the Resolve<T>()
method would be such as this:
public class Mapper : Mapper<Request, Response, Entity>
{
public override Entity ToEntity(Request r)
{
var mySvc = Resolve<MyService>();
}
}
Mappers & Validators that use the Resolve<T>()
methods to obtain services from the DI container can now be unit tested by supplying the necessary dependencies.
var validator = Factory.CreateValidator<AgeValidator>(s =>
{
s.AddTransient<AgeService>();
});
Use Factory.CreateMapper<TMapper>()
the same way in order to get a testable instance of a mapper.
New extension method overloads have been added to make it easier to add Roles
and Permissions
with params
and with tuples for Claims
when creating JWT tokens.
var jwtToken = JWTBearer.CreateToken(
priviledges: u =>
{
u.Roles.Add(
"Manager",
"Employee");
u.Permissions.Add(
"ManageUsers",
"ManageInventory");
u.Claims.Add(
("UserName", req.Username),
("Email", req.Email));
});
The unit testing Factory.Create<T>(...)
method will now inform which service you forgot to register if either the endpoint or one of the dependencies requires a service. In which case, you'd be registering that service like below:
var ep = Factory.Create<Endpoint>(ctx =>
{
ctx.AddTestServices(s => s.AddScoped<ScopedSvc>());
});
FastEndpoints needs sponsorship to sustain the project. Please help out if you can.
PublishAsync()
on a IEvent
type without a concrete event model type #info
.UseSwaggerGen(uiConfig: c => c.DeActivateTryItOut())
extension method to de-activate the try it out button by default.Factory.Create()
method #448httpContext.AddTestServices(...)
for cleaner test services registration with Factory.Create()
method #448UseFastEndpoints()
call overwriting the DI registered JsonOptions
#info
Throw*(404)
endpoint error short-circuit methods #450Asp.Versioning.Http
package via FastEndpoints.AspVersioning
#info
AddSwaggerDoc()
calls with SwaggerDocument(Action<DocumentOptions>)
. see deprecations below & example.IFormFile
support in OAS2 #info
the following methods have been deprecated but will still work until the next major version jump. you may however want to refactor your code as shown in the latest documentation, which will only take a few minutes.
FastEndpoints.Swagger.Extensions.AddSwaggerDoc()
in favor of SwaggerDocument(Action<DocumentOptions>)
FastEndpoints.Swagger.Extensions.EndpointFilter()
in favor of DocumentOptions.EndpointFilter
propertyFastEndpoints.Swagger.Extensions.TagDescriptions()
in favor of DocumentOptions.TagDescriptions
propertyFastEndpoints.Swagger.Extensions.EnableFastEndpoints()
in favor of EnableFastEndpoints(Action<DocumentOptions>)