Dispose CancellationTokenSource created in CacheTagHelper (#6293)
Fixes #5649
This commit is contained in:
parent
ca751c5297
commit
13e76c24d3
|
|
@ -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
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,4 +105,4 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
Loading…
Reference in New Issue