Releases: FastEndpoints/FastEndpoints
v5.19.1 Patch Release
Fixes 🪲
Auto binding collections of form files fails after first request
An object disposed error was being thrown in subsequent requests for file collection submissions due to a flaw in the model binding logic, which has now been corrected.
v5.19 Release
✨ Looking For Sponsors ✨
FastEndpoints needs sponsorship to sustain the project. Please help out if you can.
New 🎉
Model binding collections of 'IFormFile' from incoming form data
The following types of properties can now be automatically model bound from file
form data fields.
class Request
{
public IEnumerable<IFormFile> Cars { get; set; }
public List<IFormFile> Boats { get; set; }
public IFormFileCollection Jets { get; set; }
}
When submitting collections of form files, the incoming field names can be one of the following 3 formats:
Format One | Format Two | Format Three | |
---|---|---|---|
# 1 | Cars | Boats[1] | Jets[] |
# 2 | Cars | Boats[2] | Jets[] |
Multiple request examples for Swagger
Multiple examples for the request DTO can be specified by either setting the ExampleRequest
property of the Summary class multiple times or adding to
the RequestExamples
collection like so:
Summary(s =>
{
s.ExampleRequest = new MyRequest {...};
s.ExampleRequest = new MyRequest {...};
s.RequestExamples.Add(new MyRequest {...});
});
Anti-forgery token validation middleware
Please see the documentation page for details of this feature.
Thank you Wàn Yǎhǔ for the contribution.
Support for simple validation with 'DataAnnotations'
//enable the feature at startup.
app.UseFastEndpoints(c.Validation.EnableDataAnnotationsSupport = true;)
//decorate properties with DataAnnotations attributes
sealed class Request
{
[Required, StringLength(10, MinimumLength = 2)]
public string Name { get; set; }
}
//can be used together with `FluentValidations` rules
sealed class MyValidator : Validator<Request>
{
public MyValidator()
{
RuleFor(x => x.Id).InclusiveBetween(10, 100);
}
}
Note: there's no swagger integration for data annotations.
Thank you Wàn Yǎhǔ for the contribution.
Improvements 🚀
Prevent swallowing of STJ exceptions in edge cases
If STJ throws internally after it has started writing to the response stream, those exceptions will no longer be swallowed.
This can happen in rare cases such as when the DTO being serialized has an infinite recursion depth issue.
Deep nested collection property name serialization support with 'AddError(expression, ...)' method
When doing a manual add error call like this:
AddError(r => r.ObjectArray[i].Test, "Some error message");
Previous output was:
New output:
Thank you Mattis Bratland for the contribution
Misc. improvements
- Upgrade dependencies to latest
- Minor internal code refactors/optimizations
Fixes 🪲
Response DTO property description not being detected
When the response DTO property description was provided by a lambda expression and the respective DTO property is also decorated with [JsonPropertyName]
attribute,
the Swagger operation processor was not correctly setting the property description in generated Swagger spec. See #511 for more details.
v5.18 Release
✨ Looking For Sponsors ✨
FastEndpoints needs sponsorship to sustain the project. Please help out if you can.
New 🎉
Source generated DI registrations
Please see the documentation for details of this feature.
Source generated access control lists
Please see the documentation for details of this feature.
Ability to show deprecated endpoint versions in Swagger
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.
Round-Robin Event delivery with gRPC
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.
Improvements 🚀
Ability to get rid of null-forgiving operator '!' from test code
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.
Optimize source generator performance
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.
Optimize startup routine
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.
Fixes 🪲
Startup issue due to 'IAuthorizationService' injection
v5.16 had introduced a bug of not being able to inject IAuthorizationService
into endpoint classes, which has now been fixed.
Startup type discovery issue with exclusion list
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.
Empty swagger parameter example generation
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": ""
}
Swagger parameter example generation with default values
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
}
Allow customizing serialization/deserialization of Event/Command objects in Job/Event Queue storage
See code example and related issue: #480
Minor Breaking Change ⚠️
'AddFastEndpoints()' no longer calls 'AddAuthorization()'
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.
v5.17.1 Release
✨ Looking For Sponsors ✨
FastEndpoints needs sponsorship to sustain the project. Please help out if you can.
🪲 Fixes
Auth policy not found bug
The auth policy builder was not being run when an endpoint only specifies a Policies(...)
config call.
🚀 Improvements
Internal optimizations in 'FastEndpoints.Testing' package
- Prevent duplicate WAFs from being created for a single
TestFixture
type.
v5.17 Release
✨ Looking For Sponsors ✨
FastEndpoints needs sponsorship to sustain the project. Please help out if you can.
🔖 New
'FastEndpoints.Testing' package for convenient Integration testing
Please see the documentation for details.
🪲 Fixes
Example generation for swagger nullable request params
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
⚠️ Minor Breaking Changes
Type discovery source generator behavior change
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);
})
v5.16 Release
✨ Looking For Sponsors ✨
FastEndpoints needs sponsorship to sustain the project. Please help out if you can.
🔖 New
Integration testing with fake/test handlers for messaging features
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:
[DontRegister] attribute for skipping auto registration
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.
Auto instantiation of 'JsonSerializerContext' with global 'SerializerOptions'
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.
Auto generation of examples for swagger request parameters
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;
};
});
NSwag serializer (Newtonsoft) customization
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.
Starter Project Templates
See here for details about new project scaffolding with the Template Pack
.
🚀 Improvements
Minor performance optimizations
- Job queue message pump improvements
- Startup code optimizations
Concurrent WAF testing
- Better thread safety of
EndpointData
when running concurrent integration tests - Avoid potential contention issues for
Event Handlers
when integration testing
Unit testing improvements
- Warn user if internal
ServiceResolver
is null due to incorrect unit test setup
Nested type discovery for source generator
Nested 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.
🪲 Fixes
Event handler constructors being called twice
Due to an oversight in IEnumerable
iteration, the event handler constructor was being called twice per execution. Thank you Wahid Bitar for reporting it.
Json serializer context was not correctly copying 'JsonSerializerOptions'
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.
Startup exception edge case
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.
v5.15 Release
✨ Looking For Sponsors ✨
FastEndpoints needs sponsorship to sustain the project. Please help out if you can.
📢 New
Job Queues for background processing of commands
Please see the documentation here for details.
TypedResults (union type) support for endpoints
Please see the documentation here for details.
Support for IResult via SendResultAsync() method
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());
}
}
🚀 Improvements
Allow customization of in-memory event queue size
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.
Remote messaging performance improvements
- Refactor logging to use code generated high performance logging.
- Reduce allocations for
void
commands by utilizing a staticEmptyObject
instance.
Event Queues internal optimizations
- Use
SemaphoreSlim
s instead ofTask.Delay(...)
for message pump
Misc. performance improvements
- Reduce boxing/unboxing in a few hot paths.
⚠️ Minor Breaking Changes
Event Queue storage provider API changes
There 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.
v5.14 Release
⭐ Looking For Sponsors
FastEndpoints needs sponsorship to sustain the project. Please help out if you can.
📢 New
1️⃣ gRPC based Event Broker functionality
Please see the documentation here for details.
2️⃣ Ability to subscribe to exceptions in Event Queues
Please see the documentation here for details.
3️⃣ Support for TimeProvider in FastEndpoints.Security package
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
4️⃣ Support for Asp.Versioning.Http package
Please see the documentation here for details.
5️⃣ Visual Studio Code Extension
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.
🚀 Improvements
1️⃣ Optimize Event Queue internals
2️⃣ Upgrade dependencies to latest
v5.13 Release
⭐ Looking For Sponsors
FastEndpoints needs sponsorship to sustain the project. Please help out if you can.
📢 New
1️⃣ Support for RPC Commands that do not return any result
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();
2️⃣ Reliable remote Pub/Sub event queues
Please refer to the documentation for details of this feature.
🪲 Fixes
1️⃣ Scope creation in a Validator was throwing an exception in unit tests
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));
}
}
⚠️ Minor Breaking Changes
1️⃣ RPC remote connection configuration method renamed
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(...)
v5.12 Release
⭐ Looking For Sponsors
FastEndpoints needs sponsorship to sustain the project. Please help out if you can.
📢 New
1️⃣ GRPC based Remote-Procedure-Calls
Please refer to the documentation for details of this feature.
2️⃣ Unit test Endpoints that use Resolve<T>() methods
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>();
}
}
3️⃣ Unit test Mapper & Validator classes that use Resolve<T>()
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.
4️⃣ Overloads for adding Claims, Roles & Permissions when creating JWT tokens
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));
});
🚀 Improvements
1️⃣ Alert which service was not registered when unit testing
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>());
});