/// <summary> /// Builds a strongly typed Entity Model based on a given DXA R2 Data Model. /// </summary> /// <param name="entityModel">The strongly typed Entity Model to build. Is <c>null</c> for the first Entity Model Builder in the pipeline.</param> /// <param name="entityModelData">The DXA R2 Data Model.</param> /// <param name="baseModelType">The base type for the Entity Model to build.</param> /// <param name="localization">The context <see cref="ILocalization"/>.</param> public virtual void BuildEntityModel(ref EntityModel entityModel, EntityModelData entityModelData, Type baseModelType, ILocalization localization) { using (new Tracer(entityModel, entityModelData, baseModelType, localization)) { MvcData mvcData = CreateMvcData(entityModelData.MvcData, "Entity"); SemanticSchema semanticSchema = SemanticMapping.GetSchema(entityModelData.SchemaId, localization); Type modelType = (baseModelType == null) ? ModelTypeRegistry.GetViewModelType(mvcData) : semanticSchema.GetModelTypeFromSemanticMapping(baseModelType); MappingData mappingData = new MappingData { SourceViewModel = entityModelData, ModelType = modelType, PropertyValidation = new Validation { MainSchema = semanticSchema, InheritedSchemas = GetInheritedSemanticSchemas(entityModelData, localization) }, Fields = entityModelData.Content, MetadataFields = entityModelData.Metadata, Localization = localization }; entityModel = (EntityModel)CreateViewModel(mappingData); entityModel.Id = entityModelData.Id; entityModel.MvcData = mvcData ?? entityModel.GetDefaultView(localization); } }
/// <summary> /// Generates semantic markup (HTML/RDFa attributes) for a given property of a given Entity Model. /// </summary> /// <param name="entityModel">The Entity Model which contains the property.</param> /// <param name="propertyInfo">The reflected property info.</param> /// <param name="index">The index of the property value (for multi-value properties).</param> /// <returns>The semantic markup (HTML/RDFa attributes).</returns> internal static MvcHtmlString RenderPropertyAttributes(EntityModel entityModel, MemberInfo propertyInfo, int index = 0) { string markup = string.Empty; string propertyName = propertyInfo.Name; string[] semanticPropertyNames = ModelTypeRegistry.GetSemanticPropertyNames(propertyInfo.DeclaringType, propertyName); if (semanticPropertyNames != null && semanticPropertyNames.Any()) { markup = $"property=\"{string.Join(" ", semanticPropertyNames)}\""; } if (WebRequestContext.IsPreview) { string xpmMarkupAttr = RenderXpmMarkupAttribute(entityModel, propertyName, index); if (string.IsNullOrEmpty(markup)) { markup = xpmMarkupAttr; } else { markup += " " + xpmMarkupAttr; } } return(new MvcHtmlString(markup)); }
/// <summary> /// Registers a View Model and associated View. /// </summary> /// <param name="viewName">The name of the View to register.</param> /// <param name="modelType">The View Model Type to associate with the View. Must be a subclass of Type <see cref="ViewModel"/>.</param> /// <param name="controllerName">The Controller name. If not specified (or <c>null</c>), the Controller name is inferred from the <see cref="modelType"/>: either "Entity", "Region" or "Page".</param> private static void RegisterViewModel(string viewName, Type modelType, string controllerName = null) { if (String.IsNullOrEmpty(controllerName)) { if (typeof(EntityModel).IsAssignableFrom(modelType)) { controllerName = "Entity"; } else if (typeof(RegionModel).IsAssignableFrom(modelType)) { controllerName = "Region"; } else { controllerName = "Page"; } } MvcData mvcData = new MvcData(viewName) { ControllerName = controllerName }; ModelTypeRegistry.RegisterViewModel(mvcData, modelType); }
/// <summary> /// Registers this View Model Type. /// </summary> /// <remarks> /// Although this View Model Type is part of the DXA Framework, it has to be registered like any other View Model Type. /// In order to work with Tridion Docs content, it will be associated with specific MVC data. /// A DXA Web Application/Module that wants to work with Tridion Docs content should call this method /// unless it defines its own View Model Type for generic Topics. /// </remarks> public static void Register() { using (new Tracer()) { ModelTypeRegistry.RegisterViewModel(new MvcData("Ish:Entity:Topic"), typeof(GenericTopic)); } }
/// <summary> /// Generates semantic markup (HTML/RDFa attributes) for a given Entity Model. /// </summary> /// <param name="entityModel">The Entity Model.</param> /// <returns>The semantic markup (HTML/RDFa attributes).</returns> internal static MvcHtmlString RenderEntityAttributes(EntityModel entityModel) { string markup = string.Empty; IDictionary <string, string> prefixMappings; string[] semanticTypes = ModelTypeRegistry.GetSemanticTypes(entityModel.GetType(), out prefixMappings); if (semanticTypes.Any()) { markup = $"prefix=\"{string.Join(" ", prefixMappings.Select(pm => $"{pm.Key}: {pm.Value}"))}\" typeof=\"{string.Join(" ", semanticTypes)}\""; } if (WebRequestContext.IsPreview) { string xpmMarkupAttr = RenderXpmMarkupAttribute(entityModel); if (string.IsNullOrEmpty(markup)) { markup = xpmMarkupAttr; } else { markup += " " + xpmMarkupAttr; } } return(new MvcHtmlString(markup)); }
/// <summary> /// Determine a Model Type based on semantic mappings (and a given base model type). /// </summary> /// <param name="baseModelType">The base type as obtained from the View Model.</param> /// <returns>The given base Model Type or a subclass if a more specific class can be resolved via semantic mapping.</returns> /// <remarks> /// This method makes it possible (for example) to let the <see cref="Teaser.Media"/> property get an instance of <see cref="Image"/> /// rather than just <see cref="MediaItem"/> (the type of the View Model property). /// </remarks> public Type GetModelTypeFromSemanticMapping(Type baseModelType) { Type[] foundAmbiguousMappings = null; string[] semanticTypeNames = GetSemanticTypeNames(); foreach (string semanticTypeName in semanticTypeNames) { IEnumerable <Type> mappedModelTypes = ModelTypeRegistry.GetMappedModelTypes(semanticTypeName); if (mappedModelTypes == null) { continue; } Type[] matchingModelTypes = mappedModelTypes.Where(t => baseModelType.IsAssignableFrom(t)).ToArray(); if (matchingModelTypes.Length == 1) { // Exactly one matching model type; return it. return(matchingModelTypes[0]); } if (matchingModelTypes.Length > 1) { // Multiple candidate models types found. Continue scanning; maybe we'll find a unique one for another semantic type. foundAmbiguousMappings = matchingModelTypes; } } string errorMessage; if (foundAmbiguousMappings == null) { errorMessage = $"No semantic mapping found between Schema {Id} ({String.Join(", ", semanticTypeNames)}) and model type '{baseModelType.FullName}'"; } else { errorMessage = $"Ambiguous semantic mappings found between Schema {Id} ({String.Join(", ", semanticTypeNames)}) and model type '{String.Join(", ", foundAmbiguousMappings.Select(t => t.FullName))}'. Found types: {baseModelType.FullName}"; } if (baseModelType.IsAbstract) { // Base model type is abstract and we didn't find an (unambigous) concrete subtype to instantiate. throw new DxaException(errorMessage); } // Base model type is concrete, so we can fall back to instantiating that type. if (foundAmbiguousMappings == null) { Log.Debug("{0}. Sticking with model type.", errorMessage); } else { Log.Warn("{0}. Sticking with model type.", errorMessage); } return(baseModelType); }
/// <summary> /// Builds a strongly typed Page Model from a given DXA R2 Data Model. /// </summary> /// <param name="pageModel">The strongly typed Page Model to build. Is <c>null</c> for the first Page Model Builder in the pipeline.</param> /// <param name="pageModelData">The DXA R2 Data Model.</param> /// <param name="includePageRegions">Indicates whether Include Page Regions should be included.</param> /// <param name="localization">The context <see cref="ILocalization"/>.</param> public virtual void BuildPageModel(ref PageModel pageModel, PageModelData pageModelData, bool includePageRegions, ILocalization localization) { using (new Tracer(pageModel, pageModelData, includePageRegions, localization)) { MvcData mvcData = CreateMvcData(pageModelData.MvcData, "Page"); Type modelType = ModelTypeRegistry.GetViewModelType(mvcData); if (modelType == typeof(PageModel)) { // Standard Page Model. pageModel = new PageModel(pageModelData.Id) { ExtensionData = pageModelData.ExtensionData, HtmlClasses = pageModelData.HtmlClasses, XpmMetadata = localization.IsXpmEnabled ? pageModelData.XpmMetadata : null, }; } else if (pageModelData.SchemaId == null) { // Custom Page Model, but no custom metadata. pageModel = (PageModel)modelType.CreateInstance(pageModelData.Id); pageModel.ExtensionData = pageModelData.ExtensionData; pageModel.HtmlClasses = pageModelData.HtmlClasses; pageModel.XpmMetadata = localization.IsXpmEnabled ? pageModelData.XpmMetadata : null; } else { // Custom Page Model with custom metadata; do full-blown model mapping. MappingData mappingData = new MappingData { SourceViewModel = pageModelData, ModelId = pageModelData.Id, ModelType = modelType, PropertyValidation = new Validation { MainSchema = SemanticMapping.GetSchema(pageModelData.SchemaId, localization), InheritedSchemas = GetInheritedSemanticSchemas(pageModelData, localization) }, MetadataFields = pageModelData.Metadata, Localization = localization }; pageModel = (PageModel)CreateViewModel(mappingData); } pageModel.MvcData = mvcData; pageModel.Meta = pageModelData.Meta ?? new Dictionary <string, string>(); pageModel.Title = PostProcessPageTitle(pageModelData, localization); // TODO TSI-2210: This should eventually be done in Model Service. pageModel.Url = pageModelData.UrlPath; if (pageModelData.Regions != null) { IEnumerable <RegionModelData> regions = includePageRegions ? pageModelData.Regions : pageModelData.Regions.Where(r => r.IncludePageId == null); pageModel.Regions.UnionWith(regions.Select(data => CreateRegionModel(data, localization))); pageModel.IsVolatile |= pageModel.Regions.Any(region => region.IsVolatile); } } }
protected virtual Dictionary <string, List <SemanticProperty> > LoadPropertySemantics(Type type) { lock (_semanticPropertiesCache) { // Try to get cached semantics Dictionary <string, List <SemanticProperty> > result; if (_semanticPropertiesCache.TryGetValue(type, out result)) { return(result); } result = ModelTypeRegistry.GetPropertySemantics(type); _semanticPropertiesCache.Add(type, result); return(result); } }
/// <summary> /// Tries to convert a given generic Topic to a Strongly Typed Topic Model. /// </summary> /// <param name="genericTopic">The generic Topic to convert.</param> /// <param name="ofType">The type of the Strongly Typed Topic Model to convert to. If not specified (or <c>null</c>), the type will be determined from the XHTML.</param> /// <returns>The Strongly Typed Topic Model or <c>null</c> if the generic Topic cannot be converted.</returns> public EntityModel TryConvertToStronglyTypedTopic(GenericTopic genericTopic, Type ofType = null) { using (new Tracer(genericTopic, ofType)) { Log.Debug($"Trying to convert {genericTopic} to Strongly Typed Topic Model..."); IEnumerable <Tuple <string, Type> > registeredTopicTypes = ModelTypeRegistry.GetModelTypesForVocabulary(ViewModel.DitaVocabulary); if (registeredTopicTypes == null) { Log.Debug("No Strongly Typed Topic Models registered."); return(null); } XmlElement rootElement = null; try { rootElement = ParseXhtml(genericTopic); } catch (Exception ex) { Log.Error("Unable to parse generic Topic XHTML."); Log.Debug(genericTopic.TopicBody); Log.Error(ex); return(null); } Type topicType = ofType; if (ofType == null) { topicType = DetermineTopicType(rootElement, registeredTopicTypes); if (topicType == null) { Log.Debug("No matching Strongly Typed Topic Model found."); return(null); } } EntityModel stronglyTypedTopic = BuildStronglyTypedTopic(topicType, rootElement); if (stronglyTypedTopic.Id == null) { stronglyTypedTopic.Id = genericTopic.Id; } return(stronglyTypedTopic); } }
protected virtual RegionModel CreateRegionModel(RegionModelData regionModelData, ILocalization localization) { MvcData mvcData = CreateMvcData(regionModelData.MvcData, "Region"); Type regionModelType = ModelTypeRegistry.GetViewModelType(mvcData); RegionModel result = (RegionModel)regionModelType.CreateInstance(regionModelData.Name); result.ExtensionData = regionModelData.ExtensionData; result.HtmlClasses = regionModelData.HtmlClasses; result.MvcData = mvcData; result.XpmMetadata = localization.IsXpmEnabled ? regionModelData.XpmMetadata : null; if (regionModelData.Regions != null) { IEnumerable <RegionModel> nestedRegionModels = regionModelData.Regions.Select(data => CreateRegionModel(data, localization)); result.Regions.UnionWith(nestedRegionModels); result.IsVolatile |= result.Regions.Any(region => region.IsVolatile); } if (regionModelData.Entities != null) { foreach (EntityModelData entityModelData in regionModelData.Entities) { EntityModel entityModel; try { entityModel = ModelBuilderPipeline.CreateEntityModel(entityModelData, null, localization); // indicate to region model that this region is potentially volatile if it contains a volatile entity result.IsVolatile |= entityModel.IsVolatile; entityModel.MvcData.RegionName = regionModelData.Name; } catch (Exception ex) { // If there is a problem mapping an Entity, we replace it with an ExceptionEntity which holds the error details and carry on. Log.Error(ex); entityModel = new ExceptionEntity(ex); } result.Entities.Add(entityModel); } } return(result); }
protected virtual void MapSemanticProperties(EntityModel stronglyTypedTopic, XmlElement rootElement) { Type modelType = stronglyTypedTopic.GetType(); IDictionary <string, List <SemanticProperty> > propertySemanticsMap = ModelTypeRegistry.GetPropertySemantics(modelType); foreach (KeyValuePair <string, List <SemanticProperty> > propertySemantics in propertySemanticsMap) { PropertyInfo modelProperty = modelType.GetProperty(propertySemantics.Key); List <SemanticProperty> semanticProperties = propertySemantics.Value; IEnumerable <XmlElement> htmlElements = null; foreach (SemanticProperty ditaProperty in semanticProperties.Where(sp => sp.SemanticType.Vocab == ViewModel.DitaVocabulary)) { string ditaPropertyName = ditaProperty.PropertyName; string propertyXPath = GetPropertyXPath(ditaPropertyName); Log.Debug($"Trying XPath \"{propertyXPath}\" for property '{modelProperty.Name}'"); XmlNodeList xPathResults = rootElement.SelectNodes(propertyXPath); htmlElements = FilterXPathResults(xPathResults, ditaPropertyName); if (htmlElements != null && htmlElements.Any()) { break; } Log.Debug($"No XHTML elements found for DITA property '{ditaPropertyName}'."); } if (htmlElements == null || !htmlElements.Any()) { Log.Debug($"Unable to map property '{modelProperty.Name}'"); continue; } Log.Debug($"{htmlElements.Count()} XHTML elements found."); try { object propertyValue = GetPropertyValue(modelProperty.PropertyType, htmlElements); modelProperty.SetValue(stronglyTypedTopic, propertyValue); } catch (Exception ex) { throw new DxaException($"Unable to map property {modelType.Name}.{modelProperty.Name}", ex); } } }
private static RegionModel CreateRegionModel(RegionModelData regionModelData, Localization localization) { Common.Models.MvcData mvcData = CreateMvcData(regionModelData.MvcData, "Region"); Type regionModelType = ModelTypeRegistry.GetViewModelType(mvcData); RegionModel result = (RegionModel)regionModelType.CreateInstance(regionModelData.Name); result.ExtensionData = regionModelData.ExtensionData; result.HtmlClasses = regionModelData.HtmlClasses; result.MvcData = mvcData; result.XpmMetadata = regionModelData.XpmMetadata; if (regionModelData.Regions != null) { IEnumerable <RegionModel> nestedRegionModels = regionModelData.Regions.Select(data => CreateRegionModel(data, localization)); result.Regions.UnionWith(nestedRegionModels); } if (regionModelData.Entities != null) { foreach (EntityModelData entityModelData in regionModelData.Entities) { EntityModel entityModel; try { entityModel = ModelBuilderPipelineR2.CreateEntityModel(entityModelData, null, localization); entityModel.MvcData.RegionName = regionModelData.Name; } catch (Exception ex) { // If there is a problem mapping an Entity, we replace it with an ExceptionEntity which holds the error details and carry on. Log.Error(ex); entityModel = new ExceptionEntity(ex); } result.Entities.Add(entityModel); } } return(result); }
/// <summary> /// Automatically register all view models for an area. This is done by searching the file system /// for all .cshtml files, determining the controller and view names from the path, and using the /// BuildManager to determine the model type by compiling the view. Note that if your area contains /// a lot of views, this can be a lengthy process and you might be better off explicitly registering /// your views with the RegisterViewModel method /// </summary> protected virtual void RegisterAllViewModels() { DateTime timer = DateTime.Now; int viewCount = 0; string baseDir = AppDomain.CurrentDomain.BaseDirectory; string path = Path.Combine(baseDir, "Areas", this.AreaName, "Views"); Log.Debug("Staring to register views for area: {0}", this.AreaName); foreach (string file in Directory.GetFiles(path, "*.cshtml", SearchOption.AllDirectories)) { string relativePath = file.Substring(path.Length + 1); string virtualPath = @"~/" + file.Replace(baseDir, string.Empty).Replace("\\", "/"); int pos = relativePath.IndexOf("\\"); if (pos > 0) { string controller = relativePath.Substring(0, pos); string view = relativePath.Substring(pos + 1); int extnPos = view.LastIndexOf(".cshtml"); view = view.Substring(0, extnPos); MvcData mvcData = new MvcData { AreaName = this.AreaName, ControllerName = controller, ViewName = view }; try { ModelTypeRegistry.RegisterViewModel(mvcData, virtualPath); viewCount++; } catch { //Do nothing - we ignore views that are not strongly typed } } else { Log.Warn("Cannot add view {0} to view model registry as it is not in a {ControllerName} subfolder", file); } } Log.Info("Registered {0} views for area {1} in {2} milliseconds. This startup overhead can be reduced by explicitly registering view using the Sdl.Web.Mvc.Configuration.BaseAreaRegistration.RegisterView() method.", viewCount, this.AreaName, (DateTime.Now - timer).TotalMilliseconds); }
/// <summary> /// Determine a Model Type based on semantic mappings (and a given base model type). /// </summary> /// <param name="baseModelType">The base type as obtained from the View Model.</param> /// <returns>The given base Model Type or a subclass if a more specific class can be resolved via semantic mapping.</returns> /// <remarks> /// This method makes it possible (for example) to let the <see cref="Teaser.Media"/> property get an instance of <see cref="Image"/> /// rather than just <see cref="MediaItem"/> (the type of the View Model property). /// </remarks> public Type GetModelTypeFromSemanticMapping(Type baseModelType) { Type[] foundAmbiguousMappings = null; string[] semanticTypeNames = GetSemanticTypeNames(); foreach (string semanticTypeName in semanticTypeNames) { IEnumerable <Type> mappedModelTypes = ModelTypeRegistry.GetMappedModelTypes(semanticTypeName); if (mappedModelTypes == null) { continue; } Type[] matchingModelTypes = mappedModelTypes.Where(t => baseModelType.IsAssignableFrom(t)).ToArray(); if (matchingModelTypes.Length == 1) { // Exactly one matching model type; return it. return(matchingModelTypes[0]); } if (matchingModelTypes.Length > 1) { // Multiple candidate models types found. Continue scanning; maybe we'll find a unique one for another semantic type. foundAmbiguousMappings = matchingModelTypes; } } if (foundAmbiguousMappings == null) { Log.Warn("No semantic mapping found between Schema {0} ({1}) and model type '{2}'. Sticking with model type.", Id, String.Join(", ", semanticTypeNames), baseModelType.FullName); } else { Log.Warn("Ambiguous semantic mappings found between Schema {0} ({1}) and model type '{2}'. Found types: {3}. Sticking with model type.", Id, String.Join(", ", semanticTypeNames), String.Join(", ", foundAmbiguousMappings.Select(t => t.FullName)), baseModelType.FullName); } return(baseModelType); }
/// <summary> /// Registers a View Model Type without associated View. /// </summary> private static void RegisterViewModel(Type modelType) { ModelTypeRegistry.RegisterViewModel(null, modelType); }
protected virtual void MapSemanticProperties(ViewModel viewModel, MappingData mappingData) { Type modelType = viewModel.GetType(); IDictionary <string, List <SemanticProperty> > propertySemanticsMap = ModelTypeRegistry.GetPropertySemantics(modelType); IDictionary <string, string> xpmPropertyMetadata = new Dictionary <string, string>(); Validation validation = mappingData.PropertyValidation; foreach (KeyValuePair <string, List <SemanticProperty> > propertySemantics in propertySemanticsMap) { PropertyInfo modelProperty = modelType.GetProperty(propertySemantics.Key); List <SemanticProperty> semanticProperties = propertySemantics.Value; bool isFieldMapped = false; string fieldXPath = null; foreach (SemanticProperty semanticProperty in semanticProperties) { if (semanticProperty.PropertyName == SemanticProperty.AllFields) { modelProperty.SetValue(viewModel, GetAllFieldsAsDictionary(mappingData)); isFieldMapped = true; break; } if ((semanticProperty.PropertyName == SemanticProperty.Self) && validation.MainSchema.HasSemanticType(semanticProperty.SemanticType)) { try { object mappedSelf = MapComponentLink((EntityModelData)mappingData.SourceViewModel, modelProperty.PropertyType, mappingData.Localization); modelProperty.SetValue(viewModel, mappedSelf); isFieldMapped = true; break; } catch (Exception ex) { Log.Debug($"Self mapping failed for {modelType.Name}.{modelProperty.Name}: {ex.Message}"); continue; } } FieldSemantics fieldSemantics = new FieldSemantics( semanticProperty.SemanticType.Vocab, semanticProperty.SemanticType.EntityName, semanticProperty.PropertyName, null); SemanticSchemaField semanticSchemaField = (mappingData.EmbeddedSemanticSchemaField == null) ? ValidateField(validation, fieldSemantics) : mappingData.EmbeddedSemanticSchemaField.FindFieldBySemantics(fieldSemantics); if (semanticSchemaField == null) { // No matching Semantic Schema Field found for this Semantic Property; maybe another one will match. continue; } // Matching Semantic Schema Field found fieldXPath = IsFieldFromMainSchema(validation, fieldSemantics) ? semanticSchemaField.GetXPath(mappingData.ContextXPath) : null; ContentModelData fields = semanticSchemaField.IsMetadata ? mappingData.MetadataFields : mappingData.Fields; object fieldValue = FindFieldValue(semanticSchemaField, fields, mappingData.EmbedLevel); if (fieldValue == null) { // No field value found; maybe we will find a value for another Semantic Property. continue; } try { object mappedPropertyValue = MapField(fieldValue, modelProperty.PropertyType, semanticSchemaField, mappingData); modelProperty.SetValue(viewModel, mappedPropertyValue); } catch (Exception ex) { throw new DxaException( $"Unable to map field '{semanticSchemaField.Name}' to property {modelType.Name}.{modelProperty.Name} of type '{modelProperty.PropertyType.FullName}'.", ex); } isFieldMapped = true; break; } if (fieldXPath != null) { xpmPropertyMetadata.Add(modelProperty.Name, fieldXPath); } else if (!isFieldMapped && Log.IsDebugEnabled) { string formattedSemanticProperties = string.Join(", ", semanticProperties.Select(sp => sp.ToString())); Log.Debug( $"Property {modelType.Name}.{modelProperty.Name} cannot be mapped to a CM field of {validation.MainSchema}. Semantic properties: {formattedSemanticProperties}."); } } EntityModel entityModel = viewModel as EntityModel; if ((entityModel != null) && mappingData.Localization.IsXpmEnabled) { entityModel.XpmPropertyMetadata = xpmPropertyMetadata; } }
/// <summary> /// Registers a View Model without associated View. /// </summary> /// <param name="modelType">The View Model type.</param> /// <remarks> /// </remarks> protected void RegisterViewModel(Type modelType) { ModelTypeRegistry.RegisterViewModel(null, modelType); }
protected virtual RegionModel CreateRegionModel(RegionModelData regionModelData, ILocalization localization) { MvcData mvcData = CreateMvcData(regionModelData.MvcData, "Region"); Type regionModelType = ModelTypeRegistry.GetViewModelType(mvcData); RegionModel result = (RegionModel)regionModelType.CreateInstance(regionModelData.Name); result.ExtensionData = regionModelData.ExtensionData; result.HtmlClasses = regionModelData.HtmlClasses; result.MvcData = mvcData; result.XpmMetadata = localization.IsXpmEnabled ? regionModelData.XpmMetadata : null; result.SchemaId = regionModelData.SchemaId; if (!string.IsNullOrEmpty(regionModelData.SchemaId)) { SemanticSchema semanticSchema = SemanticMapping.GetSchema(regionModelData.SchemaId, localization); Type modelType = ModelTypeRegistry.GetViewModelType(mvcData); MappingData mappingData = new MappingData { SourceViewModel = regionModelData, ModelType = modelType, PropertyValidation = new Validation { MainSchema = semanticSchema, InheritedSchemas = GetInheritedSemanticSchemas(regionModelData, localization) }, Fields = null, MetadataFields = regionModelData.Metadata, Localization = localization }; MapSemanticProperties(result, mappingData); } if (regionModelData.Regions != null) { IEnumerable <RegionModel> nestedRegionModels = regionModelData.Regions.Select(data => CreateRegionModel(data, localization)); result.Regions.UnionWith(nestedRegionModels); result.IsVolatile |= result.Regions.Any(region => region.IsVolatile); } if (regionModelData.Entities != null) { foreach (EntityModelData entityModelData in regionModelData.Entities) { EntityModel entityModel; try { entityModel = ModelBuilderPipeline.CreateEntityModel(entityModelData, null, localization); // indicate to region model that this region is potentially volatile if it contains a volatile entity result.IsVolatile |= entityModel.IsVolatile; entityModel.MvcData.RegionName = regionModelData.Name; } catch (Exception ex) { // If there is a problem mapping an Entity, we replace it with an ExceptionEntity which holds the error details and carry on. Log.Error(ex); entityModel = new ExceptionEntity(ex); } result.Entities.Add(entityModel); } } return(result); }
public static void AddViewModelToRegistry(MvcData viewData, string viewPath) { ModelTypeRegistry.RegisterViewModel(viewData, viewPath); }
public static void AddViewModelToRegistry(MvcData mvcData, Type modelType) { ModelTypeRegistry.RegisterViewModel(mvcData, modelType); }
protected virtual Type GetViewType(MvcData viewData) { return(ModelTypeRegistry.GetViewModelType(viewData)); }