/// <summary> /// Gets <see cref="ModelExplorer"/> for named <paramref name="expression"/> in given /// <paramref name="viewData"/>. /// </summary> /// <param name="expression">Expression name, relative to <c>viewData.Model</c>.</param> /// <param name="viewData"> /// The <see cref="ViewDataDictionary"/> that may contain the <paramref name="expression"/> value. /// </param> /// <param name="metadataProvider">The <see cref="IModelMetadataProvider"/>.</param> /// <returns> /// <see cref="ModelExplorer"/> for named <paramref name="expression"/> in given <paramref name="viewData"/>. /// </returns> public static ModelExplorer FromStringExpression( string expression, [NotNull] ViewDataDictionary viewData, IModelMetadataProvider metadataProvider) { var viewDataInfo = ViewDataEvaluator.Eval(viewData, expression); if (viewDataInfo == null) { // Try getting a property from ModelMetadata if we couldn't find an answer in ViewData var propertyExplorer = viewData.ModelExplorer.GetExplorerForProperty(expression); if (propertyExplorer != null) { return(propertyExplorer); } } if (viewDataInfo != null) { if (viewDataInfo.Container == viewData && viewDataInfo.Value == viewData.Model && string.IsNullOrEmpty(expression)) { // Nothing for empty expression in ViewData and ViewDataEvaluator just returned the model. Handle // using FromModel() for its object special case. return(FromModel(viewData, metadataProvider)); } ModelExplorer containerExplorer = viewData.ModelExplorer; if (viewDataInfo.Container != null) { containerExplorer = metadataProvider.GetModelExplorerForType( viewDataInfo.Container.GetType(), viewDataInfo.Container); } if (viewDataInfo.PropertyInfo != null) { // We've identified a property access, which provides us with accurate metadata. var containerType = viewDataInfo.Container?.GetType() ?? viewDataInfo.PropertyInfo.DeclaringType; var containerMetadata = metadataProvider.GetMetadataForType(viewDataInfo.Container.GetType()); var propertyMetadata = containerMetadata.Properties[viewDataInfo.PropertyInfo.Name]; Func <object, object> modelAccessor = (ignore) => viewDataInfo.Value; return(containerExplorer.GetExplorerForExpression(propertyMetadata, modelAccessor)); } else if (viewDataInfo.Value != null) { // We have a value, even though we may not know where it came from. var valueMetadata = metadataProvider.GetMetadataForType(viewDataInfo.Value.GetType()); return(containerExplorer.GetExplorerForExpression(valueMetadata, viewDataInfo.Value)); } } // Treat the expression as string if we don't find anything better. var stringMetadata = metadataProvider.GetMetadataForType(typeof(string)); return(viewData.ModelExplorer.GetExplorerForExpression(stringMetadata, modelAccessor: null)); }
public static ModelMetadata FromStringExpression(string expression, [NotNull] ViewDataDictionary viewData, IModelMetadataProvider metadataProvider) { if (string.IsNullOrEmpty(expression)) { // Empty string really means "ModelMetadata for the current model". return(FromModel(viewData, metadataProvider)); } var viewDataInfo = ViewDataEvaluator.Eval(viewData, expression); Type containerType = null; Type modelType = null; Func <object> modelAccessor = null; string propertyName = null; object container = null; if (viewDataInfo != null) { if (viewDataInfo.Container != null) { containerType = viewDataInfo.Container.GetType(); container = viewDataInfo.Container; } modelAccessor = () => viewDataInfo.Value; if (viewDataInfo.PropertyInfo != null) { propertyName = viewDataInfo.PropertyInfo.Name; modelType = viewDataInfo.PropertyInfo.PropertyType; } else if (viewDataInfo.Value != null) { // We only need to delay accessing properties (for LINQ to SQL) modelType = viewDataInfo.Value.GetType(); } } else { // Try getting a property from ModelMetadata if we couldn't find an answer in ViewData var propertyMetadata = viewData.ModelMetadata.Properties.Where(p => p.PropertyName == expression).FirstOrDefault(); if (propertyMetadata != null) { return(propertyMetadata); } } return(GetMetadataFromProvider(modelAccessor, modelType ?? typeof(string), propertyName, container, containerType, metadataProvider)); }