Как проверить мою модель в пользовательской привязке модели?C#

Место общения программистов C#
Ответить
Anonymous
 Как проверить мою модель в пользовательской привязке модели?

Сообщение Anonymous »


Я спросил здесь о проблеме с числовыми значениями, разделенными запятыми.

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

пространство имен MvcApplication1.Core { общедоступный класс PropertyModelBinder: DefaultModelBinder { общедоступный объект переопределения BindModel (ControllerContext контроллерКонтекст, ModelBindingContext привязкаКонтекст) { объект objectModel = новый объект(); если (bindingContext.ModelType == typeof(PropertyModel)) { Запрос HttpRequestBase = контроллерКонтекст.HttpContext.Request; строка цена = request.Form.Get("Цена").Replace(",", string.Empty); ModelBindingContext newBindingContext = новый ModelBindingContext() { ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType( () => новая МодельСвойства() { Цена = Convert.ToInt32(цена) }, тип (МодельСвойства) ), ModelState =bindingContext.ModelState, ValueProvider =bindingContext.ValueProvider }; // вызываем связыватель модели по умолчанию в этом новом контексте связывания return base.BindModel(controllerContext, newBindingContext); } еще { return base.BindModel(controllerContext,bindingContext); } } //защищенный объект переопределения CreateModel(ControllerContext контроллерКонтекст, ModelBindingContext привязкаКонтекст, Тип modelType) //{ // //возвращаем base.CreateModel(controllerContext,bindingContext, modelType); // Модель PropertyModel = новая PropertyModel(); // if (modelType == typeof(PropertyModel)) // { // модель = (PropertyModel)base.CreateModel(controllerContext,bindingContext, modelType); // Запрос HttpRequestBase = контроллерКонтекст.HttpContext.Request; // строка цена = request.Form.Get("Цена").Replace(",", string.Empty); // модель.Цена = Convert.ToInt32(цена); // } // возвращаем модель; //} } } И обновил свой класс контроллера следующим образом:

пространство имен MvcApplication1.Controllers { общедоступный класс PropertyController: Контроллер { публичный ActionResult Edit() { Модель PropertyModel = новая PropertyModel { Имя Агента = "Джон Доу", BuildingStyle = "Колониальный", Год постройки = 1978, Цена = 650000, Идентификатор = 1 }; вернуть представление (модель); } [HttpPost] public ActionResult Edit([ModelBinder(typeof(PropertyModelBinder))] Модель PropertyModel) { если (ModelState.IsValid) { //Сохраняем информацию о свойстве. } вернуть представление (модель); } общественный ActionResult О () { ViewBag.Message = "Страница описания вашего приложения."; вернуть просмотр(); } общедоступный контакт ActionResult() { ViewBag.Message = "Ваша страница контактов."; вернуть просмотр(); } } } Теперь, если я введу цену с запятыми, моя пользовательская привязка модели удалит запятые, это то, что я хочу, но проверка все равно не удастся. Итак, вопрос: Как выполнить пользовательскую проверку в моей пользовательской привязке модели, чтобы можно было избежать захваченного значения цены с запятыми? Другими словами, я подозреваю, что мне нужно сделать больше в моей подшивке пользовательской модели, но не знаю, как и что. Спасибо.
Изображение


Обновление:

Итак, я попробовал решение @mare по адресу https://stackoverflow.com/a/2592430/97109 и обновил связующую модель следующим образом:

пространство имен MvcApplication1.Core { общедоступный класс PropertyModelBinder: DefaultModelBinder { общедоступный объект переопределения BindModel (ControllerContext контроллерКонтекст, ModelBindingContext привязкаКонтекст) { объект objectModel = новый объект(); если (bindingContext.ModelType == typeof(PropertyModel)) { Запрос HttpRequestBase = контроллерКонтекст.HttpContext.Request; строка цена = request.Form.Get("Цена").Replace(",", string.Empty); ModelBindingContext newBindingContext = новый ModelBindingContext() { ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType( () => новая МодельСвойства() { Цена = Convert.ToInt32(цена) }, тип (МодельСвойства) ), ModelState =bindingContext.ModelState, ValueProvider =bindingContext.ValueProvider }; // вызываем связыватель модели по умолчанию в этом новом контексте связывания объект o = base.BindModel(controllerContext, newBindingContext); newBindingContext.ModelState.Remove("Цена"); newBindingContext.ModelState.Add("Цена", новый ModelState()); newBindingContext.ModelState.SetModelValue("Цена", новый ValueProviderResult(цена, цена, ноль)); вернуться о; } еще { return base.BindModel(controllerContext,bindingContext); } } //защищенный объект переопределения CreateModel(ControllerContext контроллерКонтекст, ModelBindingContext привязкаКонтекст, Тип modelType) //{ // //возвращаем base.CreateModel(controllerContext,bindingContext, modelType); // Модель PropertyModel = новая PropertyModel(); // if (modelType == typeof(PropertyModel)) // { // модель = (PropertyModel)base.CreateModel(controllerContext,bindingContext, modelType); // Запрос HttpRequestBase = контроллерКонтекст.HttpContext.Request; // строка цена = request.Form.Get("Цена").Replace(",", string.Empty); // модель.Цена = Convert.ToInt32(цена); // } // возвращаем модель; //} } } Вроде как это работает, но если я введу 0 в качестве цены, модель снова станет действительной, что неверно, поскольку у меня есть аннотация диапазона, в которой говорится, что минимальная цена равна 1. В конце концов.

Обновление:

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

с использованием System.ComponentModel.DataAnnotations; пространство имен MvcApplication1.Models { общедоступный класс PropertyRegistrationViewModel { публичная регистрация свойствViewModel() { } публичная собственность Property { get; набор; } общественный агент Агент {получить; набор; } } собственность общественного класса { общественный ИНТ HouseNumber {получить; набор; } общественная строка Street { get; набор; } публичная строка City { get; набор; } публичная строка State {get; набор; } общественная строка Zip {get; набор; } [Обязательно(ErrorMessage="Вы должны ввести цену.")] [Диапазон(1000, 10000000, ErrorMessage="Плохая цена.")] общественный ИНТ Цена {получить; набор; } } Агент общественного класса { общественная строка FirstName {get; набор; } общественная строка LastName {get; набор; } [Обязательно(ErrorMessage="Вы должны ввести годовой объем продаж.")] [Диапазон(10000, 5000000, ErrorMessage="Неверный диапазон.")] общественный ИНТ AnnualSales {получить; набор; } публичный адрес Адрес {get; набор; } } Адрес публичного класса { общественная строка Line1 {get; набор; } общественная строка Line2 {получить; набор; } } } А вот контроллер:

с использованием MvcApplication1.Core; использование MvcApplication1.Models; использование System.Web.Mvc; пространство имен MvcApplication1.Controllers { открытый класс RegistrationController: Контроллер { публичный индекс ActionResult() { PropertyRegistrationViewModel viewModel = новый PropertyRegistrationViewModel (); вернуть представление (viewModel); } [HttpPost] public ActionResult Index([ModelBinder(typeof(PropertyRegistrationModelBinder))]PropertyRegistrationViewModel viewModel) { если (ModelState.IsValid) { //сохраняем регистрацию. } вернуть представление (viewModel); } } } Вот реализация привязки пользовательской модели:

с использованием MvcApplication1.Models; использование системы; использование System.Collections.Generic; используя System.Linq; использование System.Web; использование System.Web.Mvc; пространство имен MvcApplication1.Core { общедоступный класс PropertyRegistrationModelBinder: DefaultModelBinder { защищенный переопределяемый объект GetPropertyValue( Контекст контроллераКонтекст контроллера, ModelBindingContext привязкаContext, System.ComponentModel.PropertyDescriptor propertyDescriptor, Свойство IModelBinderBinder) { если (propertyDescriptor.ComponentType == typeof(PropertyRegistrationViewModel)) { if (propertyDescriptor.Name == "Свойство") { var цена = привязкаContext.ValueProvider.GetValue("Свойство.Цена").AttemptedValue.Replace(",", string.Empty); вар свойство = новое свойство (); // Вопрос 1: Цена — единственное свойство, которое я хочу изменить. Там в любом случае // чтобы мне не приходилось вручную заполнять остальные свойства таким образом? свойство.Цена = строка.IsNullOrWhiteSpace(цена)? 0: Convert.ToInt32(цена); property.HouseNumber = Convert.ToInt32(bindingContext.ValueProvider.GetValue("Property.HouseNumber").AttemptedValue); property.Street =bindingContext.ValueProvider.GetValue("Property.Street").AttemptedValue; property.City =bindingContext.ValueProvider.GetValue("Property.City").AttemptedValue; property.State =bindingContext.ValueProvider.GetValue("Property.State").AttemptedValue; property.Zip =bindingContext.ValueProvider.GetValue("Property.Zip").AttemptedValue; // Я думал, что когда этот объект свойства вернется, наша аннотация свойства Price // будет учитываться связующим устройством модели, но не проверяет его соответствующим образом. вернуть имущество; } if (propertyDescriptor.Name == "Агент") { var sales =bindingContext.ValueProvider.GetValue("Agent.AnnualSales").AttemptedValue.Replace(",", string.Empty); вар агент = новый агент (); // Вопрос 2: AnnualSales — единственное свойство, которое мне нужно обработать перед проверкой, // Можно ли как-нибудь избежать утомительного заполнения остальных свойств? агент.AnnualSales = string.IsNullOrWhiteSpace(продажи)? 0: Convert.ToInt32(продажи); агент.FirstName = привязкаContext.ValueProvider.GetValue("Агент.FirstName").AttemptedValue; агент.LastName = привязкаContext.ValueProvider.GetValue("Агент.LastName").AttemptedValue; адрес вар = новый адрес(); адрес.Строка1 =bindingContext.ValueProvider.GetValue("Агент.Адрес.Строка1").AttemptedValue + " ROC"; адрес.Строка2 =bindingContext.ValueProvider.GetValue("Агент.Адрес.Строка2").AttemptedValue + " MD"; агент.Адрес = адрес; // Я думал, что когда этот объект агента вернется, наша аннотация свойства AnnualSales // будет учитываться связующим устройством модели, но не проверяет его соответствующим образом. возвратный агент; } } return base.GetPropertyValue(controllerContext, BidingContext, PropertyDescriptor, PropertyBinder); } защищенное переопределение void OnModelUpdated (ControllerContext контроллерКонтекст, ModelBindingContext привязкаКонтекст) { модель вар = привязкаContext.Model как PropertyRegistrationViewModel; //Чтобы проверить нашу модель, похоже, нам придется проверить ее вручную. base.OnModelUpdated(controllerContext,bindingContext); } } } А вот вид Razor:

@model MvcApplication1.Models.PropertyRegistrationViewModel @{ ViewBag.Title = "Регистрация собственности"; } Регистрация недвижимости Введите информацию о своем объекте недвижимости и агенте ниже.
@using (Html.BeginForm("Индекс", "Регистрация")) { @Html.ValidationSummary(); Информация об объекте Номер дома @Html.TextBoxFor(m => m.Property.HouseNumber)
Улица @Html.TextBoxFor(m => m.Property.Street)
Город @Html.TextBoxFor(m => m.Property.City)
Состояние @Html.TextBoxFor(m => m.Property.State)
Zip @Html.TextBoxFor(m => m.Property.Zip)
Цена @Html.TextBoxFor(m => m.Property.Price)
Информация об агенте Имя @Html.TextBoxFor(m => m.Agent.FirstName)
Фамилия @Html.TextBoxFor(m => m.Agent.LastName)
Годовые продажи @Html.TextBoxFor(m => m.Agent.AnnualSales)
Адрес агента L1@Html.TextBoxFor(m => m.Agent.Address.Line1)
Адрес агента L2@Html.TextBoxFor(m => m.Agent.Address.Line2)
}
А вот файл global.asax, в котором я подключаю привязку пользовательской модели. Кстати, кажется, этот шаг не нужен, потому что я заметил, что он все еще работает без этого шага.

с использованием MvcApplication1.Core; использование MvcApplication1.Models; используя System.Web.Http; использование System.Web.Mvc; использование System.Web.Optimization; использование System.Web.Routing; пространство имен MvcApplication1 { // Примечание. Инструкции по включению классического режима IIS6 или IIS7 см. // посетите http://go.microsoft.com/?LinkId=9394801 общедоступный класс MvcApplication: System.Web.HttpApplication { защищенный недействительный Application_Start() { Регистрация Зоны.РегистрацияВсеОбласти(); WebApiConfig.Register(GlobalConfiguration.Configuration); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); AuthConfig.RegisterAuth(); ModelBinders.Binders.Add(typeof(PropertyRegistrationViewModel), новый PropertyRegistrationModelBinder()); } } } Возможно, я делаю что-то не так или недостаточно. Я заметил следующие проблемы:
Хотя мне нужно изменить только значение Price объекта свойства, похоже, мне придется утомительно заполнять все остальные свойства в привязке модели. Мне нужно сделать то же самое для свойства AnnualSales свойства агента. Можно ли как-нибудь этого избежать в подшивке модели? Я думал, что метод BindModel по умолчанию будет учитывать нашу аннотацию свойств наших объектов и соответствующим образом проверять их после вызова GetPropertyValue, но это не так. Если я введу какое-то значение, выходящее за пределы диапазона, для объекта «Цена объекта недвижимости» или объекта «Годовые продажи объекта агента», модель снова станет действительной. Другими словами, аннотации диапазона игнорируются. Я знаю, что могу проверить их, переопределив OnModelUpdated в пользовательской привязке модели, но это слишком много работы, и, кроме того, у меня есть аннотации, почему реализация привязки модели по умолчанию не учитывает их только потому, что я переопределяю часть этого?
@dotnetstep: Не могли бы вы пояснить это? Спасибо.
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»