如何收集模型验证错误消息?

时间:2011-06-27 17:12:14

标签: c# asp.net-mvc-3

我正在构建一个ASP.NET MVC应用程序,我正在尝试找到一种方法,我可以在自定义视图模型中从用户收集数据,尝试将这些值设置为我的一个或多个实体,然后基于在这些实体上的验证逻辑上,收集错误消息(如果有)并将它们返回到视图。我是MVC和网页设计的新手,因此我很有可能犯了重大的概念错误,但我尽可能地尝试研究。

我意识到这比将视图强烈输入到实体更为重要,因为在this tutorial.中可以很容易地显示验证错误。但是,我不想这样做这是为了安全,因为在某些地方,我希望从单个视图模型中收集值,以便在多个不同的实体中进行设置。

我也意识到我可以在视图模型本身上设置验证规则,而不是在实体上设置验证规则,但这似乎是糟糕的体系结构,因为我必须在不同的视图模型中冗余地定义它们,然后我会更少确定我是否已阻止将错误值保留到数据库中。

因此,我的计划是在实体本身上设置验证规则,并将视图模型设置为哑容器。然后,在应用程序的不同位置,我将根据我的业务逻辑将视图模型中的值应用于我的实体。此时,我希望调用我的验证逻辑。如果数据无效,我计划将视图模型上自定义属性中的错误字符串设置为实体上验证逻辑的错误。我想它会是这样的:

public class CustomViewModel()
{
    [SomeCustomValidation()] //Has a place for an error string and a boolean IsValid
    String Property { get; set; }
}


public class BusinessLogic()
{
    CustomViewModel TestForValidity(CustomViewModel viewModel)
    {

        MyEntity.Property = viewModel.Property;
        // if(MyEntity.IsValid)?  catch SomeSortOfException?
        // collect error message, put it in the attribute on the view model, set IsValid to false
    }
}

public class MyEntity()
{
    [MoreCustomValidation()]
    public String Property { get; set; }
}

因此我有三个问题:

  1. 当我尝试传递不符合我的验证规则的数据时,会抛出某种错误或异常吗?当我尝试传递无效数据时,是否有一些迹象表明我可以使用或收集?

  2. 如果出现错误或异常,我该如何收集错误消息以便将其分配给我的视图模型?

  3. 最重要的是,我是否认为这一切都错了?是否可以在运行时修改属性,例如包含新的错误消息或将IsValid更改为false?我知道我可以使用反射来access the attributes。如果我可以修改它们,我该怎么做?

  4. 提前感谢您的帮助。如果我误解了一些重大事件,我会道歉。

1 个答案:

答案 0 :(得分:1)

看起来你可能会使事情过于复杂化。我认为你想要做的是阻止模型绑定器绑定到它不应该具有的属性,并保留在模型上的属性不满足其验证要求时检查ModelState.IsValid的能力。属性。

IMO实现这一目标的最佳方法是使用我称之为“强类型绑定过滤器”。首先定义一个接口,其中只包含您希望模型绑定器可以绑定到模型上的属性。

public interface INewBlogPost
{
    string Title { get; set; }
    string Body { get; set; }
}

然后确保您的实体从绑定过滤器接口继承。

public class BlogPost : INewBlogPost
{
    ...
}

接下来,修改您的操作方法以创建新实体,并在将模型绑定器键入您刚刚定义的界面时手动调用模型绑定器。

public ActionMethod NewBlogPost()
{
    BlogPost newBlogPost = new BlogPost();
    TryUpdateModel<INewBlogPost>(newBlogPost);
    if (ModelState.IsValid)
    {
        ...
    }
}

因为您在通过TryUpdateModel调用模型绑定器时传入了一个类型,所以您明确告诉模型绑定器要绑定的类型。这意味着模型绑定器只能访问界面中列出的属性。现在,当您将模型传递给要绑定的方法时,它必须是INewBlogPost类型。因为您的实体继承自绑定过滤器接口,所以它的实例将满足此要求。模型绑定器将很乐意绑定到接口上的属性,完全忽略模型对象可能具有的任何其他属性。

有关详细信息,请参阅this blog post

除了

当您有两个具有相同名称的操作方法时,有时很容易遇到操作方法歧义;一个用于POST,一个用于GET,如下所示:

[HttpGet]
public ActionResult NewBlogPost()
{
     return View();
}

[HttpPost]
public ActionResult NewBlogPost()
{
     BlogPost newBlogPost = new BlogPost();
     TryUpdateModel<INewBlogPost>(newBlogPost);
     if (ModelState.IsValid) { ... }
}

一种简单的解决方法是将POST操作方法修改为:

[HttpPost]
public ActionResult NewBlogPost(FormCollection formCollection)
{
     BlogPost newBlogPost = new BlogPost();
     TryUpdateModel<INewBlogPost>(newBlogPost, formCollection);
     if (ModelState.IsValid) { ... }
}

MVC模型绑定器知道如何将请求表单集合绑定到类型FormCollection的参数,因此它将填充这个就好了。因为您的POST操作现在接受一个参数,所以它与您的GET方法不再含糊不清。如果您愿意,可以将此formCollection传递给TryUpdateModel以用作绑定源,但您不必这样做,因为它无论如何都会默认为请求表单集合。但是既然你传递了它,你也可以使用它:)