Современный способ обработки и проверки POST-данных в MVC 2 - PullRequest
2 голосов
/ 05 мая 2010

В MVC много статей, посвященных работе с данными, и ничего о MVC 2.

Итак, мой вопрос: как правильно обработать POST-запрос и проверить его.

Предположим, у нас есть 2 действия. Оба они работают над одним и тем же объектом, но каждое действие имеет свой отдельный набор свойств объекта, которые должны быть связаны автоматически. Например:

  • Действие «А» должно связывать только свойство «Имя» объекта, взятое из POST-запроса
  • Действие "B" должно связывать только свойство "Date" объекта, взятое из POST-запроса

Насколько я понимаю, мы не можем использовать атрибут Bind в этом случае.

Итак, каковы лучшие практики в MVC2 для обработки POST-данных и, вероятно, для их проверки?

UPD
После выполненных действий - к объектам будет применена дополнительная логика, чтобы они стали действительными и были готовы к сохранению в постоянном слое. Для действия «А» - это установка даты до текущей даты.

Ответы [ 2 ]

3 голосов
/ 05 мая 2010

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

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

ПРИМЕЧАНИЕ. Я оставил способ сочетания опубликованных моделей видов с моделью основного вида в качестве упражнения для вас, поскольку есть несколько способов приблизиться к нему

public class ActionAViewModel
{
    [Required(ErrorMessage="Please enter your name")]
    public string Name { get; set; }
}

public class ActionBViewModel
{
    [Required(ErrorMessage="Please enter your date")]
    // You could use a regex or custom attribute to do date validation,
    // allowing you to have a custom error message for badly formatted
    // dates
    public string Date { get; set; }
}

public class PageViewModel
{
    public ActionAViewModel ActionA { get; set; }
    public ActionBViewModel ActionB { get; set; }
}

public class PageController
{
    public ActionResult Index()
    {
        var viewModel = new PageViewModel
        {
            ActionA = new ActionAViewModel { Name = "Test" }
            ActionB = new ActionBViewModel { Date = DateTime.Today.ToString(); }
        };

        return View(viewModel);
    }

    // The [Bind] prefix is there for when you use 
    // <%= Html.TextBoxFor(x => x.ActionA.Name) %>
    public ActionResult ActionA(
        [Bind(Prefix="ActionA")] ActionAViewModel viewModel)
    {
        if (ModelState.IsValid)
        {
            // Load model, update the Name, and commit the change
        }
        else
        {
            // Display Index with viewModel
            // and default ActionBViewModel
        }
    }

    public ActionResult ActionB(
        [Bind(Prefix="ActionB")] ActionBViewModel viewModel)
    {
        if (ModelState.IsValid)
        {
            // Load model, update the Date, and commit the change
        }
        else
        {
            // Display Index with viewModel
            // and default ActionAViewModel
        }
    }
}
2 голосов
/ 06 мая 2010

Одним из возможных способов обработки данных POST и добавления проверки является использование связывателя пользовательской модели. Вот небольшой пример того, что я недавно использовал для добавления пользовательской проверки данных POST-формы:

public class Customer
{
    public string Name { get; set; }
    public DateTime Date { get; set; }
}


public class PageController : Controller
{
    [HttpPost]
    public ActionResult ActionA(Customer customer)
    {
        if(ModelState.IsValid) {
        //do something with the customer
        }
    }

    [HttpPost]
    public ActionResult ActionB(Customer customer)
    {
       if(ModelState.IsValid) { 
       //do something with the customer
       }
    }
}

CustomerModelBinder будет выглядеть примерно так:

    public class CustomerModelBinder : DefaultModelBinder
{
    protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, System.ComponentModel.PropertyDescriptor propertyDescriptor)
    {
        if (propertyDescriptor.Name == "Name") //or date or whatever else you want
        {


            //Access your Name property with valueprovider and do some magic before you bind it to the model.
            //To add validation errors do (simple stuff)
            if(string.IsNullOrEmpty(bindingContext.ValueProvider.GetValue("Name").AttemptedValue))
                bindingContext.ModelState.AddModelError("Name", "Please enter a valid name");

            //Any complex validation
        }
        else
        {
            //call the usual binder otherwise. I noticed that in this way you can use DataAnnotations as well.
            base.BindProperty(controllerContext, bindingContext, propertyDescriptor); 
        }
    }

и в global.asax поставить

ModelBinders.Binders.Add(typeof(Customer), new CustomerModelBinder());

Если вы не хотите связывать свойство Name (просто Date) при вызове ActionB, просто сделайте еще один пользовательский связыватель модели и в операторе if поместите для возврата значение null или уже существующее значение ты хочешь. Затем в контроллере положите:

[HttpPost]
public ActionResult([ModelBinder(typeof(CustomerAModelBinder))] Customer customer)

[HttpPost]
public ActionResult([ModelBinder(typeof(CustomerBModelBinder))] Customer customer)

Где customerAmodelbinder будет связывать только имя, а customerBmodelbinder будет связывать только дату.

Это самый простой способ, который я нашел, для проверки привязки модели, и я достиг некоторых очень крутых результатов с моделями сложного вида. Могу поспорить, что есть что-то, что я пропустил, и, возможно, более опытный может ответить. Надеюсь, я правильно понял ваш вопрос ...:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...