Проверка формы ASP.NET MVC. Как вы делаете это на объекте, не являющемся моделью?

У меня есть представление с моделью BlogPostViewModel:

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

Это представление отображается при выборе метода действия 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 });
    }

Моя проблема с проверкой. Как проверить эту форму? Модель вида на самом деле была BlogPostViewModel. Я новичок в проверке и запутался. Форма использует строго типизированные помощники для привязки к свойству NewComment элемента BlogPostViewModel, и я также включил помощники проверки.

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

Как в методе действия AddComment реализовать проверку? Когда я обнаружу Model.IsValid == false, что тогда? Что мне вернуть? Этот метод действия привязывается только к свойству PostComment начального объекта BlogPostViewModel страницы, потому что мне не нужны никакие другие свойства этой модели.


person Chev    schedule 17.03.2011    source источник


Ответы (3)


Вам нужно повторно заполнить модель и отправить на просмотр. Однако вам не нужно делать это вручную, вы можете использовать фильтры действий.

видеть:

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

Конкретно:

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

Использование:

[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");
}
person B Z    schedule 18.03.2011

В своем 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);
person Saxman    schedule 17.03.2011
comment
Однако посмотрите, представление, из которого мы публикуем, — это BlogPost, когда я делаю return View(postComment);, оно говорит The view 'AddComment' or its master was not found, что правильно, потому что это не представление с таким именем. - person Chev; 18.03.2011
comment
Если я делаю return View("BlogPost", postComment);, он кричит на меня за то, что я не указал правильный тип модели, то есть BlogPostViewModel. Означает ли это, что я должен создать BlogPostViewModel и вернуть его только для проверки? Если да, означает ли это также, что я должен заполнить свойство BlogPost в модели представления, иначе информация о сообщении в блоге исчезнет на странице при ее отображении для отображения ошибок проверки? - person Chev; 18.03.2011
comment
Вы также можете передать View в параметре, т.е. return View("BlogPost", postComment"); - person Saxman; 18.03.2011
comment
Я публиковал свой комментарий одновременно с вашим... Смотрите мой обновленный ответ. - person Saxman; 18.03.2011

Потратив много времени, я понял, что мне нужно повторно заполнить модель представления и отобразить правильное представление, передав полностью заполненную модель. Немного больно, но, по крайней мере, я понимаю, что происходит.

person Chev    schedule 17.03.2011