/// <summary> /// Returns the item uniquely identified by <paramref name="id"/> from storage. /// The class will remember its values, so we know how to deal with a later call to <see cref="SaveAsync(TId,TModel,System.Threading.CancellationToken)"/>. /// </summary> /// <returns>The found item or null.</returns> public async Task <TModel> ReadAsync(TId id, CancellationToken cancellationToken = default) { var item = await _readService.ReadAsync(id, cancellationToken); if (item == null) { return(null); } AddOrUpdateWithCopy(id, item, true); return(item); }
/// <summary> /// Read and cache the item, but only if we have an aggressive caching strategy. /// </summary> /// <param name="id">The id of the item.</param> /// <param name="service">A service to use for reading the item.</param> /// <param name="token">Propagates notification that operations should be canceled</param> protected async Task CacheMaybeSetAsync(TId id, IRead <TModel, TId> service, CancellationToken token = default(CancellationToken)) { async Task <bool> IsAlreadyCachedAndGetIsOkToUpdate() { return(Options.DoGetToUpdate && await CacheItemExistsAsync(id, token)); } var getAndSave = Options.SaveAll || await IsAlreadyCachedAndGetIsOkToUpdate(); if (!getAndSave) { return; } var item = await service.ReadAsync(id, token); await CacheSetByIdAsync(id, item, token); }
/// <summary> /// If <paramref name="item"/> implements <see cref="IOptimisticConcurrencyControlByETag"/> /// then the old value is read using <paramref name="service"/> and the values are verified to be equal. /// The Etag of the item is then set to a new value. /// </summary> /// <param name="id"></param> /// <param name="item"></param> /// <param name="service"></param> /// <param name="token">Propagates notification that operations should be canceled</param> /// <returns></returns> protected virtual async Task <TModel> MaybeVerifyEtagForUpdateAsync(TId id, TModel item, IRead <TModel, TId> service, CancellationToken token = default(CancellationToken)) { var oldItem = await service.ReadAsync(id, token); if (!(item is IOptimisticConcurrencyControlByETag etaggable)) { return(oldItem); } if (Equals(oldItem, default(TModel))) { return(oldItem); } var oldEtag = (oldItem as IOptimisticConcurrencyControlByETag)?.Etag; if (oldEtag?.ToLowerInvariant() != etaggable.Etag?.ToLowerInvariant()) { throw new FulcrumConflictException($"The updated item ({item}) had an old ETag value."); } return(oldItem); }