public void ViewDataInfoDoesNotCallAccessorUntilValuePropertyAccessed() { // Arrange bool called = false; ViewDataInfo vdi = new ViewDataInfo(() => { called = true; return 21; }); // Act & Assert Assert.IsFalse(called); object result = vdi.Value; Assert.IsTrue(called); Assert.AreEqual(21, result); }
public void GetViewDataInfoFromDictionaryWithMissingEntry() { // Arrange ViewDataDictionary vdd = new ViewDataDictionary(); // Act ViewDataInfo info = vdd.GetViewDataInfo("foo"); // Assert Assert.Null(info); }
internal static ModelMetadata FromStringExpression(string expression, ViewDataDictionary viewData, ModelMetadataProvider metadataProvider) { if (expression == null) { throw new ArgumentNullException("expression"); } if (viewData == null) { throw new ArgumentNullException("viewData"); } if (expression.Length == 0) // Empty string really means "model metadata for the current model" { return(FromModel(viewData, metadataProvider)); } ViewDataInfo vdi = viewData.GetViewDataInfo(expression); Type containerType = null; Type modelType = null; Func <object> modelAccessor = null; string propertyName = null; if (vdi != null) { if (vdi.Container != null) { containerType = vdi.Container.GetType(); } modelAccessor = () => vdi.Value; if (vdi.PropertyDescriptor != null) { propertyName = vdi.PropertyDescriptor.Name; modelType = vdi.PropertyDescriptor.PropertyType; } else if (vdi.Value != null) // We only need to delay accessing properties (for LINQ to SQL) { modelType = vdi.Value.GetType(); } } // Try getting a property from ModelMetadata if we couldn't find an answer in ViewData else if (viewData.ModelMetadata != null) { ModelMetadata propertyMetadata = viewData.ModelMetadata.Properties.Where(p => p.PropertyName == expression).FirstOrDefault(); if (propertyMetadata != null) { return(propertyMetadata); } } return(GetMetadataFromProvider(modelAccessor, modelType ?? typeof(string), propertyName, containerType, metadataProvider)); }
public void SettingExplicitValueOverridesAccessorMethod() { // Arrange bool called = false; ViewDataInfo vdi = new ViewDataInfo(() => { called = true; return null; }); // Act & Assert Assert.IsFalse(called); vdi.Value = 42; object result = vdi.Value; Assert.IsFalse(called); Assert.AreEqual(42, result); }
public void ViewDataInfoDoesNotCallAccessorUntilValuePropertyAccessed() { // Arrange bool called = false; ViewDataInfo vdi = new ViewDataInfo(() => { called = true; return(21); }); // Act & Assert Assert.IsFalse(called); object result = vdi.Value; Assert.IsTrue(called); Assert.AreEqual(21, result); }
public void AccessorIsOnlyCalledOnce() { // Arrange int callCount = 0; ViewDataInfo vdi = new ViewDataInfo(() => { ++callCount; return null; }); // Act & Assert Assert.AreEqual(0, callCount); object unused; unused = vdi.Value; unused = vdi.Value; unused = vdi.Value; Assert.AreEqual(1, callCount); }
public void SettingExplicitValueOverridesAccessorMethod() { // Arrange bool called = false; ViewDataInfo vdi = new ViewDataInfo(() => { called = true; return(null); }); // Act & Assert Assert.IsFalse(called); vdi.Value = 42; object result = vdi.Value; Assert.IsFalse(called); Assert.AreEqual(42, result); }
public void AccessorIsOnlyCalledOnce() { // Arrange int callCount = 0; ViewDataInfo vdi = new ViewDataInfo(() => { ++callCount; return(null); }); // Act & Assert Assert.AreEqual(0, callCount); object unused; unused = vdi.Value; unused = vdi.Value; unused = vdi.Value; Assert.AreEqual(1, callCount); }
public void GetViewDataInfoFromDictionaryWithNullEntry() { // Arrange ViewDataDictionary vdd = new ViewDataDictionary() { { "Foo", null } }; // Act ViewDataInfo info = vdd.GetViewDataInfo("foo"); // Assert Assert.NotNull(info); Assert.Equal(vdd, info.Container); Assert.Null(info.Value); }
public void GetViewDataInfoFromModel() { // Arrange object model = new { foo = "fooValue" }; ViewDataDictionary vdd = new ViewDataDictionary(model); PropertyDescriptor propDesc = TypeDescriptor.GetProperties(model).Find("foo", true /* ignoreCase */); // Act ViewDataInfo info = vdd.GetViewDataInfo("foo"); // Assert Assert.NotNull(info); Assert.Equal(model, info.Container); Assert.Equal(propDesc, info.PropertyDescriptor); Assert.Equal("fooValue", info.Value); }
/// <summary> /// Gets <see cref="ViewDataInfo"/> for named <paramref name="expression"/> in given /// <paramref name="viewData"/>. /// </summary> /// <param name="viewData"> /// The <see cref="ViewDataDictionary"/> that may contain the <paramref name="expression"/> value. /// </param> /// <param name="expression">Expression name, relative to <c>viewData.Model</c>.</param> /// <returns> /// <see cref="ViewDataInfo"/> for named <paramref name="expression"/> in given <paramref name="viewData"/>. /// </returns> public static ViewDataInfo Eval(ViewDataDictionary viewData, string expression) { if (viewData == null) { throw new ArgumentNullException(nameof(viewData)); } // While it is not valid to generate a field for the top-level model itself because the result is an // unnamed input element, do not throw here if full name is null or empty. Support is needed for cases // such as Html.Label() and Html.Value(), where the user's code is not creating a name attribute. Checks // are in place at higher levels for the invalid cases. var fullName = viewData.TemplateInfo.GetFullHtmlFieldName(expression); // Given an expression "one.two.three.four" we look up the following (pseudo-code): // this["one.two.three.four"] // this["one.two.three"]["four"] // this["one.two"]["three.four] // this["one.two"]["three"]["four"] // this["one"]["two.three.four"] // this["one"]["two.three"]["four"] // this["one"]["two"]["three.four"] // this["one"]["two"]["three"]["four"] // Try to find a matching ViewData entry using the full expression name. If that fails, fall back to // ViewData.Model using the expression's relative name. var result = EvalComplexExpression(viewData, fullName); if (result == null) { if (string.IsNullOrEmpty(expression)) { // Null or empty expression name means current model even if that model is null. result = new ViewDataInfo(container: viewData, value: viewData.Model); } else { result = EvalComplexExpression(viewData.Model, expression); } } return(result); }
public void GetViewDataInfoFromDictionary() { // Arrange ViewDataDictionary fooVdd = new ViewDataDictionary() { { "Bar", "barValue" } }; ViewDataDictionary vdd = new ViewDataDictionary() { { "Foo", fooVdd } }; // Act ViewDataInfo info = vdd.GetViewDataInfo("foo.bar"); // Assert Assert.NotNull(info); Assert.Equal(fooVdd, info.Container); Assert.Equal("barValue", info.Value); }
{ /// <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, ViewDataDictionary viewData, IModelMetadataProvider metadataProvider) { ViewDataInfo viewDataInfo = ViewDataEvaluator.Eval(viewData, expression); if (viewDataInfo is null) { // Try getting a property from ModelMetadata if we couldn't find an answer in ViewData ModelExplorer propertyExplorer = viewData.ModelExplorer.GetExplorerForProperty(expression); if (propertyExplorer is not null) { return(propertyExplorer); } } if (viewDataInfo is not 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 is not null) { containerExplorer = metadataProvider.GetModelExplorerForType( viewDataInfo.Container.GetType(), viewDataInfo.Container); } if (viewDataInfo.PropertyInfo is not null) { // We've identified a property access, which provides us with accurate metadata. ModelMetadata containerMetadata = metadataProvider.GetMetadataForType(viewDataInfo.Container?.GetType()); ModelMetadata propertyMetadata = containerMetadata.Properties[viewDataInfo.PropertyInfo.Name]; object modelAccessor(object ignore) { return(viewDataInfo.Value); } return(containerExplorer.GetExplorerForExpression(propertyMetadata, modelAccessor)); } else if (viewDataInfo.Value is not null) { // We have a value, even though we may not know where it came from. ModelMetadata valueMetadata = metadataProvider.GetMetadataForType(viewDataInfo.Value.GetType()); return(containerExplorer.GetExplorerForExpression(valueMetadata, viewDataInfo.Value)); } } // Treat the expression as string if we don't find anything better. ModelMetadata stringMetadata = metadataProvider.GetMetadataForType(typeof(string)); return(viewData.ModelExplorer.GetExplorerForExpression(stringMetadata, modelAccessor: null)); }