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); }
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); }