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
{
// 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.
using (var entry = MemoryCache.CreateEntry(cacheKey))
@ -108,18 +108,24 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
content = await result;
}
tcs.SetResult(content);
}
catch
{
// Remove the worker task from the cache in case it can't complete.
tokenSource.Cancel();
// If an exception occurs, ensure the other awaiters
// render the output by themselves.
tcs.SetResult(null);
throw;
}
finally
{
// If an exception occurs, ensure the other awaiters
// render the output by themselves.
tcs.SetResult(null);
// The tokenSource needs to be disposed as the MemoryCache
// will register a callback on the Token.
tokenSource.Dispose();
}
}
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);
}
[Fact]
public async Task ProcessAsync_ExceptionInProcessing_DoNotThrowInSubsequentRequests()
@ -743,15 +742,63 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
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()
{
var actionContext = new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor());
return new ViewContext(actionContext,
Mock.Of<IView>(),
new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary()),
Mock.Of<ITempDataDictionary>(),
TextWriter.Null,
new HtmlHelperOptions());
return new ViewContext(
actionContext,
Mock.Of<IView>(),
new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary()),
Mock.Of<ITempDataDictionary>(),
TextWriter.Null,
new HtmlHelperOptions());
}
private static TagHelperContext GetTagHelperContext(string id = "testid")