Skip to main content

The ModelStateDictionaryExtensions class provides extension methods to System.Web.Mvc.ModelStateDictionary.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Web.Mvc;

namespace Extensions
{
    /// <summary>
    /// The <code>ModelStateDictionaryExtensions</code> class provides extension
    /// methods to <code>System.Web.Mvc.ModelStateDictionary</code>.
    /// </summary>
    /// <remarks>https://raw.githubusercontent.com/rmariuzzo/Mariuzzo.Web.Mvc.Extras/master/Mariuzzo.Web.Mvc.Extras/ModelStateDictionaryExtensions.cs</remarks>
    public static class ModelStateDictionaryExtensions
    {
        /// <summary>
        /// Indicates if the expression is a valid field for the current model.
        /// </summary>
        /// <typeparam name="TModel">The type of the model.</typeparam>
        /// <param name="modelState">The model state.</param>
        /// <param name="expression">The expression tree representing a property to validate.</param>
        /// <returns><code>true</code> if the expression is a valid field for the current model, otherwise <code>false</code>.</returns>
        public static bool IsValidField<TModel>(this ModelStateDictionary modelState, Expression<Func<TModel, object>> expression)
        {
            if (expression == null)
            {
                throw new ArgumentNullException("expression");
            }

            return modelState.IsValidField(ExpressionHelper.GetExpressionText(expression));
        }

        /// <summary>
        /// Add a model error.
        /// </summary>
        /// <typeparam name="TModel">The type of the model.</typeparam>
        /// <param name="modelState">The model state.</param>
        /// <param name="expression">
        /// The expression tree representing a property to add an
        /// error in its state.</param>
        /// <param name="errorMessage">The error message to add.</param>
        public static void AddModelError<TModel>(this ModelStateDictionary modelState, Expression<Func<TModel, object>> expression, string errorMessage)
        {
            modelState.AddModelError(ExpressionHelper.GetExpressionText(expression), errorMessage);
        }

        /// <summary>
        /// Add a model error.
        /// </summary>
        /// <typeparam name="TModel">The type of the model.</typeparam>
        /// <param name="modelState">The model state.</param>
        /// <param name="expression">The expression tree representing a property to add an error in its state.</param>
        /// <param name="exception">The exception to add as an error message container.</param>
        public static void AddModelError<TModel>(this ModelStateDictionary modelState, Expression<Func<TModel, object>> expression, Exception exception)
        {
            modelState.AddModelError(ExpressionHelper.GetExpressionText(expression), exception);
        }

        /// <summary>
        /// Add an error not bound to any model's property.
        /// </summary>
        /// <param name="modelState">The model state.</param>
        /// <param name="errorMessage">The error message to add.</param>
        public static void AddError(this ModelStateDictionary modelState, string errorMessage)
        {
            modelState.AddModelError(string.Empty, errorMessage);
        }

        /// <summary>
        /// Remove the element that has the specified tree expression from
        /// the model-state dictionary.
        /// </summary>
        /// <typeparam name="TModel">The type of the model.</typeparam>
        /// <param name="modelState">The model state.</param>
        /// <param name="expression">The expression tree representing a property.</param>
        public static bool Remove<TModel>(this ModelStateDictionary modelState, Expression<Func<TModel, object>> expression)
        {
            return modelState.Remove(ExpressionHelper.GetExpressionText(expression));
        }

        /// <summary>
        /// Remove any element that has as prefix the specified tree
        /// expression from the model-state dictionary.
        /// </summary>
        /// <typeparam name="TModel">The type of the model.</typeparam>
        /// <param name="modelState">The model state.</param>
        /// <param name="expression">The expression tree representing a property.</param>
        /// <returns><code>true</code> if any elemente was removed from
        /// the ModelStateDictionary, otherwise <code>false</code>.</returns>
        public static bool RemoveWithPrefix<TModel>(this ModelStateDictionary modelState, Expression<Func<TModel, object>> expression)
        {
            bool anyRemoved = false;
            foreach (string key in modelState.Keys.ToList())
            {
                if (key != null && key.Split('.')[0] == ExpressionHelper.GetExpressionText(expression))
                {
                    anyRemoved = modelState.Remove(key) || anyRemoved;
                }
            }
            return anyRemoved;
        }

        /// <summary>
        /// Creates string List of the combined model state error keys
        /// and error messages (errorKey:errorMessage).
        /// </summary>
        /// <remarks>http://stackoverflow.com/a/18385336</remarks>
        /// <param name="modelState">State of the model.</param>
        /// <returns></returns>
        public static List<string> ErrorKeyList(this ModelStateDictionary modelState)
        {
            var list = new List<string>();

            if (!modelState.IsValid)
            {
                foreach (var result in modelState.Keys.SelectMany(
                    key => modelState[key].Errors.Select(x => key + ": " + x.ErrorMessage)))
                {
                    list.Add(result);
                }
            }

            return list;
        }

        /// <summary>
        /// Creates a combined string of model state error keys
        /// and error messages (errorKey:errorMessage).
        /// </summary>
        /// <param name="modelState">State of the model.</param>
        /// <returns></returns>
        public static string ErrorKeyString(this ModelStateDictionary modelState)
        {
            var sb = new StringBuilder();

            var errorList = modelState.ErrorKeyList();
            foreach (var error in errorList)
            {
                sb.AppendLine(error);
            }

            return sb.ToString();
        }
    }
}


// -----------------------------------------------------------------------------
// ModelStateExtensions from Telerik Kendo MVC:
// src/Kendo.Mvc/Kendo.Mvc/Extensions/ModelStateExtensions.cs
// -----------------------------------------------------------------------------

namespace Kendo.Mvc.Extensions
{
    using System.Web.Mvc;
    using System.Collections.Generic;
    using System.Linq;
    // using Kendo.Mvc.Resources;

    public static class ModelStateExtensions
    {
        public static object ToDataSourceResult(this ModelStateDictionary modelState)
        {
            if (!modelState.IsValid)
            {
                return new { Errors = modelState.SerializeErrors() };
            }

            return new object();
        }

        public static object SerializeErrors(this ModelStateDictionary modelState)
        {
            return modelState.Where(entry => entry.Value.Errors.Any())
                             .ToDictionary(entry => entry.Key, entry => SerializeModelState(entry.Value));
        }

        private static Dictionary<string, object> SerializeModelState(ModelState modelState)
        {
            var result = new Dictionary<string, object>();
            result["errors"] = modelState.Errors
                                         .Select(error => GetErrorMessage(error, modelState))
                                         .ToArray();
            return result;
        }

        private static string GetErrorMessage(ModelError error, ModelState modelState)
        {
            if (!error.ErrorMessage.HasValue())
            {
                if (modelState.Value == null)
                {
                    return error.ErrorMessage;
                }

                // return Exceptions.ValueNotValidForProperty.FormatWith(modelState.Value.AttemptedValue);
                return string.Format("The value '{0}' is invalid.", modelState.Value.AttemptedValue);
            }

            return error.ErrorMessage;
        }
    }
}