在ASP MVC3用的ViewModels使用[RequiredIf](Using [Require

2019-09-23 02:17发布

我使用的是由西蒙·因斯创建的自定义属性RequiredIf在我的MVC应用程序。

我有被传递给这样的观点一个视图模型:

public class HistoryViewModel
{
    public Contact ContactModel { get; set; }
    public Account AccountModel { get; set; }
    public Person PersonModel { get; set; }
 }

我有一大堆的型号,在他们所有的道具(即contact.cs,account.cs,person.cs)

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public bool IsAdult { get; set; }        
    [RequiredIf("IsAdult", "Yes", Errormessage="Please leave a comment")]
    public string Comments { get; set; }
 }

RequiredIf验证似乎并不时通过视图模型传递给合作。 如果我直接移动属性到视图模型,它工作正常. All other . All other [必填]`从模型属性的工作,通过视图模型。

所以,我需要把所有的属性到视图模型,需要对他们的RequiredIf? 或者是有没有解决这个另一种方式?

Answer 1:

您是否尝试过MVC万无一失验证 ? 它与客户端支持RequiredIf支持(和公平其他一些)。 它有时是有点马车,但最新的版本是不坏。

作品中相同的方式,与上述(其中I I之前试图切换到万无一失)

   public bool Married { get; set; }

    [RequiredIfTrue("Married")]
    public string MaidenName { get; set; }


Answer 2:

问题

如果你看一下你的Razor视图发出的HTML,你会看到什么样的问题在这里。

如果没有一个视图模型 ,我们应生成以下代码(清理一点点):

<input type="checkbox" name="IsAdult" id="IsAdult" />
<input type="text" name="Comments" id="Comments"
       data-val-requiredif-dependprop="IsAdult" 
       data-val-requiredif-value="Yes"
       data-val-requiredif="Please leave a comment" />

随着视图模型 ,我们得到这样的:

<input type="checkbox" name="PersonModel.IsAdult" id="PersonModel_IsAdult" />
<input type="text" name="PersonModel.Comments" id="PersonModel_Comments"
       data-val-requiredif-dependprop="IsAdult" 
       data-val-requiredif-value="Yes"
       data-val-requiredif="Please leave a comment" />

每当属性被嵌套在另一个属性,MVC将建立前缀的堆栈生成唯一的ID和名称。 您可以在第一种情况看, IsAdult足以识别领域,但是一旦被嵌套,该ID已更改。 在不显眼的验证(存储在属性中的规则),需要我们需要可能知道如何验证一个元素都相处在发送的data-attributes ,包括如何定位等性能。

解决方案

在类不应该知道或关心什么情况下它被称为下,因此它会继续盲目地指出相对属性所依赖的数据属性:

public bool IsAdult { get; set; }
[RequiredIf("IsAdult", "Yes", Errormessage="Please leave a comment")]
public string Comments { get; set; }

所以我们必须建立在服务器或客户端上的上下文。

在服务器 -都能跟得上!

作为你的一部分public class RequiredIfAttribute : ValidationAttribute, IClientValidatable ,你必须发出一个看起来像这样的客户端验证规则的方法:

public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
    ModelClientValidationRule requiredIfRule = new ModelClientValidationRule();
    requiredIfRule.ErrorMessage = ErrorMessageString;
    requiredIfRule.ValidationType = "requiredif";
    requiredIfRule.ValidationParameters.Add("dependprop", this._propertyName);
    requiredIfRule.ValidationParameters.Add("value", Json.Encode(this._value));     

    yield return requiredIfRule;
}

这里的诱惑将是导航viewContext.ViewData.TemplateInfo返回GetFullHtmlFieldId ,但是从我所知道的,这个信息是尚未公布 。

客户端 -靠不住的,但工作:

在客户端,我们连线了,看起来方法的适配器是这样的 :

$.validator.unobtrusive.adapters.add('requiredif', ['dependprop', 'value'], function (options) {
    options.rules["requiredif"] = { 
        id: '#' + options.params['dependprop'],
        value: JSON.parse(options.params.value) 
    };
    options.messages['requiredif'] = options.message;
});

请注意,这还只是采用普通的旧属性名称,并假定它可以被用来作为ID定位对象。

通过做一些合理的假设,我们可以建立完整的依赖属性ID。 它应该始终是该requiredif调用元素是相同的范围内我们确定范围内的财产的情况下(这就是我们如何能够通过反射找到它的服务器上)。

因此,我们将抓住从发件人这种情况下,删除该属性的名称,和我们自己的附加这样的内部$.validator.unobtrusive.adapters.add

var curId = options.element.id;               // get full id      i.e. ViewModel_Comments
var context = curId.replace(/[^_]+$/, "");    // remove last prop i.e. ViewModel_
var targetProp = options.params['dependprop'] // target name      i.e. IsAdult
var targetId = '#' + context + targetProp;    // build target ID  i.e. #ViewModel_IsAdult

options.rules["requiredif"] = {
    id: targetId,
    value: JSON.parse(options.params.value)
};

这将有助于找到合适的客户端的属性 - 然后写任何其他条件需要满足。



文章来源: Using [RequiredIf] in ASP MVC3 with ViewModels