7

我目前在 asp.net mvc 中使用 ModelStateDictionary 来保存验证错误,然后传递给用户。尤其是能够使用 ModelState.IsValid 检查整个模型是否有效。但是,我正在处理的当前应用程序需要能够报告警告。这些并不那么重要,因此仍然可以保存表单内容,但它们应该显示给用户,以便可以选择采取行动。

我一直在查看框架,看看是否有任何明显的地方可以扩展它以允许我这样做。我在想另一个带有警告的字典和一个模型错误的子类,称为模型警告。我不确定如何让框架在视图等中使用我的新容器类。不过,我仍然希望所有现有的错误内容都能正常工作。

如果有人尝试过类似的事情或有任何想法,我会很感激他们的意见。

更新:

我已经扩展了 ViewDataDictionary 以添加一些警告

public class AetherViewDataDictionary : ViewDataDictionary
{
    public AetherViewDataDictionary()
    {
        ModelStateWarning = new ModelStateDictionary();
    }

    public AetherViewDataDictionary(object model) : base(model)
    {
        ModelStateWarning = new ModelStateDictionary();
    }

    public AetherViewDataDictionary(ViewDataDictionary viewDataDictionary) : base(viewDataDictionary) 
    {
        ModelStateWarning = new ModelStateDictionary();
    }

    public ModelStateDictionary ModelStateWarning { get; private set; }
}

我现在遇到的问题是,当我看到我的视图代码时,这只是为了调试,我失去了它是我的新类型的事实,所以当我尝试将它转换回来并访问我的新字典时我没有快乐。

public partial class Index : ViewPage<PageViewData>
{
    protected override void SetViewData(ViewDataDictionary viewData)
    {
        base.SetViewData(viewData);
    }
}

它在这里正确设置,但是当我检查类型时它消失了。

编辑:事实证明这是一种愚蠢的做事方式,请参阅下面的答案。

4

3 回答 3

6

所以我之前的路线被证明是一个坏主意,框架中没有足够的访问权限来获取您需要的位。至少不是没有重新发明轮子几次。

我决定继续扩展 ModelState 类以向其添加警告集合:

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; } }
}

为了能够以与错误相同的方式轻松添加警告,我为 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);
        });
    }
}

GetModelStateForKey 代码很复杂,但您应该能够看到我的目标。接下来要做的是编写一些扩展方法,允许我显示警告和错误

于 2008-12-16T09:14:42.470 回答
4

为什么不简单地向 ViewData 添加警告列表或字典,然后在视图中显示它们?

例如

ViewData[ "warnings" ] = new[] { "You need to snarfle your aardvark" } ;
于 2008-12-15T12:00:39.110 回答
0

我使用 Simon Farrow 的解决方案作为起点,使警告与 Kendo 的数据源一起工作。默认情况下,您可以返回并显示DataOR Errors,但我想返回并显示DataAND Warnings。所以我包装了 KendoDataSourceResult并添加了另一个扩展方法,它返回收集的警告。

// 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);
于 2018-10-17T07:41:57.927 回答