in src/OrchardCore/OrchardCore.ContentManagement.Display/ContentDisplay/ContentItemDisplayCoordinator.cs [63:217]
public async Task BuildDisplayAsync(ContentItem contentItem, BuildDisplayContext context)
{
var contentTypeDefinition = _contentDefinitionManager.GetTypeDefinition(contentItem.ContentType);
if (contentTypeDefinition == null)
{
return;
}
foreach (var displayDriver in _displayDrivers)
{
try
{
var result = await displayDriver.BuildDisplayAsync(contentItem, context);
if (result != null)
{
await result.ApplyAsync(context);
}
}
catch (Exception ex)
{
InvokeExtensions.HandleException(ex, _logger, displayDriver.GetType().Name, nameof(BuildDisplayAsync));
}
}
foreach (var contentTypePartDefinition in contentTypeDefinition.Parts)
{
var partName = contentTypePartDefinition.Name;
var partTypeName = contentTypePartDefinition.PartDefinition.Name;
var contentType = contentTypePartDefinition.ContentTypeDefinition.Name;
var partActivator = _contentPartFactory.GetTypeActivator(partTypeName);
var part = contentItem.Get(partActivator.Type, partName) as ContentPart;
if (part != null)
{
var partDisplayDrivers = _contentPartDisplayDriverResolver.GetDisplayModeDrivers(partTypeName, contentTypePartDefinition.DisplayMode());
foreach (var partDisplayDriver in partDisplayDrivers)
{
try
{
var result = await partDisplayDriver.BuildDisplayAsync(part, contentTypePartDefinition, context);
if (result != null)
{
await result.ApplyAsync(context);
}
}
catch (Exception ex)
{
InvokeExtensions.HandleException(ex, _logger, partDisplayDrivers.GetType().Name, nameof(BuildDisplayAsync));
}
}
// TODO: This can be removed in a future release as the recommended way is to use ContentOptions.
// Iterate existing driver registrations as multiple drivers maybe not be registered with ContentOptions.
foreach (var displayDriver in _partDisplayDrivers)
{
try
{
var result = await displayDriver.BuildDisplayAsync(part, contentTypePartDefinition, context);
if (result != null)
{
await result.ApplyAsync(context);
}
}
catch (Exception ex)
{
InvokeExtensions.HandleException(ex, _logger, displayDriver.GetType().Name, nameof(BuildDisplayAsync));
}
}
var tempContext = context;
// Create a custom ContentPart shape that will hold the fields for dynamic content part (not implicit parts)
// This allows its fields to be grouped and templated
if (part.GetType() == typeof(ContentPart) && partTypeName != contentTypePartDefinition.ContentTypeDefinition.Name)
{
var shapeType = context.DisplayType != "Detail" ? "ContentPart_" + context.DisplayType : "ContentPart";
var shapeResult = new ShapeResult(shapeType, ctx => ctx.ShapeFactory.CreateAsync(shapeType, () => new ValueTask<IShape>(new ZoneHolding(() => ctx.ShapeFactory.CreateAsync("Zone")))));
shapeResult.Differentiator(partName);
shapeResult.Location("Content");
await shapeResult.ApplyAsync(context);
var contentPartShape = shapeResult.Shape;
// Make the ContentPart name property available on the shape
dynamic dynamicContentPartShape = contentPartShape;
dynamicContentPartShape[partTypeName] = part.Content;
dynamicContentPartShape["ContentItem"] = part.ContentItem;
contentPartShape.Metadata.Alternates.Add(partTypeName);
contentPartShape.Metadata.Alternates.Add($"{contentType}__{partTypeName}");
if (context.DisplayType != "Detail")
{
contentPartShape.Metadata.Alternates.Add($"{partTypeName}_{context.DisplayType}");
contentPartShape.Metadata.Alternates.Add($"{contentType}_{context.DisplayType}__{partTypeName}");
}
if (partName != partTypeName)
{
contentPartShape.Metadata.Alternates.Add($"{contentType}__{partName}");
if (context.DisplayType != "Detail")
{
contentPartShape.Metadata.Alternates.Add($"{contentType}_{context.DisplayType}__{partName}");
}
}
context = new BuildDisplayContext(shapeResult.Shape, context.DisplayType, context.GroupId, context.ShapeFactory, context.Layout, context.Updater);
// With a new display context we have the default FindPlacementDelegate that returns null, so we reuse the delegate from the temp context.
context.FindPlacement = tempContext.FindPlacement;
}
foreach (var contentPartFieldDefinition in contentTypePartDefinition.PartDefinition.Fields)
{
var fieldDisplayDrivers = _contentFieldDisplayDriverResolver.GetDisplayModeDrivers(contentPartFieldDefinition.FieldDefinition.Name, contentPartFieldDefinition.DisplayMode());
foreach (var fieldDisplayDriver in fieldDisplayDrivers)
{
try
{
var result = await fieldDisplayDriver.BuildDisplayAsync(part, contentPartFieldDefinition, contentTypePartDefinition, context);
if (result != null)
{
await result.ApplyAsync(context);
}
}
catch (Exception ex)
{
InvokeExtensions.HandleException(ex, _logger, fieldDisplayDriver.GetType().Name, nameof(BuildDisplayAsync));
}
}
// TODO: This can be removed in a future release as the recommended way is to use ContentOptions.
// Iterate existing driver registrations as multiple drivers maybe not be registered with ContentOptions.
foreach (var displayDriver in _fieldDisplayDrivers)
{
try
{
var result = await displayDriver.BuildDisplayAsync(part, contentPartFieldDefinition, contentTypePartDefinition, context);
if (result != null)
{
await result.ApplyAsync(context);
}
}
catch (Exception ex)
{
InvokeExtensions.HandleException(ex, _logger, displayDriver.GetType().Name, nameof(BuildDisplayAsync));
}
}
}
context = tempContext;
}
}
}