Как я могу собрать сообщения об ошибках проверки модели? - PullRequest
1 голос
/ 27 июня 2011

Я создаю приложение ASP.NET MVC и пытаюсь найти способ, с помощью которого я могу собрать данные от пользователя в пользовательской модели представления, попробовать установить эти значения для одной или нескольких моих сущностей, затем на основе при проверке логики этих объектов соберите сообщения об ошибках, если они есть, и верните их в представление. Я новичок в MVC и веб-дизайне в целом, поэтому вполне возможно, что я делаю серьезные концептуальные ошибки, но я пытался исследовать, насколько мог.

Я понимаю, что это больше, чем просто строгое представление вида к сущности, где было бы легко отобразить ошибки проверки, как в этого руководства. Однако я не Я не хочу делать это в целях безопасности и потому, что есть места, где я хочу, чтобы значения собирались из одной модели представления для установки в нескольких различных объектах.

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

Таким образом, мой план состоит в том, чтобы правила валидации были установлены для самой сущности и чтобы модель представления представляла собой тупой контейнер. Затем в другом месте приложения я бы применил значения из модели представления к моей сущности (объектам) в соответствии с моей бизнес-логикой. На этом этапе я бы хотел, чтобы моя логика проверки была вызвана. Если данные недействительны, я планирую установить строку ошибки в пользовательском атрибуте модели представления на ошибку из логики проверки на объекте. Я думаю, что это будет примерно так:

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? Я знаю, что могу использовать отражение, чтобы получить доступ к атрибутам . Если бы я мог изменить их, как бы я это сделал?

Заранее благодарю за помощь. Я прошу прощения, если я неправильно понял что-то большое.

1 Ответ

1 голос
/ 28 июня 2011

Кажется, вы немного усложняете ситуацию.Я думаю, что вы хотите сделать, чтобы предотвратить привязку связывателя модели к свойствам, которые он не должен иметь, а также сохранить возможность проверки 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.Поскольку ваша сущность наследуется от интерфейса фильтра привязки, ее экземпляр будет удовлетворять этому требованию.Механизм связывания модели с радостью свяжется со свойствами интерфейса, совершенно не обращая внимания на любые другие свойства, которые может иметь объект вашей модели.

Подробнее см. в этом блоге .

Помимо

Иногда бывает легко столкнуться с неоднозначностью методов действия, когда у вас есть два метода действия с одинаковым именем;один для 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, чтобы использовать ее в качестве источника привязки, если хотите, но вам это не нужно, так как она все равно будет использоваться по умолчанию для коллекции форм запроса.Но так как вы передаете его внутрь, вы также можете использовать его:)

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