Merge remote-tracking branch 'origin/release/2.2'
This commit is contained in:
commit
567aa6e110
|
|
@ -10,6 +10,7 @@ using Microsoft.AspNetCore.Mvc.ApplicationParts;
|
|||
using Microsoft.AspNetCore.Mvc.Razor;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.Compilation;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.Extensions;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.Infrastructure;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.Internal;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.TagHelpers;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
|
|
@ -226,6 +227,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
|
||||
// Consumed by the Cache tag helper to cache results across the lifetime of the application.
|
||||
services.TryAddSingleton<IMemoryCache, MemoryCache>();
|
||||
services.TryAddSingleton<TagHelperMemoryCacheProvider>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
// 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;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Razor.Infrastructure
|
||||
{
|
||||
/// <summary>
|
||||
/// This API supports the MVC's infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change in future releases.
|
||||
/// </summary>
|
||||
public sealed class TagHelperMemoryCacheProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// This API supports the MVC's infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change in future releases.
|
||||
/// </summary>
|
||||
public IMemoryCache Cache { get; } = new MemoryCache(new MemoryCacheOptions
|
||||
{
|
||||
SizeLimit = 10 * 1024 * 1024 // 10MB
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -4,11 +4,13 @@
|
|||
using System;
|
||||
using System.Text.Encodings.Web;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.Infrastructure;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.TagHelpers;
|
||||
using Microsoft.AspNetCore.Mvc.Routing;
|
||||
using Microsoft.AspNetCore.Mvc.TagHelpers.Internal;
|
||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
{
|
||||
|
|
@ -36,6 +38,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
/// <param name="cache">The <see cref="IMemoryCache"/>.</param>
|
||||
/// <param name="htmlEncoder">The <see cref="HtmlEncoder"/> to use.</param>
|
||||
/// <param name="urlHelperFactory">The <see cref="IUrlHelperFactory"/>.</param>
|
||||
[Obsolete("This constructor is obsolete and will be removed in a future version.")]
|
||||
public ImageTagHelper(
|
||||
IHostingEnvironment hostingEnvironment,
|
||||
IMemoryCache cache,
|
||||
|
|
@ -47,6 +50,27 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
Cache = cache;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="ImageTagHelper"/>.
|
||||
/// </summary>
|
||||
/// <param name="hostingEnvironment">The <see cref="IHostingEnvironment"/>.</param>
|
||||
/// <param name="cacheProvider">The <see cref="TagHelperMemoryCacheProvider"/>.</param>
|
||||
/// <param name="htmlEncoder">The <see cref="HtmlEncoder"/> to use.</param>
|
||||
/// <param name="urlHelperFactory">The <see cref="IUrlHelperFactory"/>.</param>
|
||||
// Decorated with ActivatorUtilitiesConstructor since we want to influence tag helper activation
|
||||
// to use this constructor in the default case.
|
||||
[ActivatorUtilitiesConstructor]
|
||||
public ImageTagHelper(
|
||||
IHostingEnvironment hostingEnvironment,
|
||||
TagHelperMemoryCacheProvider cacheProvider,
|
||||
HtmlEncoder htmlEncoder,
|
||||
IUrlHelperFactory urlHelperFactory)
|
||||
: base(urlHelperFactory, htmlEncoder)
|
||||
{
|
||||
HostingEnvironment = hostingEnvironment;
|
||||
Cache = cacheProvider.Cache;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override int Order => -1000;
|
||||
|
||||
|
|
@ -68,9 +92,9 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
[HtmlAttributeName(AppendVersionAttributeName)]
|
||||
public bool AppendVersion { get; set; }
|
||||
|
||||
protected IHostingEnvironment HostingEnvironment { get; }
|
||||
protected internal IHostingEnvironment HostingEnvironment { get; }
|
||||
|
||||
protected IMemoryCache Cache { get; }
|
||||
protected internal IMemoryCache Cache { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Process(TagHelperContext context, TagHelperOutput output)
|
||||
|
|
|
|||
|
|
@ -69,42 +69,42 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Internal
|
|||
resolvedPath = path.Substring(0, queryStringOrFragmentStartIndex);
|
||||
}
|
||||
|
||||
Uri uri;
|
||||
if (Uri.TryCreate(resolvedPath, UriKind.Absolute, out uri) && !uri.IsFile)
|
||||
if (Uri.TryCreate(resolvedPath, UriKind.Absolute, out var uri) && !uri.IsFile)
|
||||
{
|
||||
// Don't append version if the path is absolute.
|
||||
return path;
|
||||
}
|
||||
|
||||
string value;
|
||||
if (!_cache.TryGetValue(path, out value))
|
||||
if (_cache.TryGetValue(path, out string value))
|
||||
{
|
||||
var cacheEntryOptions = new MemoryCacheEntryOptions();
|
||||
cacheEntryOptions.AddExpirationToken(_fileProvider.Watch(resolvedPath));
|
||||
var fileInfo = _fileProvider.GetFileInfo(resolvedPath);
|
||||
|
||||
if (!fileInfo.Exists &&
|
||||
_requestPathBase.HasValue &&
|
||||
resolvedPath.StartsWith(_requestPathBase.Value, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var requestPathBaseRelativePath = resolvedPath.Substring(_requestPathBase.Value.Length);
|
||||
cacheEntryOptions.AddExpirationToken(_fileProvider.Watch(requestPathBaseRelativePath));
|
||||
fileInfo = _fileProvider.GetFileInfo(requestPathBaseRelativePath);
|
||||
}
|
||||
|
||||
if (fileInfo.Exists)
|
||||
{
|
||||
value = QueryHelpers.AddQueryString(path, VersionKey, GetHashForFile(fileInfo));
|
||||
}
|
||||
else
|
||||
{
|
||||
// if the file is not in the current server.
|
||||
value = path;
|
||||
}
|
||||
|
||||
value = _cache.Set(path, value, cacheEntryOptions);
|
||||
return value;
|
||||
}
|
||||
|
||||
var cacheEntryOptions = new MemoryCacheEntryOptions();
|
||||
cacheEntryOptions.AddExpirationToken(_fileProvider.Watch(resolvedPath));
|
||||
var fileInfo = _fileProvider.GetFileInfo(resolvedPath);
|
||||
|
||||
if (!fileInfo.Exists &&
|
||||
_requestPathBase.HasValue &&
|
||||
resolvedPath.StartsWith(_requestPathBase.Value, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var requestPathBaseRelativePath = resolvedPath.Substring(_requestPathBase.Value.Length);
|
||||
cacheEntryOptions.AddExpirationToken(_fileProvider.Watch(requestPathBaseRelativePath));
|
||||
fileInfo = _fileProvider.GetFileInfo(requestPathBaseRelativePath);
|
||||
}
|
||||
|
||||
if (fileInfo.Exists)
|
||||
{
|
||||
value = QueryHelpers.AddQueryString(path, VersionKey, GetHashForFile(fileInfo));
|
||||
}
|
||||
else
|
||||
{
|
||||
// if the file is not in the current server.
|
||||
value = path;
|
||||
}
|
||||
|
||||
cacheEntryOptions.SetSize(value.Length * sizeof(char));
|
||||
value = _cache.Set(path, value, cacheEntryOptions);
|
||||
return value;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -113,8 +113,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Internal
|
|||
}
|
||||
|
||||
var cacheKey = new GlobbingUrlKey(include, exclude);
|
||||
List<string> files;
|
||||
if (Cache.TryGetValue(cacheKey, out files))
|
||||
if (Cache.TryGetValue(cacheKey, out List<string> files))
|
||||
{
|
||||
return files;
|
||||
}
|
||||
|
|
@ -148,16 +147,21 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Internal
|
|||
matcher.AddExcludePatterns(trimmedExcludePatterns);
|
||||
}
|
||||
|
||||
var (matchedUrls, sizeInBytes) = FindFiles(matcher);
|
||||
options.SetSize(sizeInBytes);
|
||||
|
||||
return Cache.Set(
|
||||
cacheKey,
|
||||
FindFiles(matcher),
|
||||
matchedUrls,
|
||||
options);
|
||||
}
|
||||
|
||||
private List<string> FindFiles(Matcher matcher)
|
||||
private (List<string> matchedUrls, long sizeInBytes) FindFiles(Matcher matcher)
|
||||
{
|
||||
var matches = matcher.Execute(_baseGlobbingDirectory);
|
||||
var matchedUrls = new List<string>();
|
||||
var sizeInBytes = 0L;
|
||||
|
||||
foreach (var matchedPath in matches.Files)
|
||||
{
|
||||
// Resolve the path to site root
|
||||
|
|
@ -168,10 +172,11 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Internal
|
|||
{
|
||||
// Item doesn't already exist. Insert it.
|
||||
matchedUrls.Insert(~index, matchedUrl);
|
||||
sizeInBytes += matchedUrl.Length * sizeof(char);
|
||||
}
|
||||
}
|
||||
|
||||
return matchedUrls;
|
||||
return (matchedUrls, sizeInBytes);
|
||||
}
|
||||
|
||||
private class PathComparer : IComparer<string>
|
||||
|
|
@ -231,9 +236,8 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Internal
|
|||
var result = 0;
|
||||
var xEnumerator = new StringTokenizer(xNoExt, PathSeparator).GetEnumerator();
|
||||
var yEnumerator = new StringTokenizer(yNoExt, PathSeparator).GetEnumerator();
|
||||
StringSegment xSegment;
|
||||
StringSegment ySegment;
|
||||
while (TryGetNextSegment(ref xEnumerator, out xSegment))
|
||||
while (TryGetNextSegment(ref xEnumerator, out var xSegment))
|
||||
{
|
||||
if (!TryGetNextSegment(ref yEnumerator, out ySegment))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -8,11 +8,13 @@ using System.IO;
|
|||
using System.Text.Encodings.Web;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Html;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.Infrastructure;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.TagHelpers;
|
||||
using Microsoft.AspNetCore.Mvc.Routing;
|
||||
using Microsoft.AspNetCore.Mvc.TagHelpers.Internal;
|
||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
{
|
||||
|
|
@ -33,7 +35,6 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
[HtmlTargetElement("link", Attributes = AppendVersionAttributeName, TagStructure = TagStructure.WithoutEndTag)]
|
||||
public class LinkTagHelper : UrlResolutionTagHelper
|
||||
{
|
||||
|
||||
private static readonly string FallbackJavaScriptResourceName =
|
||||
typeof(LinkTagHelper).Namespace + ".compiler.resources.LinkTagHelper_FallbackJavaScript.js";
|
||||
|
||||
|
|
@ -103,6 +104,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
/// <param name="htmlEncoder">The <see cref="HtmlEncoder"/>.</param>
|
||||
/// <param name="javaScriptEncoder">The <see cref="JavaScriptEncoder"/>.</param>
|
||||
/// <param name="urlHelperFactory">The <see cref="IUrlHelperFactory"/>.</param>
|
||||
[Obsolete("This constructor is obsolete and will be removed in a future version.")]
|
||||
public LinkTagHelper(
|
||||
IHostingEnvironment hostingEnvironment,
|
||||
IMemoryCache cache,
|
||||
|
|
@ -112,8 +114,32 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
: base(urlHelperFactory, htmlEncoder)
|
||||
{
|
||||
HostingEnvironment = hostingEnvironment;
|
||||
Cache = cache;
|
||||
JavaScriptEncoder = javaScriptEncoder;
|
||||
Cache = cache;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="LinkTagHelper"/>.
|
||||
/// </summary>
|
||||
/// <param name="hostingEnvironment">The <see cref="IHostingEnvironment"/>.</param>
|
||||
/// <param name="cacheProvider"></param>
|
||||
/// <param name="htmlEncoder">The <see cref="HtmlEncoder"/>.</param>
|
||||
/// <param name="javaScriptEncoder">The <see cref="JavaScriptEncoder"/>.</param>
|
||||
/// <param name="urlHelperFactory">The <see cref="IUrlHelperFactory"/>.</param>
|
||||
// Decorated with ActivatorUtilitiesConstructor since we want to influence tag helper activation
|
||||
// to use this constructor in the default case.
|
||||
[ActivatorUtilitiesConstructor]
|
||||
public LinkTagHelper(
|
||||
IHostingEnvironment hostingEnvironment,
|
||||
TagHelperMemoryCacheProvider cacheProvider,
|
||||
HtmlEncoder htmlEncoder,
|
||||
JavaScriptEncoder javaScriptEncoder,
|
||||
IUrlHelperFactory urlHelperFactory)
|
||||
: base(urlHelperFactory, htmlEncoder)
|
||||
{
|
||||
HostingEnvironment = hostingEnvironment;
|
||||
JavaScriptEncoder = javaScriptEncoder;
|
||||
Cache = cacheProvider.Cache;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
|
@ -205,9 +231,9 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
[HtmlAttributeName(FallbackTestValueAttributeName)]
|
||||
public string FallbackTestValue { get; set; }
|
||||
|
||||
protected IHostingEnvironment HostingEnvironment { get; }
|
||||
protected internal IHostingEnvironment HostingEnvironment { get; }
|
||||
|
||||
protected IMemoryCache Cache { get; }
|
||||
protected internal IMemoryCache Cache { get; }
|
||||
|
||||
protected JavaScriptEncoder JavaScriptEncoder { get; }
|
||||
|
||||
|
|
|
|||
|
|
@ -7,11 +7,14 @@ using System.IO;
|
|||
using System.Text.Encodings.Web;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Html;
|
||||
using Microsoft.AspNetCore.Mvc.Razor;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.Infrastructure;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.TagHelpers;
|
||||
using Microsoft.AspNetCore.Mvc.Routing;
|
||||
using Microsoft.AspNetCore.Mvc.TagHelpers.Internal;
|
||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
{
|
||||
|
|
@ -85,6 +88,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
/// <param name="htmlEncoder">The <see cref="HtmlEncoder"/>.</param>
|
||||
/// <param name="javaScriptEncoder">The <see cref="JavaScriptEncoder"/>.</param>
|
||||
/// <param name="urlHelperFactory">The <see cref="IUrlHelperFactory"/>.</param>
|
||||
[Obsolete("This constructor is obsolete and will be removed in a future version.")]
|
||||
public ScriptTagHelper(
|
||||
IHostingEnvironment hostingEnvironment,
|
||||
IMemoryCache cache,
|
||||
|
|
@ -98,6 +102,30 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
JavaScriptEncoder = javaScriptEncoder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="ScriptTagHelper"/>.
|
||||
/// </summary>
|
||||
/// <param name="hostingEnvironment">The <see cref="IHostingEnvironment"/>.</param>
|
||||
/// <param name="cacheProvider">The <see cref="TagHelperMemoryCacheProvider"/>.</param>
|
||||
/// <param name="htmlEncoder">The <see cref="HtmlEncoder"/>.</param>
|
||||
/// <param name="javaScriptEncoder">The <see cref="JavaScriptEncoder"/>.</param>
|
||||
/// <param name="urlHelperFactory">The <see cref="IUrlHelperFactory"/>.</param>
|
||||
// Decorated with ActivatorUtilitiesConstructor since we want to influence tag helper activation
|
||||
// to use this constructor in the default case.
|
||||
[ActivatorUtilitiesConstructor]
|
||||
public ScriptTagHelper(
|
||||
IHostingEnvironment hostingEnvironment,
|
||||
TagHelperMemoryCacheProvider cacheProvider,
|
||||
HtmlEncoder htmlEncoder,
|
||||
JavaScriptEncoder javaScriptEncoder,
|
||||
IUrlHelperFactory urlHelperFactory)
|
||||
: base(urlHelperFactory, htmlEncoder)
|
||||
{
|
||||
HostingEnvironment = hostingEnvironment;
|
||||
Cache = cacheProvider.Cache;
|
||||
JavaScriptEncoder = javaScriptEncoder;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override int Order => -1000;
|
||||
|
||||
|
|
@ -169,9 +197,9 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
[HtmlAttributeName(FallbackTestExpressionAttributeName)]
|
||||
public string FallbackTestExpression { get; set; }
|
||||
|
||||
protected IHostingEnvironment HostingEnvironment { get; }
|
||||
protected internal IHostingEnvironment HostingEnvironment { get; }
|
||||
|
||||
protected IMemoryCache Cache { get; }
|
||||
protected internal IMemoryCache Cache { get; private set; }
|
||||
|
||||
protected JavaScriptEncoder JavaScriptEncoder { get; }
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ using Microsoft.AspNetCore.Html;
|
|||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc.Abstractions;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.Infrastructure;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Microsoft.AspNetCore.Mvc.Routing;
|
||||
using Microsoft.AspNetCore.Mvc.ViewEngines;
|
||||
|
|
@ -73,7 +74,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
|
||||
var helper = new ImageTagHelper(
|
||||
hostingEnvironment,
|
||||
MakeCache(),
|
||||
new TagHelperMemoryCacheProvider(),
|
||||
new HtmlTestEncoder(),
|
||||
urlHelperFactory.Object)
|
||||
{
|
||||
|
|
@ -127,7 +128,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
|
||||
var helper = new ImageTagHelper(
|
||||
hostingEnvironment,
|
||||
MakeCache(),
|
||||
new TagHelperMemoryCacheProvider(),
|
||||
new HtmlTestEncoder(),
|
||||
MakeUrlHelperFactory())
|
||||
{
|
||||
|
|
@ -170,7 +171,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
var hostingEnvironment = MakeHostingEnvironment();
|
||||
var viewContext = MakeViewContext();
|
||||
|
||||
var helper = new ImageTagHelper(hostingEnvironment, MakeCache(), new HtmlTestEncoder(), MakeUrlHelperFactory())
|
||||
var helper = new ImageTagHelper(hostingEnvironment, new TagHelperMemoryCacheProvider(), new HtmlTestEncoder(), MakeUrlHelperFactory())
|
||||
{
|
||||
ViewContext = viewContext,
|
||||
Src = "/images/test-image.png",
|
||||
|
|
@ -206,7 +207,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
var hostingEnvironment = MakeHostingEnvironment();
|
||||
var viewContext = MakeViewContext();
|
||||
|
||||
var helper = new ImageTagHelper(hostingEnvironment, MakeCache(), new HtmlTestEncoder(), MakeUrlHelperFactory())
|
||||
var helper = new ImageTagHelper(hostingEnvironment, new TagHelperMemoryCacheProvider(), new HtmlTestEncoder(), MakeUrlHelperFactory())
|
||||
{
|
||||
ViewContext = viewContext,
|
||||
Src = "/images/test-image.png",
|
||||
|
|
@ -242,7 +243,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
var hostingEnvironment = MakeHostingEnvironment();
|
||||
var viewContext = MakeViewContext("/bar");
|
||||
|
||||
var helper = new ImageTagHelper(hostingEnvironment, MakeCache(), new HtmlTestEncoder(), MakeUrlHelperFactory())
|
||||
var helper = new ImageTagHelper(hostingEnvironment, new TagHelperMemoryCacheProvider(), new HtmlTestEncoder(), MakeUrlHelperFactory())
|
||||
{
|
||||
ViewContext = viewContext,
|
||||
Src = "/bar/images/image.jpg",
|
||||
|
|
@ -328,8 +329,6 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
return hostingEnvironment.Object;
|
||||
}
|
||||
|
||||
private static IMemoryCache MakeCache() => new MemoryCache(new MemoryCacheOptions());
|
||||
|
||||
private static IUrlHelperFactory MakeUrlHelperFactory()
|
||||
{
|
||||
var urlHelper = new Mock<IUrlHelper>();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,87 @@
|
|||
// 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 System.Text.Encodings.Web;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc.Internal;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.Infrastructure;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Microsoft.AspNetCore.Mvc.Routing;
|
||||
using Microsoft.AspNetCore.Mvc.TagHelpers;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Razor.Internal
|
||||
{
|
||||
// Tests to verify that script, link and image tag helper use the size limited instance of MemoryCache.
|
||||
public class DefaultTagHelperActivatorTest
|
||||
{
|
||||
private readonly TagHelperMemoryCacheProvider CacheProvider = new TagHelperMemoryCacheProvider();
|
||||
private readonly IMemoryCache MemoryCache = new MemoryCache(new MemoryCacheOptions());
|
||||
private readonly IHostingEnvironment HostingEnvironment = Mock.Of<IHostingEnvironment>();
|
||||
|
||||
[Fact]
|
||||
public void ScriptTagHelper_DoesNotUseMemoryCacheInstanceFromDI()
|
||||
{
|
||||
// Arrange
|
||||
var activator = new DefaultTagHelperActivator(new TypeActivatorCache());
|
||||
var viewContext = CreateViewContext();
|
||||
|
||||
var scriptTagHelper = activator.Create<ScriptTagHelper>(viewContext);
|
||||
|
||||
Assert.Same(CacheProvider.Cache, scriptTagHelper.Cache);
|
||||
Assert.Same(HostingEnvironment, scriptTagHelper.HostingEnvironment);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LinkTagHelper_DoesNotUseMemoryCacheInstanceFromDI()
|
||||
{
|
||||
// Arrange
|
||||
var activator = new DefaultTagHelperActivator(new TypeActivatorCache());
|
||||
var viewContext = CreateViewContext();
|
||||
|
||||
var linkTagHelper = activator.Create<LinkTagHelper>(viewContext);
|
||||
|
||||
Assert.Same(CacheProvider.Cache, linkTagHelper.Cache);
|
||||
Assert.Same(HostingEnvironment, linkTagHelper.HostingEnvironment);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ImageTagHelper_DoesNotUseMemoryCacheInstanceFromDI()
|
||||
{
|
||||
// Arrange
|
||||
var activator = new DefaultTagHelperActivator(new TypeActivatorCache());
|
||||
var viewContext = CreateViewContext();
|
||||
|
||||
var imageTagHelper = activator.Create<ImageTagHelper>(viewContext);
|
||||
|
||||
Assert.Same(CacheProvider.Cache, imageTagHelper.Cache);
|
||||
Assert.Same(HostingEnvironment, imageTagHelper.HostingEnvironment);
|
||||
}
|
||||
|
||||
private ViewContext CreateViewContext()
|
||||
{
|
||||
var services = new ServiceCollection()
|
||||
.AddSingleton(HostingEnvironment)
|
||||
.AddSingleton(MemoryCache)
|
||||
.AddSingleton(CacheProvider)
|
||||
.AddSingleton(HtmlEncoder.Default)
|
||||
.AddSingleton(JavaScriptEncoder.Default)
|
||||
.AddSingleton(Mock.Of<IUrlHelperFactory>())
|
||||
.BuildServiceProvider();
|
||||
|
||||
var viewContext = new ViewContext
|
||||
{
|
||||
HttpContext = new DefaultHttpContext
|
||||
{
|
||||
RequestServices = services,
|
||||
}
|
||||
};
|
||||
|
||||
return viewContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,7 +5,6 @@ using System.Collections.Generic;
|
|||
using System.IO;
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc.Razor;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
|
|
@ -267,29 +266,30 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Internal
|
|||
Assert.Equal("FromCache", result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("/hello/world", "/hello/world", null)]
|
||||
[InlineData("/testApp/hello/world", "/hello/world", "/testApp")]
|
||||
public void SetsValueInCache(string filePath, string watchPath, string requestPathBase)
|
||||
[Fact]
|
||||
public void AddFileVersionToPath_CachesEntry() => AddFileVersionToPath("/hello/world", "/hello/world", null);
|
||||
|
||||
[Fact]
|
||||
public void AddFileVersionToPath_WithRequestPathBase_CachesEntry() => AddFileVersionToPath("/testApp/hello/world", "/hello/world", "/testApp");
|
||||
|
||||
private static void AddFileVersionToPath(string filePath, string watchPath, string requestPathBase)
|
||||
{
|
||||
// Arrange
|
||||
var changeToken = new Mock<IChangeToken>();
|
||||
var expected = filePath + "?v=f4OxZX_x_FO5LcGBSKHWXfwtSx-j1ncoSt3SABJtkGk";
|
||||
var expectedSize = expected.Length * sizeof(char);
|
||||
var changeToken = Mock.Of<IChangeToken>();
|
||||
|
||||
var fileProvider = GetMockFileProvider(filePath, requestPathBase != null);
|
||||
Mock.Get(fileProvider)
|
||||
.Setup(f => f.Watch(watchPath)).Returns(changeToken.Object);
|
||||
.Setup(f => f.Watch(watchPath)).Returns(changeToken);
|
||||
|
||||
object cacheValue = null;
|
||||
var value = new Mock<ICacheEntry>();
|
||||
value.Setup(c => c.Value).Returns(cacheValue);
|
||||
value.Setup(c => c.ExpirationTokens).Returns(new List<IChangeToken>());
|
||||
var cacheEntry = Mock.Of<ICacheEntry>(c => c.ExpirationTokens == new List<IChangeToken>());
|
||||
var cache = new Mock<IMemoryCache>();
|
||||
cache.CallBase = true;
|
||||
cache.Setup(c => c.TryGetValue(It.IsAny<string>(), out cacheValue))
|
||||
.Returns(cacheValue != null);
|
||||
cache.Setup(c => c.CreateEntry(
|
||||
/*key*/ filePath))
|
||||
.Returns((object key) => value.Object)
|
||||
|
||||
cache.Setup(c => c.CreateEntry(filePath))
|
||||
.Returns(cacheEntry)
|
||||
.Verifiable();
|
||||
|
||||
var fileVersionProvider = new FileVersionProvider(
|
||||
fileProvider,
|
||||
cache.Object,
|
||||
|
|
@ -299,7 +299,9 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Internal
|
|||
var result = fileVersionProvider.AddFileVersionToPath(filePath);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(filePath + "?v=f4OxZX_x_FO5LcGBSKHWXfwtSx-j1ncoSt3SABJtkGk", result);
|
||||
Assert.Equal(expected, result);
|
||||
Assert.Equal(expected, cacheEntry.Value);
|
||||
Assert.Equal(expectedSize, cacheEntry.Size);
|
||||
cache.VerifyAll();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -411,6 +411,24 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Internal
|
|||
Assert.Collection(excludePatterns, pattern => Assert.Equal($"{prefix}**/*.min.css", pattern));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BuildUrlList_AddsToMemoryCache_WithSizeLimit()
|
||||
{
|
||||
// Arrange
|
||||
var cacheEntry = Mock.Of<ICacheEntry>(m => m.ExpirationTokens == new List<IChangeToken>());
|
||||
var cache = Mock.Of<IMemoryCache>(m => m.CreateEntry(It.IsAny<object>()) == cacheEntry);
|
||||
|
||||
var fileProvider = MakeFileProvider(MakeDirectoryContents("site.css", "blank.css"));
|
||||
var requestPathBase = PathString.Empty;
|
||||
var globbingUrlBuilder = new GlobbingUrlBuilder(fileProvider, cache, requestPathBase);
|
||||
|
||||
// Act
|
||||
var urlList = globbingUrlBuilder.BuildUrlList("/site.css", "**/*.css", excludePattern: null);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(38, cacheEntry.Size);
|
||||
}
|
||||
|
||||
public class FileNode
|
||||
{
|
||||
public FileNode(string name)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ using Microsoft.AspNetCore.Html;
|
|||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc.Abstractions;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.Infrastructure;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Microsoft.AspNetCore.Mvc.Routing;
|
||||
using Microsoft.AspNetCore.Mvc.TagHelpers.Internal;
|
||||
|
|
@ -70,7 +71,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
|
||||
var helper = new LinkTagHelper(
|
||||
hostingEnvironment,
|
||||
MakeCache(),
|
||||
new TagHelperMemoryCacheProvider(),
|
||||
new HtmlTestEncoder(),
|
||||
new JavaScriptTestEncoder(),
|
||||
urlHelperFactory.Object)
|
||||
|
|
@ -167,7 +168,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
|
||||
var helper = new LinkTagHelper(
|
||||
hostingEnvironment,
|
||||
MakeCache(),
|
||||
new TagHelperMemoryCacheProvider(),
|
||||
new HtmlTestEncoder(),
|
||||
new JavaScriptTestEncoder(),
|
||||
MakeUrlHelperFactory())
|
||||
|
|
@ -330,7 +331,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
|
||||
var helper = new LinkTagHelper(
|
||||
hostingEnvironment,
|
||||
MakeCache(),
|
||||
new TagHelperMemoryCacheProvider(),
|
||||
new HtmlTestEncoder(),
|
||||
new JavaScriptTestEncoder(),
|
||||
MakeUrlHelperFactory())
|
||||
|
|
@ -427,7 +428,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
|
||||
var helper = new LinkTagHelper(
|
||||
hostingEnvironment,
|
||||
MakeCache(),
|
||||
new TagHelperMemoryCacheProvider(),
|
||||
new HtmlTestEncoder(),
|
||||
new JavaScriptTestEncoder(),
|
||||
MakeUrlHelperFactory())
|
||||
|
|
@ -473,7 +474,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
|
||||
var helper = new LinkTagHelper(
|
||||
hostingEnvironment,
|
||||
MakeCache(),
|
||||
new TagHelperMemoryCacheProvider(),
|
||||
new HtmlTestEncoder(),
|
||||
new JavaScriptTestEncoder(),
|
||||
MakeUrlHelperFactory())
|
||||
|
|
@ -584,7 +585,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
|
||||
var helper = new LinkTagHelper(
|
||||
hostingEnvironment,
|
||||
MakeCache(),
|
||||
new TagHelperMemoryCacheProvider(),
|
||||
new HtmlTestEncoder(),
|
||||
new JavaScriptTestEncoder(),
|
||||
MakeUrlHelperFactory())
|
||||
|
|
@ -614,7 +615,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
|
||||
var helper = new LinkTagHelper(
|
||||
hostingEnvironment,
|
||||
MakeCache(),
|
||||
new TagHelperMemoryCacheProvider(),
|
||||
new HtmlTestEncoder(),
|
||||
new JavaScriptTestEncoder(),
|
||||
MakeUrlHelperFactory())
|
||||
|
|
@ -660,7 +661,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
|
||||
var helper = new LinkTagHelper(
|
||||
hostingEnvironment,
|
||||
MakeCache(),
|
||||
new TagHelperMemoryCacheProvider(),
|
||||
new HtmlTestEncoder(),
|
||||
new JavaScriptTestEncoder(),
|
||||
MakeUrlHelperFactory())
|
||||
|
|
@ -723,7 +724,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
|
||||
var helper = new LinkTagHelper(
|
||||
hostingEnvironment,
|
||||
MakeCache(),
|
||||
new TagHelperMemoryCacheProvider(),
|
||||
new HtmlTestEncoder(),
|
||||
new JavaScriptTestEncoder(),
|
||||
MakeUrlHelperFactory())
|
||||
|
|
@ -764,7 +765,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
|
||||
var helper = new LinkTagHelper(
|
||||
hostingEnvironment,
|
||||
MakeCache(),
|
||||
new TagHelperMemoryCacheProvider(),
|
||||
new HtmlTestEncoder(),
|
||||
new JavaScriptTestEncoder(),
|
||||
MakeUrlHelperFactory())
|
||||
|
|
@ -802,7 +803,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
|
||||
var helper = new LinkTagHelper(
|
||||
hostingEnvironment,
|
||||
MakeCache(),
|
||||
new TagHelperMemoryCacheProvider(),
|
||||
new HtmlTestEncoder(),
|
||||
new JavaScriptTestEncoder(),
|
||||
MakeUrlHelperFactory())
|
||||
|
|
@ -860,7 +861,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
|
||||
var helper = new LinkTagHelper(
|
||||
MakeHostingEnvironment(),
|
||||
MakeCache(),
|
||||
new TagHelperMemoryCacheProvider(),
|
||||
new HtmlTestEncoder(),
|
||||
new JavaScriptTestEncoder(),
|
||||
MakeUrlHelperFactory())
|
||||
|
|
@ -939,7 +940,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
|
||||
var helper = new LinkTagHelper(
|
||||
MakeHostingEnvironment(),
|
||||
MakeCache(),
|
||||
new TagHelperMemoryCacheProvider(),
|
||||
new HtmlTestEncoder(),
|
||||
new JavaScriptTestEncoder(),
|
||||
MakeUrlHelperFactory())
|
||||
|
|
@ -991,7 +992,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
|
||||
var helper = new LinkTagHelper(
|
||||
hostingEnvironment,
|
||||
MakeCache(),
|
||||
new TagHelperMemoryCacheProvider(),
|
||||
new HtmlTestEncoder(),
|
||||
new JavaScriptTestEncoder(),
|
||||
MakeUrlHelperFactory())
|
||||
|
|
@ -1084,8 +1085,6 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
return hostingEnvironment.Object;
|
||||
}
|
||||
|
||||
private static IMemoryCache MakeCache() => new MemoryCache(new MemoryCacheOptions());
|
||||
|
||||
private static IUrlHelperFactory MakeUrlHelperFactory()
|
||||
{
|
||||
var urlHelper = new Mock<IUrlHelper>();
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ using Microsoft.AspNetCore.Html;
|
|||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc.Abstractions;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.Infrastructure;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Microsoft.AspNetCore.Mvc.Routing;
|
||||
using Microsoft.AspNetCore.Mvc.TagHelpers.Internal;
|
||||
|
|
@ -71,7 +72,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
|
||||
var helper = new ScriptTagHelper(
|
||||
hostingEnvironment,
|
||||
MakeCache(),
|
||||
new TagHelperMemoryCacheProvider(),
|
||||
new HtmlTestEncoder(),
|
||||
new JavaScriptTestEncoder(),
|
||||
urlHelperFactory.Object)
|
||||
|
|
@ -118,7 +119,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
|
||||
var helper = new ScriptTagHelper(
|
||||
hostingEnvironment,
|
||||
MakeCache(),
|
||||
new TagHelperMemoryCacheProvider(),
|
||||
new HtmlTestEncoder(),
|
||||
new JavaScriptTestEncoder(),
|
||||
MakeUrlHelperFactory())
|
||||
|
|
@ -311,7 +312,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
|
||||
var helper = new ScriptTagHelper(
|
||||
hostingEnvironment,
|
||||
MakeCache(),
|
||||
new TagHelperMemoryCacheProvider(),
|
||||
new HtmlTestEncoder(),
|
||||
new JavaScriptTestEncoder(),
|
||||
MakeUrlHelperFactory())
|
||||
|
|
@ -408,7 +409,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
|
||||
var helper = new ScriptTagHelper(
|
||||
hostingEnvironment,
|
||||
MakeCache(),
|
||||
new TagHelperMemoryCacheProvider(),
|
||||
new HtmlTestEncoder(),
|
||||
new JavaScriptTestEncoder(),
|
||||
MakeUrlHelperFactory())
|
||||
|
|
@ -507,7 +508,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
|
||||
var helper = new ScriptTagHelper(
|
||||
hostingEnvironment,
|
||||
MakeCache(),
|
||||
new TagHelperMemoryCacheProvider(),
|
||||
new HtmlTestEncoder(),
|
||||
new JavaScriptTestEncoder(),
|
||||
MakeUrlHelperFactory())
|
||||
|
|
@ -536,7 +537,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
|
||||
var helper = new ScriptTagHelper(
|
||||
MakeHostingEnvironment(),
|
||||
MakeCache(),
|
||||
new TagHelperMemoryCacheProvider(),
|
||||
new HtmlTestEncoder(),
|
||||
new JavaScriptTestEncoder(),
|
||||
MakeUrlHelperFactory())
|
||||
|
|
@ -581,7 +582,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
|
||||
var helper = new ScriptTagHelper(
|
||||
hostingEnvironment,
|
||||
MakeCache(),
|
||||
new TagHelperMemoryCacheProvider(),
|
||||
new HtmlTestEncoder(),
|
||||
new JavaScriptTestEncoder(),
|
||||
MakeUrlHelperFactory())
|
||||
|
|
@ -625,7 +626,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
|
||||
var helper = new ScriptTagHelper(
|
||||
hostingEnvironment,
|
||||
MakeCache(),
|
||||
new TagHelperMemoryCacheProvider(),
|
||||
new HtmlTestEncoder(),
|
||||
new JavaScriptTestEncoder(),
|
||||
MakeUrlHelperFactory())
|
||||
|
|
@ -688,7 +689,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
|
||||
var helper = new ScriptTagHelper(
|
||||
hostingEnvironment,
|
||||
MakeCache(),
|
||||
new TagHelperMemoryCacheProvider(),
|
||||
new HtmlTestEncoder(),
|
||||
new JavaScriptTestEncoder(),
|
||||
MakeUrlHelperFactory())
|
||||
|
|
@ -726,7 +727,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
|
||||
var helper = new ScriptTagHelper(
|
||||
MakeHostingEnvironment(),
|
||||
MakeCache(),
|
||||
new TagHelperMemoryCacheProvider(),
|
||||
new HtmlTestEncoder(),
|
||||
new JavaScriptTestEncoder(),
|
||||
MakeUrlHelperFactory())
|
||||
|
|
@ -760,7 +761,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
|
||||
var helper = new ScriptTagHelper(
|
||||
MakeHostingEnvironment(),
|
||||
MakeCache(),
|
||||
new TagHelperMemoryCacheProvider(),
|
||||
new HtmlTestEncoder(),
|
||||
new JavaScriptTestEncoder(),
|
||||
MakeUrlHelperFactory())
|
||||
|
|
@ -796,7 +797,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
|
||||
var helper = new ScriptTagHelper(
|
||||
MakeHostingEnvironment(),
|
||||
MakeCache(),
|
||||
new TagHelperMemoryCacheProvider(),
|
||||
new HtmlTestEncoder(),
|
||||
new JavaScriptTestEncoder(),
|
||||
MakeUrlHelperFactory())
|
||||
|
|
@ -859,7 +860,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
|
||||
var helper = new ScriptTagHelper(
|
||||
MakeHostingEnvironment(),
|
||||
MakeCache(),
|
||||
new TagHelperMemoryCacheProvider(),
|
||||
new HtmlTestEncoder(),
|
||||
new JavaScriptTestEncoder(),
|
||||
MakeUrlHelperFactory())
|
||||
|
|
@ -907,7 +908,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
|
||||
var helper = new ScriptTagHelper(
|
||||
MakeHostingEnvironment(),
|
||||
MakeCache(),
|
||||
new TagHelperMemoryCacheProvider(),
|
||||
new HtmlTestEncoder(),
|
||||
new JavaScriptTestEncoder(),
|
||||
MakeUrlHelperFactory())
|
||||
|
|
@ -997,8 +998,6 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
return hostingEnvironment.Object;
|
||||
}
|
||||
|
||||
private static IMemoryCache MakeCache() => new MemoryCache(new MemoryCacheOptions());
|
||||
|
||||
private static IUrlHelperFactory MakeUrlHelperFactory()
|
||||
{
|
||||
var urlHelper = new Mock<IUrlHelper>();
|
||||
|
|
|
|||
Loading…
Reference in New Issue