Dispose CancellationTokenSource created in CacheTagHelper (#6293)

Fixes #5649
This commit is contained in:
Sébastien Ros 2017-07-03 23:59:48 +02:00 committed by Pranav K
parent ca751c5297
commit 13e76c24d3
3 changed files with 66 additions and 13 deletions

View File

@ -93,7 +93,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
try try
{ {
// The entry is set instead of assigning a value to the // The entry is set instead of assigning a value to the
// task so that the expiration options are are not impacted // task so that the expiration options are not impacted
// by the time it took to compute it. // by the time it took to compute it.
using (var entry = MemoryCache.CreateEntry(cacheKey)) using (var entry = MemoryCache.CreateEntry(cacheKey))
@ -108,18 +108,24 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
content = await result; content = await result;
} }
tcs.SetResult(content);
} }
catch catch
{ {
// Remove the worker task from the cache in case it can't complete. // Remove the worker task from the cache in case it can't complete.
tokenSource.Cancel(); tokenSource.Cancel();
// If an exception occurs, ensure the other awaiters
// render the output by themselves.
tcs.SetResult(null);
throw; throw;
} }
finally finally
{ {
// If an exception occurs, ensure the other awaiters // The tokenSource needs to be disposed as the MemoryCache
// render the output by themselves. // will register a callback on the Token.
tcs.SetResult(null); tokenSource.Dispose();
} }
} }
else else
@ -238,4 +244,4 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
} }
} }
} }
} }

View File

@ -105,4 +105,4 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
} }
} }
} }

View File

@ -648,7 +648,6 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
Assert.Equal(2, calls); Assert.Equal(2, calls);
} }
[Fact] [Fact]
public async Task ProcessAsync_ExceptionInProcessing_DoNotThrowInSubsequentRequests() public async Task ProcessAsync_ExceptionInProcessing_DoNotThrowInSubsequentRequests()
@ -743,15 +742,63 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
Assert.Equal(childContent, tagHelperOutput4.Content.GetContent()); Assert.Equal(childContent, tagHelperOutput4.Content.GetContent());
} }
[Fact]
public async Task ProcessAsync_WorksForNestedCacheTagHelpers()
{
// Arrange
var expected = "Hello world";
var cache = new MemoryCache(new MemoryCacheOptions());
var encoder = new HtmlTestEncoder();
var cacheTagHelper1 = new CacheTagHelper(cache, encoder)
{
ViewContext = GetViewContext(),
Enabled = true
};
var cacheTagHelper2 = new CacheTagHelper(cache, encoder)
{
ViewContext = GetViewContext(),
Enabled = true
};
var tagHelperOutput2 = new TagHelperOutput(
"cache",
new TagHelperAttributeList(),
getChildContentAsync: (useCachedResult, _) =>
{
var content = new DefaultTagHelperContent();
content.SetContent(expected);
return Task.FromResult<TagHelperContent>(content);
});
var tagHelperOutput1 = new TagHelperOutput(
"cache",
new TagHelperAttributeList(),
getChildContentAsync: async (useCachedResult, _) =>
{
var context = GetTagHelperContext("test2");
var output = tagHelperOutput2;
await cacheTagHelper2.ProcessAsync(context, output);
return await output.GetChildContentAsync();
});
// Act
await cacheTagHelper1.ProcessAsync(GetTagHelperContext(), tagHelperOutput1);
// Assert
Assert.Equal(encoder.Encode(expected), tagHelperOutput1.Content.GetContent());
}
private static ViewContext GetViewContext() private static ViewContext GetViewContext()
{ {
var actionContext = new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor()); var actionContext = new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor());
return new ViewContext(actionContext, return new ViewContext(
Mock.Of<IView>(), actionContext,
new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary()), Mock.Of<IView>(),
Mock.Of<ITempDataDictionary>(), new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary()),
TextWriter.Null, Mock.Of<ITempDataDictionary>(),
new HtmlHelperOptions()); TextWriter.Null,
new HtmlHelperOptions());
} }
private static TagHelperContext GetTagHelperContext(string id = "testid") private static TagHelperContext GetTagHelperContext(string id = "testid")