Table of Contents

Turning exceptions into status codes

Register the handler once, rather than catching exceptions in every endpoint:

builder.Services.AddResourcefullExceptionHandler();

app.UseExceptionHandler();
Exception Status
ResourceConflictException 409 Conflict
ResourceUploadOffsetException 4.0, for an append to an upload session that doesn't start where its content ends 409 Conflict
ResourceRetainedException 4.0, for a delete of a version that's retained or under a legal hold 409 Conflict
ResourceUploadInterruptedException 4.0, for an upload whose version was deleted before it completed, as by a container delete at the same time 409 Conflict
ResourceUploadLimitException 4.0, for an append past what an upload session can hold with its provider, or an upload larger than its provider can store in one object 413 Content Too Large
ResourceContainerNotFoundException 404 Not Found
ResourceContentLengthMismatchException 400 Bad Request
ResourceNameException, for a name that breaks the name rules 400 Bad Request
ResourcePreconditionFailedException 412 Precondition Failed
ResourceRangeNotSatisfiableException 4.0, for a download range that starts past the end 416 Range Not Satisfiable, with Content-Range: bytes */ and the content's length
ResourceContentRefusedException 4.0, for an upload your upload inspector refused 422 Unprocessable Content
ResourcePolicyViolationException 4.0, for a write that breaks its container's policy 413 Content Too Large for the size limits, 409 Conflict for MaxResourceCount, 403 Forbidden for ReadOnly, 415 Unsupported Media Type for AllowedContentTypes

The responses are problem details whose title is the exception's message. Resourcefull's messages name the resource or container involved, and sometimes the argument or option, but nothing about your infrastructure, so they're safe to return. A refused upload's message ends with the reason your upload inspector gave, so keep that reason fit for the uploader to see. Other exceptions, such as a SqlException, are left to the default handler, which returns 500 without details in production. ASP.NET Core removes ETag from responses its exception handling writes, so a 412 from the handler doesn't carry the current version's ETag; the 412 that UploadFromRequestAsync returns does.