ASP.NET MVC3: отображение ошибок проверки из дочернего представления в родительском представлении - PullRequest
2 голосов
/ 11 августа 2011

Я пытаюсь добавить форму, чтобы пользователи могли комментировать сообщения в моем приложении для ведения блогов.Пока что я добавил форму в представление сведений о сообщении и могу отправлять комментарии, правильно добавляя их в свою базу данных.Однако у меня есть проблема с отображением ошибок проверки пользователю.Форма комментария содержится в частичном представлении и отображается с использованием Html.RenderAction в представлении сведений о сообщении.Я хотел бы подчеркнуть, что я не хочу использовать AJAX для этого, поскольку я хотел бы подойти к этому с точки зрения прогрессивного улучшения.

Вот соответствующее действие публикации:

[HttpPost, Authorize]
public ActionResult AddComment(CommentViewModel newComment)
{
    if (ModelState.IsValid)
    {
        Comment comment = new Comment(_userRepository.GetByUsername(User.Identity.Name));
        Mapper.Map(newComment, comment);

        _commentRepository.Add(comment);

        _postsRepository.CommentAdded(comment.Article);

        return RedirectToAction("Index", new { id = newComment.PostID });
    }

    // What do I do here?
}

Я пробовал несколько способов возврата представлений здесь, но моя проблема еще больше усложняется проверкой некоторых параметров контроллера, которую я выполняю в родительском действии:

//
// GET: /Posts/5/this-is-a-slug

public ActionResult Index(int id, string slug)
{
    PostViewModel viewModel = new PostViewModel();
    var model = _postsRepository.GetByID(id);

    if (model != null)
    {
        if (slug == null || slug.CompareTo(model.Slug) != 0)
        {
            return RedirectToActionPermanent("Index", new { id, slug = model.Slug });
        }
        else
        {
            _postsRepository.PostVisited(model);

            Mapper.Map(model, viewModel);

            viewModel.AuthorName = _userRepository.GetById(model.AuthorID);
        }
    }

    return View(viewModel);
}

Это действие в основном имитируеткак работают URL-адреса SO.Если указан идентификатор сообщения, оно извлекается из базы данных вместе со слагом, который создается при создании сообщения.Если слаг в URL не совпадает с тем, который содержится в базе данных, он перенаправляется для включения слага.Это работает хорошо, но это означает, что у меня возникают проблемы при попытке заполнить мою родительскую модель представления, а именно:

public class PostViewModel
{
    public int PostID { get; set; }
    public string Title { get; set; }
    public string Body { get; set; }
    public string Slug { get; set; }
    public DateTime DatePublished { get; set; }
    public int NumberOfComments { get; set; }
    public int AuthorID { get; set; }
    public string AuthorName { get; set; }

    public List<CommentViewModel> Comments { get; set; }
    public CommentViewModel NewComment { get; set; }
}

Я надеялся, что это сработает, это заполнение PostViewModel.NewComment, тест на просмотресли он имеет данные, а затем использует их для отображения ошибок модели.К сожалению, я заблудился относительно того, как этого добиться. Этот вопрос помог мне сформировать свой подход, но он не совсем ответил на мою проблему.

Может ли кто-нибудь мягко подтолкнуть меня в правильном направлении?Если мой подход кажется необоснованным, я хотел бы выяснить, почему и каким будет потенциальное решение проблемы.

Большое спасибо заранее.

1 Ответ

2 голосов
/ 25 октября 2011

Забыл заполнить мой ответ здесь.Для всех, кто случайно наткнулся на это, ответом было использование TempData для хранения ошибок ModelState, а затем повторное заполнение ModelState в соответствующем действии контроллера.контроллер, который будет использоваться для ссылки на данные внутри TempData.Я решил основывать это на типе CommentViewModel, поскольку оба действия зависят от него.

public class PostsController : Controller
{
    private static readonly string commentFormModelStateKey = typeof(CommentViewModel).FullName;
    // Rest of class.
}

В этом первом действии код проверяет, содержит ли TempData данные, назначенные клавише.Если это так, он копируется в ModelState.

// GET: /posts/comment
[ChildActionOnly]
public PartialViewResult Comment(PostViewModel viewModel)
{
    viewModel.NewComment = new CommentViewModel(viewModel.PostID, viewModel.Slug);

    if (TempData.ContainsKey(commentFormModelStateKey))
    {
        ModelStateDictionary commentModelState = TempData[commentFormModelStateKey] as ModelStateDictionary;
        foreach (KeyValuePair<string, ModelState> valuePair in commentModelState)
            ModelState.Add(valuePair.Key, valuePair.Value);
    }

    return PartialView(viewModel.NewComment);
}

Это действие определяет, действителен ли ModelState перед добавлением комментария в базу данных.Если ModelState недействителен, он копируется в TempData, что делает его доступным для первого действия.

// POST: /posts/comment
[HttpPost, Authorize]
public ActionResult Comment(CommentViewModel newComment)
{
    if (!ModelState.IsValid)
    {
        TempData.Add(commentFormModelStateKey, ModelState);
        return Redirect(Url.ShowPost(newComment.PostID, newComment.Slug));
    }

    // Code to add a comment goes here.
}
...