using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web.Mvc;
namespace Umbraco.Web
{
internal static class ModelStateExtensions
{
///
/// Merges ModelState that has names matching the prefix
///
///
///
///
public static void Merge(this ModelStateDictionary state, ModelStateDictionary dictionary, string prefix)
{
if (dictionary == null)
return;
foreach (var keyValuePair in dictionary
//It can either equal the prefix exactly (model level errors) or start with the prefix. (property level errors)
.Where(keyValuePair => keyValuePair.Key == prefix || keyValuePair.Key.StartsWith(prefix + ".")))
{
state[keyValuePair.Key] = keyValuePair.Value;
}
}
///
/// Checks if there are any model errors on any fields containing the prefix
///
///
///
///
public static bool IsValid(this ModelStateDictionary state, string prefix)
{
return state.Where(v => v.Key.StartsWith(prefix + ".")).All(v => !v.Value.Errors.Any());
}
//NOTE: we used this alot in v5 when we had editors in MVC, this was really handy for knockout editors using JS
/////
///// Adds an error to the model state that has to do with data validation, this is generally used for JSON responses
/////
/////
/////
//public static void AddDataValidationError(this ModelStateDictionary state, string errorMessage)
//{
// state.AddModelError("DataValidation", errorMessage);
//}
///
/// Adds the error to model state correctly for a property so we can use it on the client side.
///
///
///
///
internal static void AddPropertyError(this System.Web.Http.ModelBinding.ModelStateDictionary modelState, ValidationResult result, string propertyAlias)
{
//if there are no member names supplied then we assume that the validation message is for the overall property
// not a sub field on the property editor
if (!result.MemberNames.Any())
{
//add a model state error for the entire property
modelState.AddModelError(string.Format("{0}.{1}", "_Properties", propertyAlias), result.ErrorMessage);
}
else
{
//there's assigned field names so we'll combine the field name with the property name
// so that we can try to match it up to a real sub field of this editor
foreach (var field in result.MemberNames)
{
modelState.AddModelError(string.Format("{0}.{1}.{2}", "_Properties", propertyAlias, field), result.ErrorMessage);
}
}
}
public static IDictionary ToErrorDictionary(this System.Web.Http.ModelBinding.ModelStateDictionary modelState)
{
var modelStateError = new Dictionary();
foreach (var keyModelStatePair in modelState)
{
var key = keyModelStatePair.Key;
var errors = keyModelStatePair.Value.Errors;
if (errors != null && errors.Count > 0)
{
modelStateError.Add(key, errors.Select(error => error.ErrorMessage));
}
}
return modelStateError;
}
///
/// Serializes the ModelState to JSON for JavaScript to interrogate the errors
///
///
///
public static JsonResult ToJsonErrors(this ModelStateDictionary state)
{
return new JsonResult
{
Data = new
{
success = state.IsValid.ToString().ToLower(),
failureType = "ValidationError",
validationErrors = from e in state
where e.Value.Errors.Count > 0
select new
{
name = e.Key,
errors = e.Value.Errors.Select(x => x.ErrorMessage)
.Concat(
e.Value.Errors.Where(x => x.Exception != null).Select(x => x.Exception.Message))
}
}
};
}
}
}