Model Warnings in ASP.NET MVC

后端 未结 3 586
名媛妹妹
名媛妹妹 2021-02-06 10:13

I\'m currently using the ModelStateDictionary in asp.net mvc to hold validation errors and pass then back to the user. Being able to check if the whole model is valid with Model

相关标签:
3条回答
  • 2021-02-06 10:50

    So the route that I was headed down before turned out to be a bad idea, there just isn't enough access in the framework to get at the bits that you need. At least not without reinventing the wheel a few times.

    I decided to head down the route of extending the ModelState class to add a warnings collection to it:

    public class AetherModelState : ModelState
    {
        public AetherModelState() { }
    
        public AetherModelState(ModelState state)
        {
            this.AttemptedValue = state.AttemptedValue;
    
            foreach (var error in state.Errors)
                this.Errors.Add(error);
        }
    
        private ModelErrorCollection _warnings = new ModelErrorCollection();
    
        public ModelErrorCollection Warnings { get { return this._warnings; } }
    }
    

    In order to be able to easily add warnings in the same way that you would errors I created some extension methods for the ModelStateDictionary:

    public static class ModelStateDictionaryExtensions
    {
        public static void AddModelWarning(this ModelStateDictionary msd, string key, Exception exception)
        {
            GetModelStateForKey(key, msd).Warnings.Add(exception);
        }
    
        public static void AddModelWarning(this ModelStateDictionary msd, string key, string errorMessage)
        {
            GetModelStateForKey(key, msd).Warnings.Add(errorMessage);
        }
    
        private static AetherModelState GetModelStateForKey(string key, ModelStateDictionary msd)
        {
            ModelState state;
            if (string.IsNullOrEmpty(key))
                throw new ArgumentException("key");
    
            if (!msd.TryGetValue(key, out state))
            {
                msd[key] = state = new AetherModelState();
            }
    
            if (!(state is AetherModelState))
            {
                msd.Remove(key);
                msd[key] = state = new AetherModelState(state);
            }
    
            return state as AetherModelState;
        }
    
        public static bool HasWarnings(this ModelStateDictionary msd)
        {
            return msd.Values.Any<ModelState>(delegate(ModelState modelState)
            {
                var aState = modelState as AetherModelState;
                if (aState == null) return true;
                return (aState.Warnings.Count == 0);
            });
        }
    }
    

    The GetModelStateForKey code is ropey but you should be able to see where I'm headed with this. The next thing to do is to write some extension methods that allow me to display the warnings along with the errors

    0 讨论(0)
  • 2021-02-06 11:01

    I used the solution from Simon Farrow as a starting point to make the warnings work with Kendo's datasource. By default you can return and show Data OR Errors but I wanted to return and show Data AND Warnings. So I've wrapped Kendo's DataSourceResult and added another extension method which returns the collected warnings.

    // The wrapper
    public class DataSourceResultWithWarnings: DataSourceResult
    {
        public object Warnings { get; }
    
        public DataSourceResultWithWarnings(DataSourceResult dataSourceResult, IDictionary<string, IDictionary<string, IList<string>>> warnings)
        {
            this.AggregateResults = dataSourceResult.AggregateResults;
            this.Data = dataSourceResult.Data;
            this.Errors = dataSourceResult.Errors;
            this.Total = dataSourceResult.Total;
            Warnings = warnings;
        }
    }
    
    // The extension method
    public static IDictionary<string, IDictionary<string, IList<string>>> GetWarnings(this ModelStateDictionary msd)
    {
        var result = new Dictionary<string, IDictionary<string, IList<string>>>();
    
        for (var i = 0; i < msd.Values.Count; i++)
        {
            var wms = msd.Values.ElementAt(i) as WarningModelState;
            if (wms != null)
            {
                if (!result.ContainsKey(msd.Keys.ElementAt(i)))
                {
                    result.Add(msd.Keys.ElementAt(i), new Dictionary<string, IList<string>>() { { "warnings", new List<string>() } });
                }
                result[msd.Keys.ElementAt(i)]["warnings"].AddRange((from rec in wms.Warnings select rec.ErrorMessage));
            }
        }
    
        return result;
    }
    
    // How to use it in the controller action
    var result = new DataSourceResultWithWarnings(files.Values.ToDataSourceResult(request, ModelState), ModelState.GetWarnings());
    return Json(result, JsonRequestBehavior.AllowGet);
    
    0 讨论(0)
  • 2021-02-06 11:09

    Why not simply add a list of warnings, or a dictionary, to the ViewData and then display them in your view?

    e.g.

    ViewData[ "warnings" ] = new[] { "You need to snarfle your aardvark" } ;
    
    0 讨论(0)
提交回复
热议问题