You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/README.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -43,13 +43,13 @@ MVC Action results support allows composition handlers to set custom response re
43
43
44
44
### Serialization
45
45
46
-
By default, ServiceComposer serializes responses using the Newtonsoft JSON serializer. The built-in serialization support can be configured to serialize responses using a camel case or pascal case approach on a per-request basis by adding to the request an `Accept-Casing` custom HTTP header. For more information, refer to the [response serialization casing](response-serialization-casing.md) section. Or it's possible to take full control over the [response serialization settings on a case-by-case](custom-json-response-serialization-settings.md) by supplying at configuration time a customization function.
46
+
By default, ServiceComposer serializes responses using `System.Text.Json`. The built-in serialization support can be configured to serialize responses using a camel case or pascal case approach on a per-request basis by adding to the request an `Accept-Casing` custom HTTP header. For more information, refer to the [response serialization casing](response-serialization-casing.md) section. Or it's possible to take full control over the [response serialization settings on a case-by-case](custom-json-response-serialization-settings.md) by supplying at configuration time a customization function.
47
47
48
48
Starting with version 1.9.0, regular MVC Output Formatters can be used to serialize the response model and honor the `Accept` HTTP header set by clients. When using output formatters, the serialization casing is controlled by the formatter configuration and not by ServiceComposer. For more information on using output formatters refers to the [output formatters serialization section](output-formatters-serialization.md).
49
49
50
50
### Authentication and Authorization
51
51
52
-
By leveraging ASP.NET Core 3.x Endpoints, ServiceComposer automatically supports authentication and authorization metadata attributes to express authentication and authorization requirements for routes. For more information, refer to the [Authentication and Authorization](authentication-authorization.md) section.
52
+
By leveraging ASP.NET Core Endpoints, ServiceComposer automatically supports authentication and authorization metadata attributes to express authentication and authorization requirements for routes. For more information, refer to the [Authentication and Authorization](authentication-authorization.md) section.
Copy file name to clipboardExpand all lines: docs/authentication-authorization.md
+56-1Lines changed: 56 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,6 @@
1
1
# Authentication and Authorization
2
2
3
-
By virtue of leveraging ASP.NET Core 3.x Endpoints ServiceComposer automatically supports authentication and authorization metadata attributes to express authentication and authorization requirements on routes. For example, it's possible to use the `Authorize` attribute to specify that a handler requires authorization. The authorization process is the regular ASP.NET Core 3.x process and no special configuration is needed to plugin ServiceComposer:
3
+
By virtue of leveraging ASP.NET Core Endpoints, ServiceComposer automatically supports authentication and authorization metadata attributes to express authentication and authorization requirements on routes. For example, it's possible to use the `Authorize` attribute to specify that a handler requires authorization. The authorization process is the regular ASP.NET Core process and no special configuration is needed to plug in ServiceComposer:
@@ -17,3 +17,58 @@ public class SampleHandlerWithAuthorization : ICompositionRequestsHandler
17
17
```
18
18
<sup><ahref='/src/Snippets/SampleHandler/SampleHandler.cs#L10-L20'title='Snippet source file'>snippet source</a> | <ahref='#snippet-sample-handler-with-authorization'title='Start of snippet'>anchor</a></sup>
19
19
<!-- endSnippet -->
20
+
21
+
## How it works
22
+
23
+
ServiceComposer registers composition endpoints using ASP.NET Core's endpoint routing system. Any endpoint metadata attributes — `[Authorize]`, `[AllowAnonymous]`, `[RequireAuthorization]`, custom policy attributes — are collected from all handlers registered for a route and merged onto the composed endpoint.
24
+
25
+
This means authorization is evaluated **before** composition handlers execute, as part of the standard ASP.NET Core middleware pipeline. If the request is not authorized, it is rejected and no composition handlers run.
26
+
27
+
## Multiple handlers with different authorization requirements
28
+
29
+
When multiple handlers are registered for the same route, their authorization metadata is merged. If any handler declares `[Authorize]`, the route requires authorization. The most restrictive combination applies.
30
+
31
+
For example, if one handler requires an authenticated user and another requires a specific policy, both requirements are enforced:
<sup><ahref='/src/Snippets/Authentication/AuthenticationSnippets.cs#L11-L25'title='Snippet source file'>snippet source</a> | <ahref='#snippet-multiple-handlers-different-auth-requirements'title='Start of snippet'>anchor</a></sup>
51
+
<!-- endSnippet -->
52
+
53
+
Both `[Authorize]` and `[Authorize(Policy = "WarehouseStaff")]` are collected and applied to the route, so callers must satisfy both requirements.
54
+
55
+
## Setup
56
+
57
+
No special configuration is required beyond the standard ASP.NET Core authentication/authorization setup. Add authentication and authorization middleware before `app.MapCompositionHandlers()`:
58
+
59
+
<!-- snippet: auth-middleware-setup -->
60
+
<aid='snippet-auth-middleware-setup'></a>
61
+
```cs
62
+
varbuilder=WebApplication.CreateBuilder();
63
+
builder.Services.AddViewModelComposition();
64
+
builder.Services.AddAuthentication(); // configure your scheme here
65
+
builder.Services.AddAuthorization();
66
+
67
+
varapp=builder.Build();
68
+
app.UseAuthentication();
69
+
app.UseAuthorization();
70
+
app.MapCompositionHandlers();
71
+
app.Run();
72
+
```
73
+
<sup><ahref='/src/Snippets/Authentication/AuthenticationSnippets.cs#L31-L42'title='Snippet source file'>snippet source</a> | <ahref='#snippet-auth-middleware-setup'title='Start of snippet'>anchor</a></sup>
Copy file name to clipboardExpand all lines: docs/composition-filters.md
+21-3Lines changed: 21 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -10,7 +10,7 @@ Composition requests filter can be defined as attributes or as classes.
10
10
11
11
### Defining composition requests filters as attributes
12
12
13
-
Create an attribute that inherites from `CompositionRequestFilterAttribute` like in the following snippet:
13
+
Create an attribute that inherits from `CompositionRequestFilterAttribute` like in the following snippet:
14
14
15
15
<!-- snippet: composition-filter-attribute -->
16
16
<aid='snippet-composition-filter-attribute'></a>
@@ -49,7 +49,7 @@ public class SampleHandler : ICompositionRequestsHandler
49
49
50
50
### Defining composition requests filters as classes
51
51
52
-
Create a class te implements the `ICompositionRequestFilter<T>` interface, where the generic `T` parameter is the composition handler type to intercept:
52
+
Create a class that implements the `ICompositionRequestFilter<T>` interface, where the generic `T` parameter is the composition handler type to intercept:
53
53
54
54
<!-- snippet: composition-filter-class -->
55
55
<aid='snippet-composition-filter-class'></a>
@@ -68,4 +68,22 @@ public class SampleCompositionFilter : ICompositionRequestFilter<SampleHandler>
68
68
The above snippet defines a filter intercepting requests to the `SampleHandler` composition handler.
69
69
70
70
> [!NOTE]
71
-
> Filters defined as classes implementing the `ICompositionRequestFilter<T>` interface will be automatically registered in DI as transiten, and can use DI to resolve dependencies.
71
+
> Filters defined as classes implementing the `ICompositionRequestFilter<T>` interface will be automatically registered in DI as transient, and can use DI to resolve dependencies.
72
+
73
+
## When to use composition filters vs endpoint filters
74
+
75
+
ServiceComposer provides two filter extension points. Choosing the right one depends on the scope of interception needed.
- The logic applies to the entire composed request regardless of which handlers are involved (e.g. request logging, timing, global validation).
80
+
- You want to short-circuit the whole composition before any handler runs.
81
+
- The logic is independent of specific handler types.
82
+
83
+
**Use composition filters when:**
84
+
85
+
- The logic is specific to one particular composition handler type.
86
+
- Different handlers on the same route need different pre/post processing (e.g. handler-specific authorization checks, handler-specific input validation).
87
+
- You want to use the attribute form (`[SampleCompositionFilter]`) to keep the filter declaration co-located with the handler method.
88
+
89
+
In short: endpoint filters are coarse-grained (the whole endpoint), composition filters are fine-grained (a specific handler).
<sup><ahref='/src/Snippets/CompositionOverController.cs#L10-L15'title='Snippet source file'>snippet source</a> | <ahref='#snippet-enable-composition-over-controllers'title='Start of snippet'>anchor</a></sup>
13
+
<sup><ahref='/src/Snippets/CompositionOverController.cs#L12-L17'title='Snippet source file'>snippet source</a> | <ahref='#snippet-enable-composition-over-controllers'title='Start of snippet'>anchor</a></sup>
14
14
<!-- endSnippet -->
15
15
16
16
Once composition over controllers is enabled, ServiceComposer will inject a MVC filter to intercept all controllers invocations. If a route matches a regular controller and a set of composition handlers ServiceComposer will invoke the matching handlers after the controller and before the view is rendered.
Copy file name to clipboardExpand all lines: docs/custom-http-status-codes.md
+35-4Lines changed: 35 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,6 @@
1
-
# Custom HTTP status codes in ASP.NET Core 3.x
1
+
# Custom HTTP status codes
2
2
3
-
The response status code can be set in requests handlers and it'll be honored by the composition pipeline. To set a custom response status code the following snippet can be used:
3
+
The response status code can be set in composition handlers and it will be honored by the composition pipeline. To set a custom response status code the following snippet can be used:
@@ -20,5 +20,36 @@ public class SampleHandlerWithCustomStatusCode : ICompositionRequestsHandler
20
20
<sup><ahref='/src/Snippets/SampleHandler/SampleHandler.cs#L22-L34'title='Snippet source file'>snippet source</a> | <ahref='#snippet-sample-handler-with-custom-status-code'title='Start of snippet'>anchor</a></sup>
21
21
<!-- endSnippet -->
22
22
23
-
> [!NOTE]
24
-
> Requests handlers are executed in parallel in a non-deterministic way, setting the response code in more than one handler can have unpredictable effects.
23
+
> [!WARNING]
24
+
> Composition handlers execute in parallel in a non-deterministic order. If more than one handler sets the response status code, the final code written to the response is unpredictable. Only one handler in a composition group should set the status code.
25
+
26
+
## Recommended approach: use action results instead
27
+
28
+
For error scenarios (validation failures, not found, forbidden), prefer using [MVC Action results](action-results.md) via `request.SetActionResult(result)`. Action results are designed for exactly this case — ServiceComposer guarantees only the first handler to call `SetActionResult` takes effect, making the behavior deterministic:
<sup><ahref='/src/Snippets/SampleHandler/SetActionResultHandler.cs#L8-L27'title='Snippet source file'>snippet source</a> | <ahref='#snippet-set-action-result-preferred'title='Start of snippet'>anchor</a></sup>
53
+
<!-- endSnippet -->
54
+
55
+
Setting a status code directly on `HttpContext.Response` is appropriate only when a handler is the sole authority on the response code for its route, or when using a non-MVC endpoint where action results are not available.
0 commit comments