Beispiel #1
0
        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));
        }
Beispiel #2
0
        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));
        }
Beispiel #3
0
        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));
        }
Beispiel #4
0
        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);
        }
Beispiel #5
0
        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);
        }