FastEndpoints Versions Save

A light-weight REST API development framework for ASP.NET 6 and newer.

v5.18

7 months ago

✨ 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:

image

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

8 months ago

✨ 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

8 months ago

✨ 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

8 months ago

✨ 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

9 months ago

✨ 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 static EmptyObject instance.
Event Queues internal optimizations
  • Use SemaphoreSlims instead of Task.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

10 months ago

⭐ 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

10 months ago

⭐ 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

11 months ago

⭐ 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>());
});

v5.11.0

11 months ago

⭐ Looking For Sponsors

FastEndpoints needs sponsorship to sustain the project. Please help out if you can.


📢 New

  • ability to call 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.
  • support for property injection with unit testing using Factory.Create() method #448
  • extension method httpContext.AddTestServices(...) for cleaner test services registration with Factory.Create() method #448

🚀 Improvements

  • prevent UseFastEndpoints() call overwriting the DI registered JsonOptions #info
  • ability to optionally specify a status code when using the Throw*(404) endpoint error short-circuit methods #450

🪲 Fixes

  • swagger schema properties marked as required by a validator were not removed from the schema in some cases #info

v5.10

1 year ago

EXPERIMENTAL

  • support for Asp.Versioning.Http package via FastEndpoints.AspVersioning #info

IMPROVEMENTS

  • trim down AddSwaggerDoc() calls with SwaggerDocument(Action<DocumentOptions>). see deprecations below & example.
  • improve IFormFile support in OAS2 #info
  • nswag operation processor internal optimizations

DEPRECATIONS

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 property
  • FastEndpoints.Swagger.Extensions.TagDescriptions() in favor of DocumentOptions.TagDescriptions property
  • FastEndpoints.Swagger.Extensions.EnableFastEndpoints() in favor of EnableFastEndpoints(Action<DocumentOptions>)