public async Task <IHtmlContent> ExecuteAsync(DisplayContext context)
        {
            var shape = context.Value as IShape;

            // non-shape arguments are returned as a no-op
            if (shape == null)
            {
                return(CoerceHtmlString(context.Value));
            }

            var shapeMetadata = shape.Metadata;

            // can't really cope with a shape that has no type information
            if (shapeMetadata == null || string.IsNullOrEmpty(shapeMetadata.Type))
            {
                return(CoerceHtmlString(context.Value));
            }

            var displayContext = new ShapeDisplayContext
            {
                Shape           = shape,
                ShapeMetadata   = shapeMetadata,
                DisplayContext  = context,
                ServiceProvider = _serviceProvider
            };

            try
            {
                var theme = await _themeManager.GetThemeAsync();

                var shapeTable = _shapeTableManager.GetShapeTable(theme?.Id);

                // Use the same prefix as the shape
                var originalHtmlFieldPrefix = context.ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix;
                context.ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix = shapeMetadata.Prefix ?? "";

                // Evaluate global Shape Display Events
                await _shapeDisplayEvents.InvokeAsync(sde => sde.DisplayingAsync(displayContext), _logger);

                // Find base shape association using only the fundamental shape type.
                // Alternates that may already be registered do not affect the "displaying" event calls.
                ShapeBinding shapeBinding;
                if (TryGetDescriptorBinding(shapeMetadata.Type, Enumerable.Empty <string>(), shapeTable, out shapeBinding))
                {
                    await shapeBinding.ShapeDescriptor.DisplayingAsync.InvokeAsync(action => action(displayContext), _logger);

                    // copy all binding sources (all templates for this shape) in order to use them as Localization scopes
                    shapeMetadata.BindingSources = shapeBinding.ShapeDescriptor.BindingSources.Where(x => x != null).ToList();
                    if (!shapeMetadata.BindingSources.Any())
                    {
                        shapeMetadata.BindingSources.Add(shapeBinding.ShapeDescriptor.BindingSource);
                    }
                }

                // invoking ShapeMetadata displaying events
                shapeMetadata.Displaying.Invoke(action => action(displayContext), _logger);

                // use pre-fectched content if available (e.g. coming from specific cache implementation)
                if (displayContext.ChildContent != null)
                {
                    shape.Metadata.ChildContent = displayContext.ChildContent;
                }

                if (shape.Metadata.ChildContent == null)
                {
                    // There might be no shape binding for the main shape, and only for its alternates.
                    if (shapeBinding != null)
                    {
                        await shapeBinding.ShapeDescriptor.ProcessingAsync.InvokeAsync(action => action(displayContext), _logger);
                    }

                    // now find the actual binding to render, taking alternates into account
                    ShapeBinding actualBinding;
                    if (TryGetDescriptorBinding(shapeMetadata.Type, shapeMetadata.Alternates, shapeTable, out actualBinding))
                    {
                        // invoking ShapeMetadata processing events, this includes the Drivers results
                        await shapeMetadata.ProcessingAsync.InvokeAsync(processing => processing(displayContext.Shape), _logger);

                        shape.Metadata.ChildContent = await ProcessAsync(actualBinding, shape, context);
                    }
                    else
                    {
                        throw new Exception($"Shape type '{shapeMetadata.Type}' not found");
                    }
                }

                // Process wrappers
                if (shape.Metadata.Wrappers.Count > 0)
                {
                    foreach (var frameType in shape.Metadata.Wrappers)
                    {
                        ShapeBinding frameBinding;
                        if (TryGetDescriptorBinding(frameType, Enumerable.Empty <string>(), shapeTable, out frameBinding))
                        {
                            shape.Metadata.ChildContent = await ProcessAsync(frameBinding, shape, context);
                        }
                    }

                    // Clear wrappers to prevent the child content from rendering them again
                    shape.Metadata.Wrappers.Clear();
                }

                await _shapeDisplayEvents.InvokeAsync(async sde =>
                {
                    var prior = displayContext.ChildContent = displayContext.ShapeMetadata.ChildContent;
                    await sde.DisplayedAsync(displayContext);
                    // update the child content if the context variable has been reassigned
                    if (prior != displayContext.ChildContent)
                    {
                        displayContext.ShapeMetadata.ChildContent = displayContext.ChildContent;
                    }
                }, _logger);

                if (shapeBinding != null)
                {
                    await shapeBinding.ShapeDescriptor.DisplayedAsync.InvokeAsync(async action =>
                    {
                        var prior = displayContext.ChildContent = displayContext.ShapeMetadata.ChildContent;

                        await action(displayContext);

                        // update the child content if the context variable has been reassigned
                        if (prior != displayContext.ChildContent)
                        {
                            displayContext.ShapeMetadata.ChildContent = displayContext.ChildContent;
                        }
                    }, _logger);
                }

                // invoking ShapeMetadata displayed events
                shapeMetadata.Displayed.Invoke(action => action(displayContext), _logger);

                //restore original HtmlFieldPrefix
                context.ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix = originalHtmlFieldPrefix;
            }
            finally
            {
                await _shapeDisplayEvents.InvokeAsync(sde => sde.DisplayingFinalizedAsync(displayContext), _logger);
            }

            return(shape.Metadata.ChildContent);
        }
예제 #2
0
        public async Task <IHtmlContent> ExecuteAsync(DisplayContext context)
        {
            var shape = context.Value as IShape;

            // non-shape arguments are returned as a no-op
            if (shape == null)
            {
                return(CoerceHtmlString(context.Value));
            }

            var shapeMetadata = shape.Metadata;

            // can't really cope with a shape that has no type information
            if (shapeMetadata == null || string.IsNullOrEmpty(shapeMetadata.Type))
            {
                return(CoerceHtmlString(context.Value));
            }

            // Copy the current context such that the rendering can customize it if necessary
            // For instance to change the HtmlFieldPrefix
            var localContext = new DisplayContext(context);

            localContext.HtmlFieldPrefix = shapeMetadata.Prefix ?? "";

            var displayContext = new ShapeDisplayContext
            {
                Shape           = shape,
                DisplayContext  = localContext,
                ServiceProvider = _serviceProvider
            };

            try
            {
                var theme = await _themeManager.GetThemeAsync();

                var shapeTable = _shapeTableManager.GetShapeTable(theme?.Id);

                // Evaluate global Shape Display Events
                await _shapeDisplayEvents.InvokeAsync((e, displayContext) => e.DisplayingAsync(displayContext), displayContext, _logger);

                // Find base shape association using only the fundamental shape type.
                // Alternates that may already be registered do not affect the "displaying" event calls.
                var shapeDescriptor = GetShapeDescriptor(shapeMetadata.Type, shapeTable);
                if (shapeDescriptor != null)
                {
                    await shapeDescriptor.DisplayingAsync.InvokeAsync((action, displayContext) => action(displayContext), displayContext, _logger);

                    // copy all binding sources (all templates for this shape) in order to use them as Localization scopes
                    shapeMetadata.BindingSources = shapeDescriptor.BindingSources.Where(x => x != null).ToList();
                    if (!shapeMetadata.BindingSources.Any())
                    {
                        shapeMetadata.BindingSources.Add(shapeDescriptor.BindingSource);
                    }
                }

                // invoking ShapeMetadata displaying events
                shapeMetadata.Displaying.Invoke(action => action(displayContext), _logger);

                // use pre-fetched content if available (e.g. coming from specific cache implementation)
                if (displayContext.ChildContent != null)
                {
                    shape.Metadata.ChildContent = displayContext.ChildContent;
                }

                if (shape.Metadata.ChildContent == null)
                {
                    // There might be no shape binding for the main shape, and only for its alternates.
                    if (shapeDescriptor != null)
                    {
                        await shapeDescriptor.ProcessingAsync.InvokeAsync((action, displayContext) => action(displayContext), displayContext, _logger);
                    }

                    // now find the actual binding to render, taking alternates into account
                    var actualBinding = await GetShapeBindingAsync(shapeMetadata.Type, shapeMetadata.Alternates, shapeTable);

                    if (actualBinding != null)
                    {
                        await shapeMetadata.ProcessingAsync.InvokeAsync((action, displayContext) => action(displayContext.Shape), displayContext, _logger);

                        shape.Metadata.ChildContent = await ProcessAsync(actualBinding, shape, localContext);
                    }
                    else
                    {
                        throw new Exception($"Shape type '{shapeMetadata.Type}' not found");
                    }
                }

                // Process wrappers
                if (shape.Metadata.Wrappers.Count > 0)
                {
                    foreach (var frameType in shape.Metadata.Wrappers)
                    {
                        var frameBinding = await GetShapeBindingAsync(frameType, AlternatesCollection.Empty, shapeTable);

                        if (frameBinding != null)
                        {
                            shape.Metadata.ChildContent = await ProcessAsync(frameBinding, shape, localContext);
                        }
                    }

                    // Clear wrappers to prevent the child content from rendering them again
                    shape.Metadata.Wrappers.Clear();
                }

                await _shapeDisplayEvents.InvokeAsync(async (e, displayContext) =>
                {
                    var prior = displayContext.ChildContent = displayContext.Shape.Metadata.ChildContent;

                    await e.DisplayedAsync(displayContext);

                    // update the child content if the context variable has been reassigned
                    if (prior != displayContext.ChildContent)
                    {
                        displayContext.Shape.Metadata.ChildContent = displayContext.ChildContent;
                    }
                }, displayContext, _logger);

                if (shapeDescriptor != null)
                {
                    await shapeDescriptor.DisplayedAsync.InvokeAsync(async (action, displayContext) =>
                    {
                        var prior = displayContext.ChildContent = displayContext.Shape.Metadata.ChildContent;

                        await action(displayContext);

                        // update the child content if the context variable has been reassigned
                        if (prior != displayContext.ChildContent)
                        {
                            displayContext.Shape.Metadata.ChildContent = displayContext.ChildContent;
                        }
                    }, displayContext, _logger);
                }

                // invoking ShapeMetadata displayed events
                shapeMetadata.Displayed.Invoke((action, displayContext) => action(displayContext), displayContext, _logger);
            }
            finally
            {
                await _shapeDisplayEvents.InvokeAsync((e, displayContext) => e.DisplayingFinalizedAsync(displayContext), displayContext, _logger);
            }

            return(shape.Metadata.ChildContent);
        }