internal async Task ValidateOperationAsync(
            ItemBatchOperation operation,
            ItemRequestOptions itemRequestOptions = null,
            CancellationToken cancellationToken   = default(CancellationToken))
        {
            if (itemRequestOptions != null)
            {
                if (itemRequestOptions.BaseConsistencyLevel.HasValue ||
                    itemRequestOptions.PreTriggers != null ||
                    itemRequestOptions.PostTriggers != null ||
                    itemRequestOptions.SessionToken != null)
                {
                    throw new InvalidOperationException(ClientResources.UnsupportedBatchRequestOptions);
                }

                Debug.Assert(BatchAsyncContainerExecutor.ValidateOperationEPK(operation, itemRequestOptions));
            }

            await operation.MaterializeResourceAsync(this.cosmosClientContext.CosmosSerializer, cancellationToken);

            int itemByteSize = operation.GetApproximateSerializedLength();

            if (itemByteSize > this.maxServerRequestBodyLength)
            {
                throw new ArgumentException(RMResources.RequestTooLarge);
            }
        }
        public virtual bool TryAdd(ItemBatchOperation operation)
        {
            if (this.dispatched)
            {
                DefaultTrace.TraceCritical($"Add operation attempted on dispatched batch.");
                return(false);
            }

            if (operation == null)
            {
                throw new ArgumentNullException(nameof(operation));
            }

            if (operation.Context == null)
            {
                throw new ArgumentNullException(nameof(operation.Context));
            }

            if (operation.Context.IsClientEncrypted && !this.isClientEncrypted)
            {
                this.isClientEncrypted          = true;
                this.intendedCollectionRidValue = operation.Context.IntendedCollectionRidValue;
            }

            if (this.batchOperations.Count == this.maxBatchOperationCount)
            {
                DefaultTrace.TraceInformation($"Batch is full - Max operation count {this.maxBatchOperationCount} reached.");
                return(false);
            }

            int itemByteSize = operation.GetApproximateSerializedLength();

            if (this.batchOperations.Count > 0 && itemByteSize + this.currentSize > this.maxBatchByteSize)
            {
                DefaultTrace.TraceInformation($"Batch is full - Max byte size {this.maxBatchByteSize} reached.");
                return(false);
            }

            this.currentSize += itemByteSize;

            // Operation index is in the scope of the current batch
            operation.OperationIndex         = this.batchOperations.Count;
            operation.Context.CurrentBatcher = this;
            this.batchOperations.Add(operation);
            return(true);
        }