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);
        }
Example #2
0
        public void GetViewDataInfoFromDictionaryWithMissingEntry()
        {
            // Arrange
            ViewDataDictionary vdd = new ViewDataDictionary();

            // Act
            ViewDataInfo info = vdd.GetViewDataInfo("foo");

            // Assert
            Assert.Null(info);
        }
Example #3
0
        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);
        }
Example #5
0
        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);
        }
Example #7
0
        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);
        }
Example #8
0
        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);
        }
Example #9
0
        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);
        }
Example #10
0
        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);
        }
Example #11
0
    /// <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);
    }
Example #12
0
        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);
        }
Example #13
0
    {    /// <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));
        }