2

タイプBarのMyPropというプロパティを持つFooというモデルがあります。このモデルをコントローラーに投稿するとき、モデル バインダーでMyPropを検証する必要があります。これは、文字列の場合と同様に Required 属性があるためです。これを Bar クラス内または別のクラスとして自己完結型にする必要があります。Barクラスで IValidatableObject を使用しようとしましたが、 FooクラスがMyPropにRequired属性を持っているかどうかを確認することは不可能のようです。だから今、私には選択肢がなく、助けが必要です。以下は私の質問のサンプルコードです。

public class Foo {
    [Required]
    public Bar MyProp { get; set; }
}

public class Bar {
    [ScaffoldColumn(false)]
    public int Id { get; set; }
    public string Name { get; set; }
}
4

3 に答える 3

2

これは、組み込みの必須属性を使用してもカスタム動作を取得できるという私の問題に対する1つの解決策です。これは、概念コードの証明にすぎません。

モデル:

public class Page : IPageModel {
    [Display(Name = "Page", Prompt = "Specify page name...")]
    [Required(ErrorMessage = "You must specify a page name")]
    public PageReference PageReference { get; set; }
}

モデル バインダー:

public class PageModelBinder : DefaultModelBinder {
    protected override void OnModelUpdated(ControllerContext controllerContext, ModelBindingContext bindingContext) {
        foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(bindingContext.ModelType)) {
            var attributes = property.Attributes;
            if (attributes.Count == 0) continue;
            foreach (var attribute in attributes) {
                if (attribute.GetType().BaseType == typeof(ValidationAttribute) && property.PropertyType == typeof(PageReference)) {
                    var pageReference = bindingContext.ModelType.GetProperty(property.Name).GetValue(bindingContext.Model, null) as PageReference;
                    Type attrType = attribute.GetType();
                    if (attrType == typeof (RequiredAttribute) && string.IsNullOrEmpty(pageReference.Name)) {
                        bindingContext.ModelState.AddModelError(property.Name,
                            ((RequiredAttribute) attribute).ErrorMessage);
                    }
                }
            }
        }
        base.OnModelUpdated(controllerContext, bindingContext);
    }
}

モデル バインダー プロバイダー:

public class InheritanceAwareModelBinderProvider : Dictionary<Type, IModelBinder>, IModelBinderProvider {
    public IModelBinder GetBinder(Type modelType) {
        var binders = from binder in this
                      where binder.Key.IsAssignableFrom(modelType)
                      select binder.Value;

        return binders.FirstOrDefault();
    }
}

最後に、global.asax の登録を行います。

var binderProvider = new InheritanceAwareModelBinderProvider {
    {
        typeof (IPageModel), new PageModelBinder() }
    };
ModelBinderProviders.BinderProviders.Add(binderProvider);

結果: http://cl.ly/IjCS

では、このソリューションについてどう思いますか?

于 2012-08-13T19:36:42.623 に答える
0

問題は、呼び出される html フィールドがなくMyProp、MVC がこのプロパティの検証を開始しないことです。

目標を達成する 1 つの方法は、 でプロパティを削除Barして作成することです。AutoMapperを使用して、配管コードを最小限に抑えることができます。Bar'sFoo

別の解決策は、値に対して検証するカスタム検証属性を作成し、属性nullの代わりに使用することRequiredです。

于 2012-08-12T22:57:15.440 に答える
0

解決策 1

を使用する代わりに[Required]、カスタムを試してくださいValidationAttribute

public class Foo {
    [RequiredBar]
    public Bar MyProp { get; set; }
}

public class Bar {
    [ScaffoldColumn(false)]
    public int Id { get; set; }
    public string Name { get; set; }
}

public class RequiredBar : ValidationAttribute {

    public override bool IsValid(object value)
    {
        Bar bar = (Bar)value;

        // validate. For example
        if (bar == null)
        {
            return false;
        }

        return bar.Name != null;
    }
}

解決策 2:

Bar の対応する必要なプロパティを設定するだけRequiredです。たとえば、

public class Foo {
    //[RequiredBar]
    public Bar MyProp { get; set; }
}

public class Bar {
    [ScaffoldColumn(false)]
    public int Id { get; set; }

    [Required]
    public string Name { get; set; }
}
于 2012-08-13T05:51:29.653 に答える