Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ServiceComposer/ServiceComposer.AspNetCore/llms.txt

Use this file to discover all available pages before exploring further.

Composition handlers occasionally need to short-circuit a request and return an error response — for example, when an identifier fails validation or a resource is not found. Throwing an exception works, but it bypasses your API’s normal error-shape contract. ServiceComposer provides SetActionResult, an HttpRequest extension method that lets any handler set a first-class ASP.NET Core ActionResult instead, and ICompositionErrorsHandler for catching unhandled exceptions that escape the composition pipeline entirely.

When to use action results

Validation errors

Return BadRequestObjectResult with ValidationProblemDetails when an incoming value does not meet the required format or business rules.

Not found / forbidden

Return NotFoundResult or ForbidResult without throwing — avoids polluting logs with expected error conditions.

Deterministic behaviour

ServiceComposer guarantees only the first call to SetActionResult takes effect. All subsequent calls from other handlers are silently ignored, making the outcome predictable even when handlers run in parallel.

Structured problem details

Use ProblemDetails or ValidationProblemDetails to emit RFC 7807-compliant responses that clients can reliably parse.

Setting an action result

Call request.SetActionResult(result) inside any ICompositionRequestsHandler implementation. The method is an extension on HttpRequest, so no extra service injection is required.
public class UseSetActionResultHandler : ICompositionRequestsHandler
{
    [HttpGet("/product/{id}")]
    public Task Handle(HttpRequest request)
    {
        var id = request.RouteValues["id"];

        //validate the id format

        var problems = new ValidationProblemDetails(new Dictionary<string, string[]>()
        {
            { "Id", new []{ "The supplied id does not respect the identifier format." } }
        });
        var result = new BadRequestObjectResult(problems);

        request.SetActionResult(result);

        return Task.CompletedTask;
    }
}
ServiceComposer supports only one action result per request. If two or more composition handlers call SetActionResult, only the first call succeeds. All subsequent calls are silently discarded.

Required configuration

Action results depend on MVC output formatters. Enable them in AddViewModelComposition:
builder.Services.AddViewModelComposition(options =>
{
    options.ResponseSerialization.UseOutputFormatters = true;
});
You must also register MVC services — any of the following works:
  • builder.Services.AddControllers()
  • builder.Services.AddControllersAndViews()
  • builder.Services.AddMvc()
  • builder.Services.AddRazorPages()

Custom HTTP status codes

For cases where a full ActionResult is unnecessary — or when a handler is the sole authority on the response code for its route — you can set the status code directly on HttpContext.Response:
public class SampleHandlerWithCustomStatusCode : ICompositionRequestsHandler
{
    [HttpGet("/sample/{id}")]
    public Task Handle(HttpRequest request)
    {
        var response = request.HttpContext.Response;
        response.StatusCode = (int)HttpStatusCode.Forbidden;

        return Task.CompletedTask;
    }
}
Composition handlers execute in parallel in non-deterministic order. If more than one handler sets Response.StatusCode, the final value written to the response is unpredictable. Prefer SetActionResult for error scenarios — its first-writer-wins guarantee makes behaviour deterministic.

Prefer SetActionResult for error scenarios

The recommended pattern is to use SetActionResult rather than writing to Response.StatusCode directly:
public class SampleHandler : ICompositionRequestsHandler
{
    [HttpGet("/sample/{id}")]
    public Task Handle(HttpRequest request)
    {
        if (!IsValid(request))
        {
            request.SetActionResult(new BadRequestResult());
            return Task.CompletedTask;
        }

        var vm = request.GetComposedResponseModel();
        vm.Data = "...";
        return Task.CompletedTask;
    }

    bool IsValid(HttpRequest request) => request.RouteValues["id"] != null;
}
Setting Response.StatusCode directly is appropriate only when you are in a non-MVC endpoint context where action results are unavailable, or when only one handler will ever touch the status code for that route.

Handling composition exceptions with ICompositionErrorsHandler

ICompositionErrorsHandler is a composition hook that fires when an unhandled exception escapes from any handler during the composition pipeline. Implement it to log the error, set a fallback action result, or perform cleanup:
public interface ICompositionErrorsHandler
{
    Task OnRequestError(HttpRequest request, Exception ex);
}
ServiceComposer discovers ICompositionErrorsHandler by inspecting the composition handlers already registered for the matched endpoint. A class participates in error handling only if it is also registered as a composition component — for example, by implementing ICompositionRequestsHandler alongside ICompositionErrorsHandler:
public class SampleHandlerWithErrorHandling : ICompositionRequestsHandler, ICompositionErrorsHandler
{
    [HttpGet("/sample/{id}")]
    public Task Handle(HttpRequest request)
    {
        // normal composition logic
        return Task.CompletedTask;
    }

    public Task OnRequestError(HttpRequest request, Exception ex)
    {
        request.SetActionResult(new ObjectResult(new ProblemDetails
        {
            Status = StatusCodes.Status500InternalServerError,
            Title = "An unexpected error occurred.",
            Detail = ex.Message
        })
        {
            StatusCode = StatusCodes.Status500InternalServerError
        });

        return Task.CompletedTask;
    }
}
Because the class already implements ICompositionRequestsHandler, the assembly scanner picks it up automatically — no additional DI registration is needed.
OnRequestError is called inside the composition pipeline’s exception handler, which re-throws the exception after invoking all error handlers. Action results set inside OnRequestError are written to the response before the exception propagates, so they will be honoured by the MVC output formatter pipeline.
ICompositionErrorsHandler is your safety net for unexpected failures. For expected error conditions such as validation failures or missing resources, use SetActionResult directly inside the handler where the condition is detected.

Build docs developers (and LLMs) love