/// <inheritdoc />
        public Task <byte[]> SerializeAsync(DistributedCacheTagHelperFormattingContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (context.Html == null)
            {
                throw new ArgumentNullException(nameof(context.Html));
            }

            var serialized = Encoding.UTF8.GetBytes(context.Html.ToString());

            return(Task.FromResult(serialized));
        }
        /// <inheritdoc />
        public Task<byte[]> SerializeAsync(DistributedCacheTagHelperFormattingContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (context.Html == null)
            {
                throw new ArgumentException(
                    Resources.FormatPropertyOfTypeCannotBeNull(
                        nameof(DistributedCacheTagHelperFormattingContext.Html),
                        typeof(DistributedCacheTagHelperFormattingContext).FullName));
            }

            var serialized = Encoding.UTF8.GetBytes(context.Html.ToString());
            return Task.FromResult(serialized);
        }
        /// <inheritdoc />
        public Task <byte[]> SerializeAsync(DistributedCacheTagHelperFormattingContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (context.Html == null)
            {
                throw new ArgumentException(
                          Resources.FormatPropertyOfTypeCannotBeNull(
                              nameof(DistributedCacheTagHelperFormattingContext.Html),
                              typeof(DistributedCacheTagHelperFormattingContext).FullName));
            }

            var serialized = Encoding.UTF8.GetBytes(context.Html.ToString());

            return(Task.FromResult(serialized));
        }
Пример #4
0
        /// <inheritdoc />
        public async Task <IHtmlContent> ProcessContentAsync(TagHelperOutput output, CacheTagKey key, DistributedCacheEntryOptions options)
        {
            IHtmlContent content = null;

            while (content == null)
            {
                // Is there any request already processing the value?
                if (!_workers.TryGetValue(key, out var result))
                {
                    // There is a small race condition here between TryGetValue and TryAdd that might cause the
                    // content to be computed more than once. We don't care about this race as the probability of
                    // happening is very small and the impact is not critical.
                    var tcs = new TaskCompletionSource <IHtmlContent>(creationOptions: TaskCreationOptions.RunContinuationsAsynchronously);

                    _workers.TryAdd(key, tcs.Task);

                    try
                    {
                        var serializedKey = Encoding.UTF8.GetBytes(key.GenerateKey());
                        var storageKey    = key.GenerateHashedKey();
                        var value         = await _storage.GetAsync(storageKey);

                        if (value == null)
                        {
                            // The value is not cached, we need to render the tag helper output
                            var processedContent = await output.GetChildContentAsync();

                            var stringBuilder = new StringBuilder();
                            using (var writer = new StringWriter(stringBuilder))
                            {
                                processedContent.WriteTo(writer, _htmlEncoder);
                            }

                            var formattingContext = new DistributedCacheTagHelperFormattingContext
                            {
                                Html = new HtmlString(stringBuilder.ToString())
                            };

                            // Then cache the result
                            value = await _formatter.SerializeAsync(formattingContext);

                            var encodeValue = Encode(value, serializedKey);

                            await _storage.SetAsync(storageKey, encodeValue, options);

                            content = formattingContext.Html;
                        }
                        else
                        {
                            // The value was found in the storage, decode and ensure
                            // there is no cache key hash collision
                            byte[] decodedValue = Decode(value, serializedKey);

                            try
                            {
                                if (decodedValue != null)
                                {
                                    content = await _formatter.DeserializeAsync(decodedValue);
                                }
                            }
                            catch (Exception e)
                            {
                                _logger.DistributedFormatterDeserializationException(storageKey, e);
                            }
                            finally
                            {
                                // If the deserialization fails the content is rendered
                                if (content == null)
                                {
                                    content = await output.GetChildContentAsync();
                                }
                            }
                        }
                    }
                    catch
                    {
                        content = null;
                        throw;
                    }
                    finally
                    {
                        // Remove the worker task before setting the result.
                        // If the result is null, other threads would potentially
                        // acquire it otherwise.
                        _workers.TryRemove(key, out result);

                        // Notify all other awaiters to render the content
                        tcs.TrySetResult(content);
                    }
                }
                else
                {
                    content = await result;
                }
            }

            return(content);
        }
Пример #5
0
        /// <inheritdoc />
        public async Task <IHtmlContent> ProcessContentAsync(TagHelperOutput output, string key, DistributedCacheEntryOptions options)
        {
            IHtmlContent content = null;

            while (content == null)
            {
                Task <IHtmlContent> result = null;

                // Is there any request already processing the value?
                if (!_workers.TryGetValue(key, out result))
                {
                    var tcs = new TaskCompletionSource <IHtmlContent>();

                    _workers.TryAdd(key, tcs.Task);

                    try
                    {
                        var value = await _storage.GetAsync(key);

                        if (value == null)
                        {
                            var processedContent = await output.GetChildContentAsync();

                            var stringBuilder = new StringBuilder();
                            using (var writer = new StringWriter(stringBuilder))
                            {
                                processedContent.WriteTo(writer, _htmlEncoder);
                            }

                            var formattingContext = new DistributedCacheTagHelperFormattingContext
                            {
                                Html = new HtmlString(stringBuilder.ToString())
                            };

                            value = await _formatter.SerializeAsync(formattingContext);

                            await _storage.SetAsync(key, value, options);

                            content = formattingContext.Html;
                        }
                        else
                        {
                            content = await _formatter.DeserializeAsync(value);

                            // If the deserialization fails, it can return null, for instance when the
                            // value is not in the expected format.
                            if (content == null)
                            {
                                content = await output.GetChildContentAsync();
                            }
                        }

                        tcs.TrySetResult(content);
                    }
                    catch
                    {
                        tcs.TrySetResult(null);
                        throw;
                    }
                    finally
                    {
                        // Remove the worker task from the in-memory cache
                        Task <IHtmlContent> worker;
                        _workers.TryRemove(key, out worker);
                    }
                }
                else
                {
                    content = await result;
                }
            }

            return(content);
        }
Пример #6
0
        public async Task Deserialize_DoesntAlterValue_WhenSerialized()
        {
            // Arrange
            var content = "<b>some content</b>";
            var formatter = GetFormatter();
            var context = new DistributedCacheTagHelperFormattingContext
            {
                Html = new HtmlString(content)
            };
            var serialized = await formatter.SerializeAsync(context);

            // Act
            var deserialized = await formatter.DeserializeAsync(serialized);

            // Assert
            Assert.Equal(deserialized.ToString(), content);
        }