Private cache for cache tag helper and distributed cache tag helper

This commit is contained in:
Javier Calvarro Nelson 2017-07-05 15:09:33 -07:00
parent 65fce8dd65
commit 3d76fdf086
10 changed files with 234 additions and 73 deletions

View File

@ -2,15 +2,10 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.IO;
using Microsoft.AspNetCore.Antiforgery;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Razor.Internal;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace MvcSandbox
{
@ -20,11 +15,6 @@ namespace MvcSandbox
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddSingleton<IFileProvider>(new PhysicalFileProvider(Path.GetFullPath(".")));
services.Insert(0, ServiceDescriptor.Singleton(
typeof(IConfigureOptions<AntiforgeryOptions>),
new ConfigureOptions<AntiforgeryOptions>(options => options.Cookie.Name = "<choose a name>")));
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.

View File

@ -9,4 +9,4 @@
<li>This sandbox should give you a quick view of a basic MVC application.</li>
</ul>
</div>
</div>
</div>

View File

@ -3,6 +3,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="refresh" content="1">
<title>@ViewData["Title"] - MvcSandbox</title>
<link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.5/css/bootstrap.min.css" />
</head>

View File

@ -85,6 +85,9 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Cache
// Is there any request already processing the value?
if (!_workers.TryGetValue(key, out 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>();
_workers.TryAdd(key, tcs.Task);

View File

@ -10,6 +10,7 @@ using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Mvc.TagHelpers.Cache;
using Microsoft.AspNetCore.Mvc.TagHelpers.Internal;
using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal;
using Microsoft.AspNetCore.Razor.TagHelpers;
using Microsoft.Extensions.Caching.Memory;
@ -29,14 +30,22 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
private const string CachePriorityAttributeName = "priority";
// We need to come up with a value for the size of entries when storing a gating Task on the cache. Any value
// greater than 0 will suffice. We choose 56 bytes as an approximation of the size of the task that we store
// in the cache. This size got calculated as an upper bound for the size of an actual task on an x64 architecture
// and corresponds to 24 bytes for the object header block plus the 40 bytes added by the members of the task
// object.
private const int PlaceholderSize = 64;
/// <summary>
/// Creates a new <see cref="CacheTagHelper"/>.
/// </summary>
/// <param name="memoryCache">The <see cref="IMemoryCache"/>.</param>
/// <param name="factory">The factory containing the private <see cref="IMemoryCache"/> instance
/// used by the <see cref="CacheTagHelper"/>.</param>
/// <param name="htmlEncoder">The <see cref="HtmlEncoder"/> to use.</param>
public CacheTagHelper(IMemoryCache memoryCache, HtmlEncoder htmlEncoder) : base(htmlEncoder)
public CacheTagHelper(CacheTagHelperMemoryCacheFactory factory, HtmlEncoder htmlEncoder) : base(htmlEncoder)
{
MemoryCache = memoryCache;
MemoryCache = factory.Cache;
}
/// <summary>
@ -93,7 +102,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
var options = GetMemoryCacheEntryOptions();
options.AddExpirationToken(new CancellationChangeToken(tokenSource.Token));
options.SetSize(PlaceholderSize);
var tcs = new TaskCompletionSource<IHtmlContent>();
// The returned value is ignored, we only do this so that
@ -116,11 +125,11 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
// such that the tokens are inherited.
var result = ProcessContentAsync(output);
entry.SetOptions(options);
entry.Value = result;
content = await result;
options.SetSize(GetSize(content));
entry.SetOptions(options);
entry.Value = result;
}
tcs.SetResult(content);
@ -143,6 +152,22 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
}
}
private long GetSize(IHtmlContent content)
{
if (content is CharBufferHtmlContent charBuffer)
{
// We need to multiply the size of the buffer
// by a factor of two due to the fact that
// characters in .NET are UTF-16 which means
// every character uses two bytes (surrogates
// are represented as two characters)
return charBuffer.Buffer.Length * sizeof(char);
}
Debug.Fail($"{nameof(content)} should be an {nameof(CharBufferHtmlContent)}.");
return -1;
}
// Internal for unit testing
internal MemoryCacheEntryOptions GetMemoryCacheEntryOptions()
{
@ -226,17 +251,19 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
_buffer = buffer;
}
public PagedCharBuffer Buffer => _buffer;
public void WriteTo(TextWriter writer, HtmlEncoder encoder)
{
var length = _buffer.Length;
var length = Buffer.Length;
if (length == 0)
{
return;
}
for (var i = 0; i < _buffer.Pages.Count; i++)
for (var i = 0; i < Buffer.Pages.Count; i++)
{
var page = _buffer.Pages[i];
var page = Buffer.Pages[i];
var pageLength = Math.Min(length, page.Length);
writer.Write(page, index: 0, count: pageLength);
length -= pageLength;

View File

@ -0,0 +1,17 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.AspNetCore.Mvc.TagHelpers
{
/// <summary>
/// Provides programmatic configuration for the cache tag helper in the MVC framework.
/// </summary>
public class CacheTagHelperOptions
{
/// <summary>
/// The maximum total size in bytes that will be cached by the <see cref="CacheTagHelper"/>
/// at any given time.
/// </summary>
public long SizeLimit { get; set; }
}
}

View File

@ -2,18 +2,20 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNetCore.Mvc.TagHelpers;
using Microsoft.AspNetCore.Mvc.TagHelpers.Cache;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.AspNetCore.Mvc.TagHelpers.Internal;
using Microsoft.Extensions.DependencyInjection.Extensions;
namespace Microsoft.Extensions.DependencyInjection
{
{
/// <summary>
/// Extension methods for configuring Razor cache tag helpers.
/// </summary>
public static class TagHelperServicesExtensions
{
private const int DefaultCacheMaximumSizeInBytes = 100 * 1024 * 1024; // 100MB
/// <summary>
/// Adds MVC cache tag helper services to the application.
/// </summary>
@ -26,13 +28,60 @@ namespace Microsoft.Extensions.DependencyInjection
throw new ArgumentNullException(nameof(builder));
}
builder.Services.TryAddTransient<IDistributedCacheTagHelperStorage, DistributedCacheTagHelperStorage>();
builder.Services.TryAddTransient<IDistributedCacheTagHelperFormatter, DistributedCacheTagHelperFormatter>();
builder.Services.TryAddSingleton<IDistributedCacheTagHelperStorage, DistributedCacheTagHelperStorage>();
builder.Services.TryAddSingleton<IDistributedCacheTagHelperFormatter, DistributedCacheTagHelperFormatter>();
builder.Services.TryAddSingleton<IDistributedCacheTagHelperService, DistributedCacheTagHelperService>();
// Required default services for cache tag helpers
builder.Services.TryAddSingleton<IDistributedCache, MemoryDistributedCache>();
builder.Services.TryAddSingleton<IMemoryCache, MemoryCache>();
builder.Services.AddDistributedMemoryCache();
builder.Services.TryAddSingleton<CacheTagHelperMemoryCacheFactory>();
builder.AddCacheTagHelperLimits(options => options.SizeLimit = DefaultCacheMaximumSizeInBytes);
return builder;
}
/// <summary>
/// Configures the memory size limits on the cache of the <see cref="CacheTagHelper"/>.
/// </summary>
/// <param name="builder">The <see cref="IMvcBuilder"/>.</param>
/// <param name="configure">The <see cref="Action{CacheTagHelperOptions}"/>to configure the cache options.</param>
/// <returns>The <see cref="IMvcBuilder"/>.</returns>
public static IMvcBuilder AddCacheTagHelperLimits(this IMvcBuilder builder, Action<CacheTagHelperOptions> configure)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
if (configure == null)
{
throw new ArgumentNullException(nameof(configure));
}
builder.Services.Configure(configure);
return builder;
}
/// <summary>
/// Configures the memory size limits on the cache of the <see cref="CacheTagHelper"/>.
/// </summary>
/// <param name="builder">The <see cref="IMvcCoreBuilder"/>.</param>
/// <param name="configure">The <see cref="Action{CacheTagHelperOptions}"/>to configure the cache options.</param>
/// <returns>The <see cref="IMvcCoreBuilder"/>.</returns>
public static IMvcCoreBuilder AddCacheTagHelperLimits(this IMvcCoreBuilder builder, Action<CacheTagHelperOptions> configure)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
if (configure == null)
{
throw new ArgumentNullException(nameof(configure));
}
builder.Services.Configure(configure);
return builder;
}

View File

@ -0,0 +1,27 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Mvc.TagHelpers.Internal
{
public class CacheTagHelperMemoryCacheFactory
{
public CacheTagHelperMemoryCacheFactory(IOptions<CacheTagHelperOptions> options)
{
Cache = new MemoryCache(new MemoryCacheOptions
{
SizeLimit = options.Value.SizeLimit
});
}
// For testing only.
internal CacheTagHelperMemoryCacheFactory(IMemoryCache cache)
{
Cache = cache;
}
public IMemoryCache Cache { get; }
}
}

View File

@ -13,6 +13,7 @@ using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.TagHelpers.Cache;
using Microsoft.AspNetCore.Mvc.TagHelpers.Internal;
using Microsoft.AspNetCore.Mvc.ViewEngines;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers;
@ -48,7 +49,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
var tagHelperOutput = GetTagHelperOutput(
attributes: new TagHelperAttributeList(),
childContent: childContent);
var cacheTagHelper = new CacheTagHelper(cache.Object, new HtmlTestEncoder())
var cacheTagHelper = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache.Object), new HtmlTestEncoder())
{
ViewContext = GetViewContext(),
Enabled = false
@ -75,7 +76,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
var tagHelperOutput = GetTagHelperOutput(
attributes: new TagHelperAttributeList(),
childContent: childContent);
var cacheTagHelper = new CacheTagHelper(cache, new HtmlTestEncoder())
var cacheTagHelper = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder())
{
ViewContext = GetViewContext(),
Enabled = true
@ -102,7 +103,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
var tagHelperOutput1 = GetTagHelperOutput(
attributes: new TagHelperAttributeList(),
childContent: childContent);
var cacheTagHelper1 = new CacheTagHelper(cache, new HtmlTestEncoder())
var cacheTagHelper1 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder())
{
VaryByQuery = "key1,key2",
ViewContext = GetViewContext(),
@ -124,7 +125,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
var tagHelperOutput2 = GetTagHelperOutput(
attributes: new TagHelperAttributeList(),
childContent: "different-content");
var cacheTagHelper2 = new CacheTagHelper(cache, new HtmlTestEncoder())
var cacheTagHelper2 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder())
{
VaryByQuery = "key1,key2",
ViewContext = GetViewContext(),
@ -153,7 +154,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
var tagHelperOutput1 = GetTagHelperOutput(childContent: childContent1);
tagHelperOutput1.PreContent.Append("<cache>");
tagHelperOutput1.PostContent.SetContent("</cache>");
var cacheTagHelper1 = new CacheTagHelper(cache, new HtmlTestEncoder())
var cacheTagHelper1 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder())
{
VaryByCookie = "cookie1,cookie2",
ViewContext = GetViewContext(),
@ -175,7 +176,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
var tagHelperOutput2 = GetTagHelperOutput(childContent: childContent2);
tagHelperOutput2.PreContent.SetContent("<cache>");
tagHelperOutput2.PostContent.SetContent("</cache>");
var cacheTagHelper2 = new CacheTagHelper(cache, new HtmlTestEncoder())
var cacheTagHelper2 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder())
{
VaryByCookie = "cookie1,cookie2",
ViewContext = GetViewContext(),
@ -198,7 +199,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
// Arrange
var expiresOn = DateTimeOffset.UtcNow.AddMinutes(4);
var cache = new MemoryCache(new MemoryCacheOptions());
var cacheTagHelper = new CacheTagHelper(cache, new HtmlTestEncoder())
var cacheTagHelper = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder())
{
ExpiresOn = expiresOn
};
@ -210,13 +211,58 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
Assert.Equal(expiresOn, cacheEntryOptions.AbsoluteExpiration);
}
[Fact]
public async Task ProcessAsync_SetsEntrySize_ForPlaceholderAndFinalCacheEntries()
{
// Arrange
var mockCache = new Mock<IMemoryCache>();
var tempEntry = new Mock<ICacheEntry>();
tempEntry.SetupAllProperties();
tempEntry.Setup(e => e.ExpirationTokens).Returns(new List<IChangeToken>());
tempEntry.Setup(e => e.PostEvictionCallbacks).Returns(new List<PostEvictionCallbackRegistration>());
var finalEntry = new Mock<ICacheEntry>();
finalEntry.SetupAllProperties();
finalEntry.Setup(e => e.ExpirationTokens).Returns(new List<IChangeToken>());
finalEntry.Setup(e => e.PostEvictionCallbacks).Returns(new List<PostEvictionCallbackRegistration>());
object value;
mockCache
.Setup(s => s.TryGetValue(It.IsAny<object>(), out value))
.Returns(false);
mockCache.SetupSequence(mc => mc.CreateEntry(It.IsAny<object>()))
.Returns(tempEntry.Object)
.Returns(finalEntry.Object);
var id = "unique-id";
var childContent1 = "original-child-content";
var tagHelperContext1 = GetTagHelperContext(id);
var tagHelperOutput1 = GetTagHelperOutput(childContent: childContent1);
tagHelperOutput1.PreContent.Append("<cache>");
tagHelperOutput1.PostContent.SetContent("</cache>");
var cacheTagHelper1 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(mockCache.Object), new HtmlTestEncoder())
{
ViewContext = GetViewContext(),
};
// Act
await cacheTagHelper1.ProcessAsync(tagHelperContext1, tagHelperOutput1);
// Assert
Assert.Empty(tagHelperOutput1.PreContent.GetContent());
Assert.Empty(tagHelperOutput1.PostContent.GetContent());
Assert.True(tagHelperOutput1.IsContentModified);
Assert.Equal(childContent1, tagHelperOutput1.Content.GetContent());
tempEntry.VerifySet(e => e.Size = 64);
finalEntry.VerifySet(e => e.Size = childContent1.Length * 2);
}
[Fact]
public void UpdateCacheEntryOptions_DefaultsTo30SecondsSliding_IfNoEvictionCriteriaIsProvided()
{
// Arrange
var slidingExpiresIn = TimeSpan.FromSeconds(30);
var cache = new MemoryCache(new MemoryCacheOptions());
var cacheTagHelper = new CacheTagHelper(cache, new HtmlTestEncoder());
var cacheTagHelper = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder());
// Act
var cacheEntryOptions = cacheTagHelper.GetMemoryCacheEntryOptions();
@ -231,7 +277,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
// Arrange
var expiresAfter = TimeSpan.FromSeconds(42);
var cache = new MemoryCache(new MemoryCacheOptions());
var cacheTagHelper = new CacheTagHelper(cache, new HtmlTestEncoder())
var cacheTagHelper = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder())
{
ExpiresAfter = expiresAfter
};
@ -249,7 +295,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
// Arrange
var expiresSliding = TimeSpan.FromSeconds(37);
var cache = new MemoryCache(new MemoryCacheOptions());
var cacheTagHelper = new CacheTagHelper(cache, new HtmlTestEncoder())
var cacheTagHelper = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder())
{
ExpiresSliding = expiresSliding
};
@ -267,7 +313,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
// Arrange
var priority = CacheItemPriority.High;
var cache = new MemoryCache(new MemoryCacheOptions());
var cacheTagHelper = new CacheTagHelper(cache, new HtmlTestEncoder())
var cacheTagHelper = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder())
{
Priority = priority
};
@ -294,7 +340,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
var tagHelperOutput1 = GetTagHelperOutput(childContent: childContent1);
tagHelperOutput1.PreContent.SetContent("<cache>");
tagHelperOutput1.PostContent.SetContent("</cache>");
var cacheTagHelper1 = new CacheTagHelper(cache, new HtmlTestEncoder())
var cacheTagHelper1 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder())
{
ViewContext = GetViewContext(),
ExpiresAfter = TimeSpan.FromMinutes(10)
@ -315,7 +361,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
var tagHelperOutput2 = GetTagHelperOutput(childContent: childContent2);
tagHelperOutput2.PreContent.SetContent("<cache>");
tagHelperOutput2.PostContent.SetContent("</cache>");
var cacheTagHelper2 = new CacheTagHelper(cache, new HtmlTestEncoder())
var cacheTagHelper2 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder())
{
ViewContext = GetViewContext(),
ExpiresAfter = TimeSpan.FromMinutes(10)
@ -347,7 +393,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
var tagHelperOutput1 = GetTagHelperOutput(childContent: childContent1);
tagHelperOutput1.PreContent.SetContent("<cache>");
tagHelperOutput1.PostContent.SetContent("</cache>");
var cacheTagHelper1 = new CacheTagHelper(cache, new HtmlTestEncoder())
var cacheTagHelper1 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder())
{
ViewContext = GetViewContext(),
ExpiresOn = currentTime.AddMinutes(5)
@ -369,7 +415,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
var tagHelperOutput2 = GetTagHelperOutput(childContent: childContent2);
tagHelperOutput2.PreContent.SetContent("<cache>");
tagHelperOutput2.PostContent.SetContent("</cache>");
var cacheTagHelper2 = new CacheTagHelper(cache, new HtmlTestEncoder())
var cacheTagHelper2 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder())
{
ViewContext = GetViewContext(),
ExpiresOn = currentTime.AddMinutes(5)
@ -400,7 +446,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
var tagHelperOutput1 = GetTagHelperOutput(childContent: childContent1);
tagHelperOutput1.PreContent.SetContent("<cache>");
tagHelperOutput1.PostContent.SetContent("</cache>");
var cacheTagHelper1 = new CacheTagHelper(cache, new HtmlTestEncoder())
var cacheTagHelper1 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder())
{
ViewContext = GetViewContext(),
ExpiresSliding = TimeSpan.FromSeconds(30)
@ -422,7 +468,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
var tagHelperOutput2 = GetTagHelperOutput(childContent: childContent2);
tagHelperOutput2.PreContent.SetContent("<cache>");
tagHelperOutput2.PostContent.SetContent("</cache>");
var cacheTagHelper2 = new CacheTagHelper(cache, new HtmlTestEncoder())
var cacheTagHelper2 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder())
{
ViewContext = GetViewContext(),
ExpiresSliding = TimeSpan.FromSeconds(30)
@ -469,7 +515,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
});
tagHelperOutput.PreContent.SetContent("<cache>");
tagHelperOutput.PostContent.SetContent("</cache>");
var cacheTagHelper = new CacheTagHelper(cache, new HtmlTestEncoder())
var cacheTagHelper = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder())
{
ViewContext = GetViewContext(),
};
@ -535,13 +581,13 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
return Task.FromResult<TagHelperContent>(tagHelperContent);
});
var cacheTagHelper1 = new CacheTagHelper(cache, new HtmlTestEncoder())
var cacheTagHelper1 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder())
{
ViewContext = GetViewContext(),
Enabled = true
};
var cacheTagHelper2 = new CacheTagHelper(cache, new HtmlTestEncoder())
var cacheTagHelper2 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder())
{
ViewContext = GetViewContext(),
Enabled = true
@ -618,13 +664,13 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
return Task.FromResult<TagHelperContent>(tagHelperContent);
});
var cacheTagHelper1 = new CacheTagHelper(cache, new HtmlTestEncoder())
var cacheTagHelper1 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder())
{
ViewContext = GetViewContext(),
Enabled = true
};
var cacheTagHelper2 = new CacheTagHelper(cache, new HtmlTestEncoder())
var cacheTagHelper2 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder())
{
ViewContext = GetViewContext(),
Enabled = true
@ -699,7 +745,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
var tagHelperOutput3 = new TagHelperOutput("cache", new TagHelperAttributeList(), GetChildContentAsync);
var tagHelperOutput4 = new TagHelperOutput("cache", new TagHelperAttributeList(), GetChildContentAsync);
var cacheTagHelper = new CacheTagHelper(cache, new HtmlTestEncoder())
var cacheTagHelper = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder())
{
ViewContext = GetViewContext(),
Enabled = true,
@ -762,13 +808,13 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
var expected = "Hello world";
var cache = new MemoryCache(new MemoryCacheOptions());
var encoder = new HtmlTestEncoder();
var cacheTagHelper1 = new CacheTagHelper(cache, encoder)
var cacheTagHelper1 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), encoder)
{
ViewContext = GetViewContext(),
Enabled = true
};
var cacheTagHelper2 = new CacheTagHelper(cache, encoder)
var cacheTagHelper2 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), encoder)
{
ViewContext = GetViewContext(),
Enabled = true
@ -808,7 +854,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
// Arrange
var expected = new DivideByZeroException();
var cache = new TestMemoryCache();
var cacheTagHelper = new CacheTagHelper(cache, new HtmlTestEncoder())
var cacheTagHelper = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder())
{
ViewContext = GetViewContext(),
Enabled = true
@ -841,7 +887,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
var expected = "Hello world";
var cache = new TestMemoryCache();
var encoder = new HtmlTestEncoder();
var cacheTagHelper = new CacheTagHelper(cache, encoder)
var cacheTagHelper = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), encoder)
{
ViewContext = GetViewContext(),
Enabled = true

View File

@ -10,6 +10,7 @@ using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.TagHelpers.Cache;
using Microsoft.AspNetCore.Mvc.TagHelpers.Internal;
using Microsoft.AspNetCore.Mvc.ViewEngines;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers;
@ -29,7 +30,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
// Arrange
var id = Guid.NewGuid().ToString();
var tagHelperContext = GetTagHelperContext(id);
var cacheTagHelper = new CacheTagHelper(Mock.Of<IMemoryCache>(), new HtmlTestEncoder())
var cacheTagHelper = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(Mock.Of<IMemoryCache>()), new HtmlTestEncoder())
{
ViewContext = GetViewContext()
};
@ -49,13 +50,13 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
// Arrange
var id = Guid.NewGuid().ToString();
var tagHelperContext1 = GetTagHelperContext(id);
var cacheTagHelper1 = new CacheTagHelper(Mock.Of<IMemoryCache>(), new HtmlTestEncoder())
var cacheTagHelper1 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(Mock.Of<IMemoryCache>()), new HtmlTestEncoder())
{
ViewContext = GetViewContext()
};
var tagHelperContext2 = GetTagHelperContext(id);
var cacheTagHelper2 = new CacheTagHelper(Mock.Of<IMemoryCache>(), new HtmlTestEncoder())
var cacheTagHelper2 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(Mock.Of<IMemoryCache>()), new HtmlTestEncoder())
{
ViewContext = GetViewContext()
};
@ -73,13 +74,13 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
{
// Arrange
var tagHelperContext1 = GetTagHelperContext("some-id");
var cacheTagHelper1 = new CacheTagHelper(Mock.Of<IMemoryCache>(), new HtmlTestEncoder())
var cacheTagHelper1 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(Mock.Of<IMemoryCache>()), new HtmlTestEncoder())
{
ViewContext = GetViewContext()
};
var tagHelperContext2 = GetTagHelperContext("some-other-id");
var cacheTagHelper2 = new CacheTagHelper(Mock.Of<IMemoryCache>(), new HtmlTestEncoder())
var cacheTagHelper2 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(Mock.Of<IMemoryCache>()), new HtmlTestEncoder())
{
ViewContext = GetViewContext()
};
@ -97,13 +98,13 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
{
// Arrange
var tagHelperContext1 = GetTagHelperContext("some-id");
var cacheTagHelper1 = new CacheTagHelper(Mock.Of<IMemoryCache>(), new HtmlTestEncoder())
var cacheTagHelper1 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(Mock.Of<IMemoryCache>()), new HtmlTestEncoder())
{
ViewContext = GetViewContext()
};
var tagHelperContext2 = GetTagHelperContext("some-id");
var cacheTagHelper2 = new CacheTagHelper(Mock.Of<IMemoryCache>(), new HtmlTestEncoder())
var cacheTagHelper2 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(Mock.Of<IMemoryCache>()), new HtmlTestEncoder())
{
ViewContext = GetViewContext()
};
@ -124,13 +125,13 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
{
// Arrange
var tagHelperContext1 = GetTagHelperContext("some-id");
var cacheTagHelper1 = new CacheTagHelper(Mock.Of<IMemoryCache>(), new HtmlTestEncoder())
var cacheTagHelper1 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(Mock.Of<IMemoryCache>()), new HtmlTestEncoder())
{
ViewContext = GetViewContext()
};
var tagHelperContext2 = GetTagHelperContext("some-other-id");
var cacheTagHelper2 = new CacheTagHelper(Mock.Of<IMemoryCache>(), new HtmlTestEncoder())
var cacheTagHelper2 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(Mock.Of<IMemoryCache>()), new HtmlTestEncoder())
{
ViewContext = GetViewContext()
};
@ -177,7 +178,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
{
// Arrange
var tagHelperContext = GetTagHelperContext();
var cacheTagHelper = new CacheTagHelper(Mock.Of<IMemoryCache>(), new HtmlTestEncoder())
var cacheTagHelper = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(Mock.Of<IMemoryCache>()), new HtmlTestEncoder())
{
ViewContext = GetViewContext(),
VaryBy = varyBy
@ -206,7 +207,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
{
// Arrange
var tagHelperContext = GetTagHelperContext();
var cacheTagHelper = new CacheTagHelper(Mock.Of<IMemoryCache>(), new HtmlTestEncoder())
var cacheTagHelper = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(Mock.Of<IMemoryCache>()), new HtmlTestEncoder())
{
ViewContext = GetViewContext(),
VaryByCookie = varyByCookie
@ -232,7 +233,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
{
// Arrange
var tagHelperContext = GetTagHelperContext();
var cacheTagHelper = new CacheTagHelper(Mock.Of<IMemoryCache>(), new HtmlTestEncoder())
var cacheTagHelper = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(Mock.Of<IMemoryCache>()), new HtmlTestEncoder())
{
ViewContext = GetViewContext(),
VaryByHeader = varyByHeader
@ -260,7 +261,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
{
// Arrange
var tagHelperContext = GetTagHelperContext();
var cacheTagHelper = new CacheTagHelper(Mock.Of<IMemoryCache>(), new HtmlTestEncoder())
var cacheTagHelper = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(Mock.Of<IMemoryCache>()), new HtmlTestEncoder())
{
ViewContext = GetViewContext(),
VaryByQuery = varyByQuery
@ -286,7 +287,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
{
// Arrange
var tagHelperContext = GetTagHelperContext();
var cacheTagHelper = new CacheTagHelper(Mock.Of<IMemoryCache>(), new HtmlTestEncoder())
var cacheTagHelper = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(Mock.Of<IMemoryCache>()), new HtmlTestEncoder())
{
ViewContext = GetViewContext(),
VaryByRoute = varyByRoute
@ -308,7 +309,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
// Arrange
var expected = "CacheTagHelper||testid||VaryByUser||";
var tagHelperContext = GetTagHelperContext();
var cacheTagHelper = new CacheTagHelper(Mock.Of<IMemoryCache>(), new HtmlTestEncoder())
var cacheTagHelper = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(Mock.Of<IMemoryCache>()), new HtmlTestEncoder())
{
ViewContext = GetViewContext(),
VaryByUser = true
@ -328,7 +329,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
// Arrange
var expected = "CacheTagHelper||testid||VaryByUser||test_name";
var tagHelperContext = GetTagHelperContext();
var cacheTagHelper = new CacheTagHelper(Mock.Of<IMemoryCache>(), new HtmlTestEncoder())
var cacheTagHelper = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(Mock.Of<IMemoryCache>()), new HtmlTestEncoder())
{
ViewContext = GetViewContext(),
VaryByUser = true
@ -351,7 +352,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
var expected = "CacheTagHelper||testid||VaryBy||custom-value||" +
"VaryByHeader(content-type||text/html)||VaryByUser||someuser";
var tagHelperContext = GetTagHelperContext();
var cacheTagHelper = new CacheTagHelper(Mock.Of<IMemoryCache>(), new HtmlTestEncoder())
var cacheTagHelper = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(Mock.Of<IMemoryCache>()), new HtmlTestEncoder())
{
ViewContext = GetViewContext(),
VaryByUser = true,