public override async ValueTask <FluidValue> EvaluateAsync(TemplateContext context) { var arguments = new FilterArguments(); foreach (var argument in _arguments) { arguments.Add(argument.Name, await argument.Expression.EvaluateAsync(context)); } return(FluidValue.Create(arguments)); }
public override async Task <FluidValue> EvaluateAsync(TemplateContext context) { var arguments = new FilterArguments(); foreach (var parameter in _parameters) { arguments.Add(parameter.Name, await parameter.Expression.EvaluateAsync(context)); } var input = await Input.EvaluateAsync(context); if (!context.Filters.TryGetValue(_name, out AsyncFilterDelegate filter) && !TemplateContext.GlobalFilters.TryGetValue(_name, out filter)) { // When a filter is not defined, return the input return(input); } return(await filter(input, arguments, context)); }
public override async ValueTask <FluidValue> EvaluateAsync(TemplateContext context) { FilterArguments arguments; // The arguments can be cached if all the parameters are LiteralExpression if (_cachedArguments == null) { arguments = new FilterArguments(); foreach (var parameter in Parameters) { _canBeCached = _canBeCached && parameter.Expression is LiteralExpression; arguments.Add(parameter.Name, await parameter.Expression.EvaluateAsync(context)); } // Can we cache it? if (_canBeCached) { _cachedArguments = arguments; } } else { arguments = _cachedArguments; } var input = await Input.EvaluateAsync(context); if (!context.Filters.TryGetValue(Name, out AsyncFilterDelegate filter) && !TemplateContext.GlobalFilters.TryGetValue(Name, out filter)) { // When a filter is not defined, return the input return(input); } return(await filter(input, arguments, context)); }
public static async ValueTask <Completion> WriteToAsync(List <FilterArgument> arguments, IReadOnlyList <Statement> statements, TextWriter writer, TextEncoder encoder, TemplateContext context) { var services = ((LiquidTemplateContext)context).Services; var dynamicCache = services.GetService <IDynamicCacheService>(); var cacheScopeManager = services.GetService <ICacheScopeManager>(); var loggerFactory = services.GetService <ILoggerFactory>(); var logger = loggerFactory.CreateLogger <CacheTag>(); var cacheOptions = services.GetRequiredService <IOptions <CacheOptions> >().Value; if (dynamicCache == null || cacheScopeManager == null) { logger.LogInformation(@"Liquid cache block entered without an available IDynamicCacheService or ICacheScopeManager. The contents of the cache block will not be cached. To enable caching, make sure that a feature that contains an implementation of IDynamicCacheService and ICacheScopeManager is enabled (for example, 'Dynamic Cache')."); if (statements != null && statements.Count > 0) { var completion = await statements.RenderStatementsAsync(writer, encoder, context); if (completion != Completion.Normal) { return(completion); } } return(Completion.Normal); } var filterArguments = new FilterArguments(); foreach (var argument in arguments) { filterArguments.Add(argument.Name, await argument.Expression.EvaluateAsync(context)); } var cacheKey = filterArguments.At(0).ToStringValue(); var contexts = filterArguments["vary_by"].ToStringValue(); var tags = filterArguments["dependencies"].ToStringValue(); var durationString = filterArguments["expires_after"].ToStringValue(); var slidingDurationString = filterArguments["expires_sliding"].ToStringValue(); var cacheContext = new CacheContext(cacheKey) .AddContext(contexts.Split(SplitChars, StringSplitOptions.RemoveEmptyEntries)) .AddTag(tags.Split(SplitChars, StringSplitOptions.RemoveEmptyEntries)); if (TimeSpan.TryParse(durationString, out var duration)) { cacheContext.WithExpiryAfter(duration); } if (TimeSpan.TryParse(slidingDurationString, out var slidingDuration)) { cacheContext.WithExpirySliding(slidingDuration); } var cacheResult = await dynamicCache.GetCachedValueAsync(cacheContext); if (cacheResult != null) { await writer.WriteAsync(cacheResult); return(Completion.Normal); } cacheScopeManager.EnterScope(cacheContext); var content = ""; try { if (statements != null && statements.Count > 0) { using var sb = StringBuilderPool.GetInstance(); using (var render = new StringWriter(sb.Builder)) { foreach (var statement in statements) { await statement.WriteToAsync(render, encoder, context); } await render.FlushAsync(); } content = sb.Builder.ToString(); } } finally { cacheScopeManager.ExitScope(); } if (cacheOptions.DebugMode) { // No need to optimize this code as it will be used for debugging purpose. var debugContent = new StringWriter(); debugContent.WriteLine(); debugContent.WriteLine($"<!-- CACHE BLOCK: {cacheContext.CacheId} ({Guid.NewGuid()})"); debugContent.WriteLine($" VARY BY: {String.Join(", ", cacheContext.Contexts)}"); debugContent.WriteLine($" DEPENDENCIES: {String.Join(", ", cacheContext.Tags)}"); debugContent.WriteLine($" EXPIRES ON: {cacheContext.ExpiresOn}"); debugContent.WriteLine($" EXPIRES AFTER: {cacheContext.ExpiresAfter}"); debugContent.WriteLine($" EXPIRES SLIDING: {cacheContext.ExpiresSliding}"); debugContent.WriteLine("-->"); debugContent.WriteLine(content); debugContent.WriteLine(); debugContent.WriteLine($"<!-- END CACHE BLOCK: {cacheContext.CacheId} -->"); content = debugContent.ToString(); } await dynamicCache.SetCachedValueAsync(cacheContext, content); await writer.WriteAsync(content); return(Completion.Normal); }
public static async ValueTask <Completion> WriteToAsync(string identifier, List <FilterArgument> arguments, IReadOnlyList <Statement> statements, TextWriter writer, TextEncoder encoder, TemplateContext context) { var services = ((LiquidTemplateContext)context).Services; var viewContextAccessor = services.GetRequiredService <ViewContextAccessor>(); var viewContext = viewContextAccessor.ViewContext; // If no identifier is set, use the first argument as the name of the tag helper // e.g., {% helper "input", for: "Text", class: "form-control" %} identifier ??= (await arguments[0].Expression.EvaluateAsync(context)).ToStringValue(); // These mapping will assign an argument name to the first element in the filter arguments, // such that the tag helper can be matched based on the expected attribute names. if (DefaultArgumentsMapping.TryGetValue(identifier, out var mapping)) { arguments = new List <FilterArgument>(arguments); arguments[0] = new FilterArgument(mapping, arguments[0].Expression); } var filterArguments = new FilterArguments(); foreach (var argument in arguments) { filterArguments.Add(argument.Name, await argument.Expression.EvaluateAsync(context)); } var factory = services.GetRequiredService <LiquidTagHelperFactory>(); var activator = factory.GetActivator(identifier, filterArguments.Names); if (activator == LiquidTagHelperActivator.None) { return(Completion.Normal); } var tagHelper = factory.CreateTagHelper(activator, viewContext, filterArguments, out var contextAttributes, out var outputAttributes); ViewBufferTextWriterContent content = null; if (statements != null && statements.Count > 0) { content = new ViewBufferTextWriterContent(); var completion = await statements.RenderStatementsAsync(content, encoder, context); if (completion != Completion.Normal) { return(completion); } } Interlocked.CompareExchange(ref _uniqueId, long.MaxValue, 0); var id = Interlocked.Increment(ref _uniqueId); var tagHelperContext = new TagHelperContext(contextAttributes, new Dictionary <object, object>(), id.ToString()); TagHelperOutput tagHelperOutput = null; if (content != null) { tagHelperOutput = new TagHelperOutput( identifier, outputAttributes, (_, e) => Task.FromResult(new DefaultTagHelperContent().AppendHtml(content)) ); } else { tagHelperOutput = new TagHelperOutput( identifier, outputAttributes, (_, e) => Task.FromResult <TagHelperContent>(new DefaultTagHelperContent()) ); } await tagHelper.ProcessAsync(tagHelperContext, tagHelperOutput); return(Completion.Normal); }