/// <summary> /// Lazily convert the reliable state enumerable into a queryable <see cref="Entity{TKey, TValue}"/> enumerable. /// /// </summary> /// <param name="source">Reliable state enumerable.</param> /// <param name="partitionId">Partition id.</param> /// <param name="cancellationToken">Cancellation token.</param> /// <returns>The</returns> private static IAsyncEnumerable <Entity <TKey, TValue> > AsEntity <TKey, TValue>(this IAsyncEnumerable <KeyValuePair <TKey, TValue> > source, Guid partitionId, CancellationToken cancellationToken) { return(source.SelectAsync(kvp => new Entity <TKey, TValue> { PartitionId = partitionId, Key = kvp.Key, Value = kvp.Value, // TODO: only set the ETag if the query selects this object. Etag = CRC64.ToCRC64(JsonConvert.SerializeObject(kvp.Value)).ToString(), })); }
private static async Task <HttpStatusCode> ExecuteUpdateAsync(ITransaction tx, IReliableState dictionary, EntityOperation <JToken, JToken> operation) { // Get type information. Type keyType = dictionary.GetKeyType(); Type valueType = dictionary.GetValueType(); var key = operation.Key.ToObject(keyType); var value = operation.Value.ToObject(valueType); Type dictionaryType = typeof(IReliableDictionary <,>).MakeGenericType(keyType, valueType); // Read the existing value. MethodInfo tryGetMethod = dictionaryType.GetMethod("TryGetValueAsync", new[] { typeof(ITransaction), keyType, typeof(LockMode) }); var tryGetTask = (Task)tryGetMethod.Invoke(dictionary, new[] { tx, key, LockMode.Update }); await tryGetTask.ConfigureAwait(false); var tryGetResult = tryGetTask.GetPropertyValue <object>("Result"); // Only update the value if it exists. if (!tryGetResult.GetPropertyValue <bool>("HasValue")) { throw new QueryException(HttpStatusCode.NotFound, "Key not found."); } // Validate the ETag. var currentValue = tryGetResult.GetPropertyValue <object>("Value"); var currentEtag = CRC64.ToCRC64(JsonConvert.SerializeObject(currentValue)).ToString(); if (currentEtag != operation.Etag) { throw new QueryException(HttpStatusCode.PreconditionFailed, "The value has changed on the server."); } // Update in reliable dictionary. MethodInfo setMethod = dictionaryType.GetMethod("SetAsync", new[] { typeof(ITransaction), keyType, valueType }); await((Task)setMethod.Invoke(dictionary, new[] { tx, key, value })).ConfigureAwait(false); return(HttpStatusCode.OK); }