CircleDI wired up with ASP.NET Core minimal API. The extra Blazor features are
- EndpointAttribute to register methods as minimal API endpoint.
This package includes all functionalities of CircleDI and including also the plain CircleDI package will cause errors.
- Add PackageReference to your .csproj file.
<ItemGroup>
<PackageReference Include="CircleDI.MinimalAPI" Version="{latest version}" PrivateAssets="all" />
</ItemGroup>
- Create a partial class with the ServiceProviderAttribute.
using CircleDIAttributes;
[ServiceProvider]
[ScopedProvider(ThreadSafe = false)]
public partial class MyMinimalAPIServiceProvider;
- Register to the built-in provider the ServiceProvider as Singleton and the ScopeProvider as Scoped.
builder.Services.AddSingleton<IMyMinimalAPIServiceProvider, MyMinimalAPIServiceProvider>();
builder.Services.AddScoped<IMyMinimalAPIServiceProvider.IScope, MyMinimalAPIServiceProvider.Scope>();
- Map all endpoints decorated with the EndpointAttribute.
using CircleDIAttributes;
...
app.MapCircleDIEndpoints();
- Create an endpoint handler by using the EndpointAttribute.
using CircleDIAttributes;
public static class EndpointCollection {
[Endpoint("/", Http.Get)]
public static string MyFirstEndpoint() {
return "Hello World!";
}
}
To inject a service to an endpoint from a ServiceProvider generated by CircleDI, you must explicitly use the [Dependency] attribute. This works only with endpoints mapped with the EndpointAttribute.
using CircleDIAttributes;
public sealed class MyService : IMyService;
public interface IMyService;
[ServiceProvider]
[Singleton<IMyService, MyService>]
public partial class MyMinimalAPIServiceProvider;
public static class EndpointCollection {
[Endpoint("/dependency", Http.Get)]
public static string EndpointWithDependency([Dependency] IMyService myService) {
return myService.ToString();
}
}
You can also define a constructor inside your ServiceProvider/ScopeProvider that takes parameter. In that case you register the provider with the method overload that takes the implementationFactory parameter.
using CircleDIAttributes;
public partial interface IMyMinimalAPIServiceProvider;
[ServiceProvider]
public sealed partial class MyMinimalAPIServiceProvider {
private readonly string _connectionString;
public MyMinimalAPIServiceProvider(string connectionString, IServiceProvider builtinProvider) {
_connectionString = connectionString;
InitServices(builtinProvider);
}
public sealed partial class Scope {
private readonly string _connectionStringScoped;
public Scope(string connectionStringScoped, [Dependency] IMyMinimalAPIServiceProvider serviceProvider, IServiceProvider builtinProvider) {
_connectionStringScoped = connectionStringScoped;
InitServices(serviceProvider, builtinProvider);
}
}
}
...
string connectionString = GetConnectionString();
string connectionStringScoped = GetConnectionStringScoped();
builder.Services.AddSingleton<IMyMinimalAPIServiceProvider>((IServiceProvider sp) => new MyMinimalAPIServiceProvider(connectionString, sp));
builder.Services.AddScoped<IMyMinimalAPIServiceProvider.IScope>((IServiceProvider sp) => sp.GetRequiredService<IMyMinimalAPIServiceProvider>().CreateScope(connectionStringScoped, sp));
The endpoint attribute has 3 parameters: pattern, httpMethod, RouteBuilder. The first two are required, the third one is optional.
pattern is the same parameter as in the normal app.Map() call and httpMethod maps to the equivalent app.Map() call. Following table shows some examples:
Normal Endpoint | CircleDI Endpoint |
---|---|
app.Map("/", ...); | [Endpoint("/", Http.Any)] |
app.MapGet("/books/{id}", ...); | [Endpoint("/books/{id}", Http.Get)] |
app.MapPost("/book", ...); | [Endpoint("/book", Http.Post)] |
app.MapDelete("/book", ...); | [Endpoint("/book", Http.Delete)] |
The third parameter is used to specify a method that is normally added behind the map call e.g. .ShortCircuit();, .AddEndpointFilter(...) or .WithName("...").WithOpenApi();
Following is the Weatherforecast example as CircleDI endpoint.
public static class WeatherforecastEndpoint {
public static void WeatherForecastRouteBuilder(RouteHandlerBuilder routeHandlerBuilder) {
routeHandlerBuilder.WithName("GetWeatherForecast").WithOpenApi();
}
[Endpoint("/weatherforecast", Http.Get, RouteBuilder = nameof(WeatherForecastRouteBuilder))]
public static WeatherForecast[] WeatherForecast() {
WeatherForecast[] forecast = Enumerable.Range(1, 5).Select(index =>
new WeatherForecast {
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = SummaryList[Random.Shared.Next(SummaryList.Length)]
})
.ToArray();
return forecast;
}
private static readonly string[] SummaryList = ["Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"];
}
The ServiceProviderAttribute has an additional property EndpointProvider. Per default this value is true, so every created ServiceProvider will be the provider used for resolving dependencies for [Endpoint]-methods. Since in most cases there is only one ServiceProvider, this works fine, but as soon as another ServiceProvider is defined, you get an error that only one EndpointProvider is allowed. By setting the EndpointProvider value of one ServiceProivder to false, that ServiceProvider becomes a normal provider and the other one is used for the [Endpoint]-methods.
[Endpoint]-methods also work without any EndpointProvider, as long there is no [Dependency]-parameter.
Same as ServiceProviderAttribute + following properties:
Name | Type | Description |
---|---|---|
EndpointProvider | bool | Indicates that this provider is taken for resolving [Dependency]-parameters in [Endpoint]-methods. Default is true. |
Adds a RouteEndpoint to the IEndpointRouteBuilder that matches HTTP requests for the specified pattern with the specified HTTP method.
The method must be static and non-generic. Dependencies must be explicitly marked with [Dependency].
Name | Type | Description |
---|---|---|
pattern | string | The pattern for the route or url. |
httpMethod | Http | The HTTP method for this endpoint. |
Name | Type | Description |
---|---|---|
RouteBuilder | string | The name of a method that takes RouteHandlerBuilder to configure the endpoint. The method must be in the same class. |
HTTP method of the endpoint.
Name | Description |
---|---|
Any | Matches any HTTP requests for the specified pattern. |
Get | Matches HTTP GET requests for the specified pattern. |
Post | Matches HTTP POST requests for the specified pattern. |
Put | Matches HTTP PUT requests for the specified pattern. |
Patch | Matches HTTP PATCH requests for the specified pattern. |
Delete | Matches HTTP DELETE requests for the specified pattern. |