[必須]属性をList <>プロパティに配置することは可能ですか?
POSTの汎用リストにバインドし、プロパティに0個のアイテムがある場合にModelState.IsValid()を失敗させることができるかどうか疑問に思っていましたか?
Required
属性をリストスタイルのプロパティに追加しても、実際には期待どおりの結果が得られません。リストが作成されていない場合は文句を言いますが、リストに0個のアイテムが含まれている場合は文句を言いません。
ただし、独自のデータ注釈属性を導出し、リストでCount
> 0をチェックするのは簡単なはずです。次のようなもの(まだテストされていません):
_[AttributeUsage(AttributeTargets.Property)]
public sealed class CannotBeEmptyAttribute : ValidationAttribute
{
private const string defaultError = "'{0}' must have at least one element.";
public CannotBeEmptyAttribute ( ) : base(defaultError) //
{
}
public override bool IsValid ( object value )
{
IList list = value as IList;
return ( list != null && list.Count > 0 );
}
public override string FormatErrorMessage ( string name )
{
return String.Format(this.ErrorMessageString, name);
}
}
_
編集:
また、ビューでリストをバインドする方法にも注意する必要があります。たとえば、_List<String>
_を次のようなビューにバインドする場合:
_<input name="ListName[0]" type="text" />
<input name="ListName[1]" type="text" />
<input name="ListName[2]" type="text" />
<input name="ListName[3]" type="text" />
<input name="ListName[4]" type="text" />
_
MVCモデルバインダーは常にリストに5つの要素を入れます。すべて_String.Empty
_です。これがビューの動作方法である場合、Reflectionを使用してジェネリック型パラメーターをプルし、各リスト要素をdefault(T)
などと比較するなど、属性をもう少し複雑にする必要があります。
より良い代替方法は、jQueryを使用して入力要素を動的に作成することです。
ミニマリストの例を探している人のために:
[AttributeUsage(AttributeTargets.Property)]
public sealed class CannotBeEmptyAttribute : RequiredAttribute
{
public override bool IsValid(object value)
{
var list = value as IEnumerable;
return list != null && list.GetEnumerator().MoveNext();
}
}
これは、受け入れられた回答から変更されたコードです。 IEnumerableはSystem.Collections階層の上位にあるため、質問の場合、さらに多くの場合に適しています。さらに、RequiredAttributeから動作を継承するため、明示的にコーディングする必要はありません。
C#6.0(およびそれ以降)を使用していて、ワンライナーを探している人の場合:
[AttributeUsage(AttributeTargets.Property)]
public sealed class CannotBeEmptyAttribute : RequiredAttribute
{
public override bool IsValid(object value) => (value as IEnumerable)?.GetEnumerator().MoveNext() ?? false;
}
私の要件に合わせて@moudrickの実装を変更しました
リストとチェックボックスリストに必要な検証属性
[AttributeUsage(AttributeTargets.Property)]
public sealed class CustomListRequiredAttribute : RequiredAttribute
{
public override bool IsValid(object value)
{
var list = value as IEnumerable;
return list != null && list.GetEnumerator().MoveNext();
}
}
チェックボックスリストがある場合
[AttributeUsage(AttributeTargets.Property)]
public sealed class CustomCheckBoxListRequiredAttribute : RequiredAttribute
{
public override bool IsValid(object value)
{
bool result = false;
var list = value as IEnumerable<CheckBoxViewModel>;
if (list != null && list.GetEnumerator().MoveNext())
{
foreach (var item in list)
{
if (item.Checked)
{
result = true;
break;
}
}
}
return result;
}
}
これが私のビューモデルです
public class CheckBoxViewModel
{
public string Name { get; set; }
public bool Checked { get; set; }
}
使用法
[CustomListRequiredAttribute(ErrorMessage = "Required.")]
public IEnumerable<YourClass> YourClassList { get; set; }
[CustomCheckBoxListRequiredAttribute(ErrorMessage = "Required.")]
public IEnumerable<CheckBoxViewModel> CheckBoxRequiredList { get; set; }