ASP.NET MVC 3 - Как я могу условно проверить (IValidatableObject) при вызове UpdateModel или TryUpdateModel? - PullRequest
0 голосов
/ 29 января 2011

Я использую EFCodeFirst CTP5 (хотя это не должно иметь значения) и ASP.NET MVC 3. Я создал следующие объекты:

public class Company
{
    public int CompanyID { get; set; }    
    public int SubdomainID { get; set; }
    public virtual Subdomain Subdomain { get; set; }    
}

public class Subdomain : IValidatableObject
{
    public int SubdomainID { get; set; }    
    public virtual ICollection<SubdomainActivity> Activities { get; set; }    
    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        int activitySum = Activities.Sum(x => x.Value);
        if (activitySum != 100)
        {
            yield return new ValidationResult(string.Format("The Activity percentages must add up to 100. Current sum is {0}", activitySum), new[] { "Activities" });
        }
    }    
}
public class SubdomainActivity
{        
    public int ActivityID { get; set; }    
    public int Value { get; set; }
}

Обратите внимание, что Company имеет Subdomain, а Subdomain имеет ICollection<SubdomainActivity>.

У меня есть контроллеры для Company и Subdomain. В SubdomainController, когда я вызываю UpdateModel() (или TryUpdateModel()) для экземпляра Subdomain, я получаю желаемый результат. Действия Subdomain подтверждаются тем, что значения составляют до 100.

В CompanyController, когда я вызываю UpdateModel() для экземпляра Company, он подтверждает, что Subdomain.Activities также добавляет до 100, что мне не нужно. Пользователь не может даже редактировать Subdomain.Activites из вида редактирования Company, поэтому нет смысла сообщать им, что произошла ошибка с Subdomain.Activities.

Я хотел бы иметь возможность добавить элемент в IDictionary validationContext.Items, чтобы я мог выполнять условную проверку на основе контекста или чего-то подобного, но я не смог понять, как это сделать, не написав собственный IModelBinder (что я мог бы сделать, я полагаю, но кажется излишним). В конечном счете, я нашел этот обходной путь в CompanyController, но я уверен, что есть правильный способ справиться с этим (это обернуто в try catch)

var d = this.companyRepository.GetById(id);
bool good = TryUpdateModel(d);
if (!good)
{
    if (ModelState.ContainsKey("Subdomain.Activities"))       
        ModelState.Remove("Subdomain.Activities");        
    if (!ModelState.IsValid)
        throw new InvalidOperationException(string.Format("The model of type '{0}' could not be updated.", typeof(Company).FullName));
}
this.companyRepository.Save();

В качестве интересного примечания: если я не проверю правильность модели и не выдаю ошибку, то companyRepository.Save () работает нормально. Другими словами, EFCodeFirst, кажется, не вызывает Validate на поддомене, но MVC UpdateModel делает.

Может кто-нибудь помочь мне с лучшим / правильным / рекомендуемым способом справиться с этим?

Ответы [ 2 ]

0 голосов
/ 28 февраля 2011
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
    int activitySum = Activities.Sum(x => x.Value);
    if (activitySum != 100)
    {
        yield return new ValidationResult(string.Format("The Activity percentages must add up to 100. Current sum is {0}", activitySum), new[] { "Activities" });
    }
}  

как насчет изменения вашего метода Validate (), как показано ниже?

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
    int activitySum = Activities.Sum(x => x.Value);
    if (Activities.Count != 0 && activitySum != 100)
    {
        yield return new ValidationResult(string.Format("The Activity percentages must add up to 100. Current sum is {0}", activitySum), new[] { "Activities" });
    }
}  
0 голосов
/ 31 января 2011

Я нашел способ справиться с этим немного более изящно. Вместо реализации IValidatableObject в Subdomain я просто использую атрибут [CustomValidation] в свойстве Activity субдомена. Это НЕ вызывается при проверке экземпляра Company в моем вопросе, и я все еще получаю свою специализированную проверку действий. Надеюсь, это когда-нибудь кому-нибудь поможет.

public class Subdomain
{
    public int SubdomainID { get; set; }

    [CustomValidation(typeof(Subdomain), "ValidateActivities")]
    public virtual ICollection<SubdomainActivity> Activities { get; set; }
    public static ValidationResult ValidateActivities(ICollection<SubdomainActivity> activities)
    {
        if (activities.Count > 0)
        {
            int activitySum = activities.Sum(x => x.Value);
            if (activitySum != 100)
            {
                return new ValidationResult(string.Format("The Activity percentages must add up to 100. Current sum is {0}", activitySum), new[] { "Activities" });
            }
        }
        return ValidationResult.Success;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...