DocumentClientException.Error.Code可取哪些值?如何处理DocumentClient异常?
Great question! Properly handling exceptions from the old DocumentClient API (used for Azure Cosmos DB's DocumentDB compatibility mode) is crucial for building reliable data access layers—especially when dealing with optimistic concurrency and common edge cases like throttling or resource conflicts. Let’s break this down step by step.
Common Values for DocumentClientException.Error.Code
The Code property maps to specific Cosmos DB service errors, each tied to a standard HTTP status code. Here are the most frequently encountered codes you’ll want to handle:
PreconditionFailed: This is the key code for optimistic concurrency failures. Triggered when theAccessCondition(e.g.,IfMatchwith an ETag) doesn’t match the current state of the document. Corresponding HTTP status code: 412.NotFound: Thrown when the target resource (document, collection, database) doesn’t exist. HTTP 404.Conflict: Occurs when a unique constraint is violated (e.g., inserting a document with a duplicate unique key). HTTP 409.RequestRateTooLarge: The classic throttling error—you’ve exceeded your container’s RU (Request Unit) limit. HTTP 429.BadRequest: Invalid request format (e.g., malformed JSON, missing required fields). HTTP 400.Unauthorized: Authentication failure (wrong account key, expired token). HTTP 401.Forbidden: The authenticated identity doesn’t have permission to perform the operation. HTTP 403.InternalServerError: Rare service-side error. HTTP 500.ServiceUnavailable: Temporary service outage or maintenance. HTTP 503.
Exception Handling Implementation Details
Using C#’s exception filtering (the when clause) is absolutely the cleanest way to target specific DocumentClientException cases—no messy conditional checks inside the catch block. Here’s how to put this into practice:
Example 1: Optimistic Concurrency Handling
This is exactly the scenario you mentioned with AccessCondition:
try { // Build the URI for the document we want to update var documentUri = UriFactory.CreateDocumentUri("MyDatabase", "MyCollection", "Document123"); // Assume we fetched the existing document's ETag earlier var updatedDocument = new MyBusinessDocument { Id = "Document123", Title = "Updated Document Title", ETag = existingDocumentETag // ETag from the original fetch }; // Attempt to update with optimistic concurrency check await _documentClient.ReplaceDocumentAsync( documentUri, updatedDocument, new RequestOptions { AccessCondition = new AccessCondition { Condition = existingDocumentETag, Type = AccessConditionType.IfMatch } }); } catch (DocumentClientException ex) when (ex.Error.Code == "PreconditionFailed") { // Handle concurrency conflict: refresh the document, merge changes, and retry (or notify the user) Console.WriteLine("Oops! Someone else updated this document before you. Please refresh and try again."); // Optional: Implement retry logic here with fresh document data }
Example 2: Handling Throttling (RequestRateTooLarge)
Throttling is a common scenario in Cosmos DB, and you’ll want to implement retry logic here (usually with exponential backoff):
catch (DocumentClientException ex) when (ex.Error.Code == "RequestRateTooLarge") { // Use the RetryAfter value provided by Cosmos DB to know how long to wait var delay = ex.RetryAfter ?? TimeSpan.FromSeconds(1); await Task.Delay(delay); // Re-execute the failed operation (wrap this in a retry loop for multiple attempts) await RetryDocumentUpdateOperation(); }
Key Best Practices
- Combine Code and StatusCode: For clarity, you can also check the
StatusCodeproperty alongsideCode, e.g.,when (ex.StatusCode == HttpStatusCode.PreconditionFailed). Both work, so pick whichever feels more readable to you. - Retry Strategically: Only retry for transient errors like
RequestRateTooLargeandServiceUnavailable. Errors likeNotFoundorBadRequestare usually permanent and don’t benefit from retries. - Avoid Generic Catches: Never catch
Exceptiondirectly unless you have to—always target specific exceptions likeDocumentClientExceptionto avoid swallowing unexpected errors.
内容的提问来源于stack exchange,提问作者Imre Pühvel

