Есть ли способ заставить модель пройти повторную проверку в контроллере MVC3? - PullRequest
2 голосов
/ 10 ноября 2011

У меня есть Модель, которая содержит Адрес и Персона дважды, один раз для «основного» контакта и один раз для «счета-фактуры», а также логическое значение InvoiceContactSameAsMain - неуклюжее имя, но описательное. Получатель свойства проверяет, совпадают ли объекты Address и Contact для «main» и «invoice», и возвращает true, если они есть. Установщик проверяет, является ли значение истинным, и, если это так, копирует основного человека по лицу счета и главный адрес по адресу счета.

В моем представлении логическое значение представлено флажком (как и следовало ожидать). К этому добавлена ​​небольшая JS-функция, которая, если установлен этот флажок, скрывает поля счета и «отключает» проверку на стороне клиента, устанавливая для атрибута HTML data-val значение false и вынуждая повторный анализ ненавязчивого Атрибуты проверки в форме. Если флажок снят, поля естественным образом отображаются и снова включается проверка.

Все это прекрасно работает, пока я не доберусь до моего контроллера.

Несмотря на то, что Модель является «действительной» и содержит правильные поля (благодаря моему установщику InvoiceContactSameAsMain), ModelState.IsValid остается абсолютно ложным, и я не могу найти какой-либо способ для повторной проверки модели. Если я очищаю ModelState, все ошибки исчезают. Я бы предпочел не копаться в полях ModelState по именам, поскольку объекты Person и Address используются в проекте и могут потребовать изменения или расширения в какой-то момент.

Есть ли что-то очевидное, что я здесь упустил, что позволит мне заново проверить ModelState? Я пробовал TryUpdateModel и TryValidateModel, но они оба используют кэшированные значения ModelState. Я даже попытался рекурсивно вызвать мой Action снова, передав «фиксированную» модель. Я почти благодарен, что один не сработал.

Пожалуйста, дайте мне знать, если какие-либо подробности или примеры помогут.

Редактировать: Очевидно, что если это совершенно неправильный подход к проблеме, просто дайте мне знать.

Редактировать 2: Добавлены примеры кода в соответствии с предложением Рона Сайма.

Модель выглядит следующим образом: публичный класс Подробнее { публичный int? UserID {get; задавать; }

    public Company Company { get; set; }

    public Address CompanyAddress { get; set; }
    public Person MainPerson { get; set; }

    public Address InvoiceAddress { get; set; }
    public Person InvoiceContact { get; set; }

    [Display(Name = "Promotional code")]
    [StringLength(20, ErrorMessage = "Promotional code should not exceed 20 characters")]
    public string PromotionalCode { get; set; }

    [Display(Name = "Invoice contact same as main")]
    public bool InvoiceContactSameasMain
    {
        get { return InvoiceContact.Equals(MainPerson); }
        set
        {
            if (value)
            {
                InvoiceContact = MainPerson.Copy();
                InvoiceAddress = CompanyAddress.Copy();
            }
        }
    }

    [_Common.MustAccept]
    [Display(Name = "I agree with the Privacy Policy")]
    public bool PrivacyFlag { get; set; }

    [Display(Name = "Please subscribe to Sodexo News Letter")]
    public bool MarketingOption { get; set; }

    [Display(Name = "Contract number")]
    public int? ContractNumber { get; set; }

    public Details()
    {
        Company = new Company();
        CompanyAddress = new Address();
        MainPerson = new Person();
        InvoiceAddress = new Address();
        InvoiceContact = new Person();
    }
}

Это обернуто в ViewModel, так как на странице задействовано несколько списков выбора:

public class DetailsViewModel
{
    public Details    Details              { get; set; }
    public SelectList MainContactTitles    { get; set; }
    public SelectList InvoiceContactTitles { get; set; }
    public SelectList SICCodes             { get; set; }
    public SelectList TypesOfBusiness      { get; set; }
    public SelectList NumbersOfEmployees    { get; set; }

    public DetailsViewModel()
    {
    }
}

Два соответствующих действия Контроллера заключаются в следующем:

public class DetailsController : _ClientController
{
    [Authorize]
    public ActionResult Index()
    {
        DetailsViewModel viewModel = new DetailsViewModel();
        if (Client == null)
        {
            viewModel.Details = DetailsFunctions.GetClient((int)UserId, null);
        }
        else
        {
             viewModel.Details = DetailsFunctions.GetClient((int)UserId, Client.ContractNumber);
        }
        viewModel.MainContactTitles = DetailsFunctions.GetTitles((int)UserId, viewModel.Details.MainPerson.title);
        viewModel.InvoiceContactTitles = DetailsFunctions.GetTitles((int)UserId, viewModel.Details.InvoiceContact.title);
        viewModel.SICCodes = DetailsFunctions.GetSICCodes(viewModel.Details.Company.sic_code);
        viewModel.NumbersOfEmployees = DetailsFunctions.GetNumbersOfEmployees(viewModel.Details.Company.number_of_employees);
        viewModel.TypesOfBusiness = DetailsFunctions.GetTypesOfBusiness(viewModel.Details.Company.public_private);
        return View(viewModel);
    }

    [Authorize]
    [HttpPost]
    public ActionResult Index(DetailsViewModel ViewModel)
    {
        if (ModelState.IsValid)
        {
            //go to main page for now
            DetailsFunctions.SetClient((int)UserId, ViewModel.Details);
            return RedirectToAction("Index", "Home");
        }
        else
        {
            ViewModel.MainContactTitles = DetailsFunctions.GetTitles((int)UserId, ViewModel.Details.MainPerson.title);
            ViewModel.InvoiceContactTitles = DetailsFunctions.GetTitles((int)UserId, ViewModel.Details.InvoiceContact.title);
            ViewModel.SICCodes = DetailsFunctions.GetSICCodes(ViewModel.Details.Company.sic_code);
            ViewModel.NumbersOfEmployees = DetailsFunctions.GetNumbersOfEmployees(ViewModel.Details.Company.number_of_employees);
            ViewModel.TypesOfBusiness = DetailsFunctions.GetTypesOfBusiness(ViewModel.Details.Company.public_private);
            return View(ViewModel);
        }
    }
}

Я могу предоставить представление и JS, если это необходимо, но, поскольку привязка Model все работает просто отлично, я не уверен, какая это помощь.

1 Ответ

3 голосов
/ 11 ноября 2011

Это хак с умеренным дерьмом, но в итоге я просто очистил ошибки ModelState для соответствующих полей в контроллере перед проверкой ModelState.IsValid:

if(ViewModel.Details.InvoiceContactSameasMain)
        {
            //iterate all ModelState values, grabbing the keys we want to clear errors from
            foreach (string Key in ModelState.Keys)
            {
                if (Key.StartsWith("Details.InvoiceContact") || Key.Startwith("Details.InvoiceAddress"))
                {
                    ModelState[Key].Errors.Clear();
                }
            }
        }

Единственным преимуществом является то, что если объекты Person или Address изменятся, этот код не нужно будет изменять.

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