ASP。净MVC表单验证。如何在非模型对象上做呢?

时间:2022-08-28 04:03:26

I have a view with model BlogPostViewModel:

我对model BlogPostViewModel有一个看法:

public class BlogPostViewModel
{
    public BlogPost BlogPost { get; set; }
    public PostComment NewComment { get; set; }
}

This view is rendered when action method BlogPost is hit. The view displays information regarding the blog post as well as a list of comments on the blog post by iterating over Model.BlogPost.PostComments. Below that I have a form allowing users to post a new comment. This form posts to a different action AddComment.

当单击action方法BlogPost时,将呈现此视图。视图通过遍历Model.BlogPost.PostComments显示关于博客文章的信息以及博客文章的评论列表。下面是一个表单,允许用户发布新的评论。此表单将发布到另一个动作AddComment。

    [HttpPost]
    public ActionResult AddComment([Bind(Prefix = "NewComment")] PostComment postComment)
    {
        postComment.Body = Server.HtmlEncode(postComment.Body);
        postComment.PostedDate = DateTime.Now;
        postCommentRepo.AddPostComment(postComment);
        postCommentRepo.SaveChanges();
        return RedirectToAction("BlogPost", new { Id = postComment.PostID });
    }

My problem is with validation. How do I validate this form? The model of the view was actually BlogPostViewModel. I'm new to validation and am confused. The form uses the strongly-typed helpers to bind to the NewComment property of BlogPostViewModel and I included the validation helpers as well.

我的问题是验证。我如何验证这个表单?视图的模型实际上是BlogPostViewModel。我对验证并不熟悉,也很困惑。表单使用强类型的助手绑定到BlogPostViewModel的NewComment属性,我还包括了验证助手。

@using (Html.BeginForm("AddComment", "Blog")
{
    <div class="formTitle">Add Comment</div>
    <div>
        @Html.HiddenFor(x => x.NewComment.PostID) @* This property is populated in the action method for the page. *@
        <table>
            <tr>
                <td>
                    Name:
                </td>
                <td>
                    @Html.TextBoxFor(x => x.NewComment.Author)
                </td>
                <td>
                    @Html.ValidationMessageFor(x => x.NewComment.Author)
                </td>
            </tr>
            <tr>
                <td>
                    Email:
                </td>
                <td>
                    @Html.TextBoxFor(x => x.NewComment.Email)
                </td>
                <td>
                    @Html.ValidationMessageFor(x => x.NewComment.Email)
                </td>
            </tr>
            <tr>
                <td>
                    Website:
                </td>
                <td>
                    @Html.TextBoxFor(x => x.NewComment.Website)
                </td>
                <td>
                    @Html.ValidationMessageFor(x => x.NewComment.Website)
                </td>
            </tr>
            <tr>
                <td>
                    Body:
                </td>
                <td>
                    @Html.TextAreaFor(x => x.NewComment.Body)
                </td>
                <td>
                    @Html.ValidationMessageFor(x => x.NewComment.Body)
                </td>
            </tr>
            <tr>
                <td>
                </td>
                <td>
                    <input type="submit" value="Add Comment" />
                </td>
            </tr>
        </table>
    </div>
}

How in the AddComment action method do I implement validation? When I detect Model.IsValid == false then what? What do I return? This action method is only binding to the PostComment property of the pages initial BlogPostViewModel object because I don't care about any other properties on that model.

如何在AddComment操作方法中实现验证?当我发现模型。IsValid == false,然后呢?我回报什么?此操作方法仅绑定到page initial BlogPostViewModel对象的PostComment属性,因为我不关心该模型上的任何其他属性。

Any help is appreciated.

任何帮助都是感激。

3 个解决方案

#1


2  

You need to repopulate the model and send to view. However, you don't need to do this by hand, you can use action filters.

您需要重新填充模型并将其发送到view。但是,您不需要手工操作,您可以使用操作过滤器。

see:

看到的:

http://weblogs.asp.net/rashid/archive/2009/04/01/asp-net-mvc-best-practices-part-1.aspx#prg

http://weblogs.asp.net/rashid/archive/2009/04/01/asp网- mvc -最佳实践- 1. aspx # prg一部分

Specifically:

具体地说:

public abstract class ModelStateTempDataTransfer : ActionFilterAttribute
{
    protected static readonly string Key = typeof(ModelStateTempDataTransfer).FullName;
}

public class ExportModelStateToTempData : ModelStateTempDataTransfer
{
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        //Only export when ModelState is not valid
        if (!filterContext.Controller.ViewData.ModelState.IsValid)
        {
            //Export if we are redirecting
            if ((filterContext.Result is RedirectResult) || (filterContext.Result is RedirectToRouteResult))
            {
                filterContext.Controller.TempData[Key] = filterContext.Controller.ViewData.ModelState;
            }
        }

        base.OnActionExecuted(filterContext);
    }
}

public class ImportModelStateFromTempData : ModelStateTempDataTransfer
{
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        ModelStateDictionary modelState = filterContext.Controller.TempData[Key] as ModelStateDictionary;

        if (modelState != null)
        {
            //Only Import if we are viewing
            if (filterContext.Result is ViewResult)
            {
                filterContext.Controller.ViewData.ModelState.Merge(modelState);
            }
            else
            {
                //Otherwise remove it.
                filterContext.Controller.TempData.Remove(Key);
            }
        }

        base.OnActionExecuted(filterContext);
    }
}

Usage:

用法:

[AcceptVerbs(HttpVerbs.Get), ImportModelStateFromTempData]
public ActionResult Index(YourModel stuff)
{
    return View();
}

[AcceptVerbs(HttpVerbs.Post), ExportModelStateToTempData]
public ActionResult Submit(YourModel stuff)
{
    if (ModelState.IsValid)
    {
        try
        {
            //save
        }
        catch (Exception e)
        {
            ModelState.AddModelError(ModelStateException, e);
        }
    }

    return RedirectToAction("Index");
}

#2


0  

In your AddComment ActionResult, do this:

在你的AddComment ActionResult中,这样做:

if(ModelState.IsValid)
{
 // Insert new comment
 ..
 ..
 // Redirect to a different view
}
// Something is wrong, return to the same view with the model & errors 
var postModel = new BlogPostViewModel { PostComment = postComment };
return View(postModel);

#3


0  

After much time spent I have realized that I have to repopulate the view model and render the correct view, passing in the fully-populated model. Kind of a pain but at least I understand what's going on.

在花了很多时间之后,我意识到我必须重新填充视图模型并呈现正确的视图,传递完全填充的模型。有点痛苦,但至少我明白发生了什么。

#1


2  

You need to repopulate the model and send to view. However, you don't need to do this by hand, you can use action filters.

您需要重新填充模型并将其发送到view。但是,您不需要手工操作,您可以使用操作过滤器。

see:

看到的:

http://weblogs.asp.net/rashid/archive/2009/04/01/asp-net-mvc-best-practices-part-1.aspx#prg

http://weblogs.asp.net/rashid/archive/2009/04/01/asp网- mvc -最佳实践- 1. aspx # prg一部分

Specifically:

具体地说:

public abstract class ModelStateTempDataTransfer : ActionFilterAttribute
{
    protected static readonly string Key = typeof(ModelStateTempDataTransfer).FullName;
}

public class ExportModelStateToTempData : ModelStateTempDataTransfer
{
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        //Only export when ModelState is not valid
        if (!filterContext.Controller.ViewData.ModelState.IsValid)
        {
            //Export if we are redirecting
            if ((filterContext.Result is RedirectResult) || (filterContext.Result is RedirectToRouteResult))
            {
                filterContext.Controller.TempData[Key] = filterContext.Controller.ViewData.ModelState;
            }
        }

        base.OnActionExecuted(filterContext);
    }
}

public class ImportModelStateFromTempData : ModelStateTempDataTransfer
{
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        ModelStateDictionary modelState = filterContext.Controller.TempData[Key] as ModelStateDictionary;

        if (modelState != null)
        {
            //Only Import if we are viewing
            if (filterContext.Result is ViewResult)
            {
                filterContext.Controller.ViewData.ModelState.Merge(modelState);
            }
            else
            {
                //Otherwise remove it.
                filterContext.Controller.TempData.Remove(Key);
            }
        }

        base.OnActionExecuted(filterContext);
    }
}

Usage:

用法:

[AcceptVerbs(HttpVerbs.Get), ImportModelStateFromTempData]
public ActionResult Index(YourModel stuff)
{
    return View();
}

[AcceptVerbs(HttpVerbs.Post), ExportModelStateToTempData]
public ActionResult Submit(YourModel stuff)
{
    if (ModelState.IsValid)
    {
        try
        {
            //save
        }
        catch (Exception e)
        {
            ModelState.AddModelError(ModelStateException, e);
        }
    }

    return RedirectToAction("Index");
}

#2


0  

In your AddComment ActionResult, do this:

在你的AddComment ActionResult中,这样做:

if(ModelState.IsValid)
{
 // Insert new comment
 ..
 ..
 // Redirect to a different view
}
// Something is wrong, return to the same view with the model & errors 
var postModel = new BlogPostViewModel { PostComment = postComment };
return View(postModel);

#3


0  

After much time spent I have realized that I have to repopulate the view model and render the correct view, passing in the fully-populated model. Kind of a pain but at least I understand what's going on.

在花了很多时间之后,我意识到我必须重新填充视图模型并呈现正确的视图,传递完全填充的模型。有点痛苦,但至少我明白发生了什么。