asp.net mvc 模型状态错误键

asp.net mvc model state errors keys

于是我发现了一个有趣的问题。 我有这样的模型:

public class ApplicantModel
{
    [Display(Name = "Firstname", ResourceType = typeof(Resources))]
    [MaxLength(50, ErrorMessageResourceName = "FirstName", ErrorMessageResourceType = typeof(Validations), ErrorMessage = null)]
    [Required(ErrorMessageResourceName = "FirstName", ErrorMessageResourceType = typeof(Validations), ErrorMessage = null)]
    public string Firstname { get; set; }

    [Display(Name = "Surname", ResourceType = typeof(Resources))]
    [MaxLength(50, ErrorMessageResourceName = "Surname", ErrorMessageResourceType = typeof(Validations), ErrorMessage = null)]
    [Required(ErrorMessageResourceName = "Surname", ErrorMessageResourceType = typeof(Validations), ErrorMessage = null)]
    public string Surname { get; set; }
}

一切都很好,当我检查模型状态并且模型上有错误时,我得到如下信息: 错误:

[{
Key = FirstApplicant.Firstname
Value = ["First name is required field"]
},
{
Key = FirstApplicant.Surname
Value = ["Surname name is required field"]
}].

也可以

编辑: 这是可视化为 JSON 对象的 c# ModelState 对象。实物看起来像这样:

ModelState
{System.Web.Mvc.ModelStateDictionary}
    Count: 2
    IsReadOnly: false
    IsValid: false
    Keys: Count = 2
    Values: Count = 2
    Results View: Expanding the Results View will enumerate the IEnumerable

但是我的问题是。是否有可能以某种方式更改密钥?我知道密钥是作为对象的名称创建的,然后是该对象上的名称 属性。 所以这是有道理的,但是有什么办法可以改变这种默认行为吗?还是我必须更改对象的名称?

编辑2:

我在这里想要实现的是我有一个 c# ViewModel 和 knockout ViewModel。当你进行服务器端验证时,你会得到这个键和值字典,我将其序列化并发送给客户端。 然后我在客户端调用这个函数:

var errors = @Html.Raw(Json.Encode(Model.Errors));
        function showErrors(serializedErrors) {
            var errors = JSON.parse(serializedErrors);
            for (var i = 0; i < errors.length; i++) {
                var error = errors[i];
                var key = error.Key;
                var property = eval("masterModel." + key);
                property.setError(error.Value.ErrorMessage);
                property.isModified(true);
            }
        }
        showErrors(errors);

如果视图模型 属性 名称在服务器和客户端上匹配,这将工作正常。但是例如在服务器端我有一个 FirstApplicant.FirstName 而在客户端它是 ApplicantOne.firstname。谢谢大家的帮助和评论。我希望这次我能更详细地解释我的问题。

最后我找到了解决这个问题的办法。它有点复杂,但它有效。

首先我创建了一个属性。

public class ClientNameAttribute : Attribute, IMetadataAware
{
    public ClientNameAttribute(string name)
    {
        this.Name = name;
    }

    public string Name { get; set; }

    public void OnMetadataCreated(ModelMetadata metadata)
    {
        metadata.AdditionalValues["ClientName"] = this.Name;
    }
}

注意这个属性也实现了IMetadataAware

下一步是创建 Html 助手,这样我就可以在视图中调用它了。

public static class HtmlHelperExtensions
{
    public static string CustomModelState<T>(this HtmlHelper<T> helper)
    {
        var errors = helper.ViewData.ModelState.Select(
            m => new { Key = GenerateClientName(m.Key, helper), Value = m.Value.Errors.FirstOrDefault() }).Where(e=> e.Value != null);

        return Json.Encode(errors);
    }

    private static string GenerateClientName<T>(string key, HtmlHelper<T> helper)
    {
        StringBuilder builder = new StringBuilder();
        int periodIndex = -1;
        do
        {
            periodIndex = key.IndexOf('.', periodIndex + 1);
            string part = key.Substring(0, periodIndex==-1 ? key.Length : periodIndex);
            var partMetadata = ModelMetadata.FromStringExpression(part, helper.ViewData);

            object clientName;
            if (builder.Length > 0)
            {
                builder.Append('.');
            }

            if (partMetadata.AdditionalValues.TryGetValue("ClientName", out clientName))
            {
                builder.Append(clientName);
            }
            else
            {
                builder.Append(partMetadata.PropertyName);
            }
        }
        while (periodIndex != -1);

        return builder.ToString();
    }
}

CustomModelState是我在视图中调用的方法。

像这样:

var errors = @Html.Raw(Html.CustomModelState());
if (errors.length > 0) {
    showErrors("masterModel",errors);
}

这将为您提供格式正确的错误,以及您自定义的属性名称。

下面是测试:

public class TestModel
{
    [Required]
    public string Normal { get; set; }
    [ClientName("Other")]
    [Required]
    public string Changed { get; set; }

    [ClientName("Complicated")]
    public TestModelTwo TestModelTwo { get; set; }
}

public class TestModelTwo
{
    public string PropertyOne { get; set; }

    [ClientName("Two")]
    public string PropertyTwo{ get; set; }
}

[TestClass]
public class HtmlHelperExtensionsTests
{
    [TestMethod]
    public void CustomModelStateTests()
    {
        var model = new TestModel();
        var page = new ViewPage();
        page.ViewData.Model = model;
        page.ViewData.ModelState.AddModelError("Normal", "Error1");
        page.ViewData.ModelState.AddModelError("Changed", "Error2");
        HtmlHelper<TestModel> helper = new HtmlHelper<TestModel>(new ViewContext(), page);
        var custom = helper.CustomModelState();
        string expectedResult =
            "[{\"Key\":\"Normal\",\"Value\":{\"Exception\":null,\"ErrorMessage\":\"Error1\"}},{\"Key\":\"Other\",\"Value\":{\"Exception\":null,\"ErrorMessage\":\"Error2\"}}]";
        Assert.AreEqual(expectedResult, custom);
    }


    [TestMethod]
    public void CustomModelStateTests_ObjectProperty_With_ClientName()
    {
        var model = new TestModel();
        model.TestModelTwo = new TestModelTwo();
        var page = new ViewPage();
        page.ViewData.Model = model;
        page.ViewData.ModelState.AddModelError("TestModelTwo.PropertyOne", "Error1");
        page.ViewData.ModelState.AddModelError("TestModelTwo.PropertyTwo", "Error2");
        HtmlHelper<TestModel> helper = new HtmlHelper<TestModel>(new ViewContext(), page);
        var custom = helper.CustomModelState();
        string expectedResult =
            "[{\"Key\":\"Complicated.PropertyOne\",\"Value\":{\"Exception\":null,\"ErrorMessage\":\"Error1\"}},{\"Key\":\"Complicated.Two\",\"Value\":{\"Exception\":null,\"ErrorMessage\":\"Error2\"}}]";
        Assert.AreEqual(expectedResult, custom);
    }
}