Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/264.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 无法强制要求列表_C#_Asp.net_Asp.net Mvc_Entity Framework - Fatal编程技术网

C# 无法强制要求列表

C# 无法强制要求列表,c#,asp.net,asp.net-mvc,entity-framework,C#,Asp.net,Asp.net Mvc,Entity Framework,我试图使用数据注释将验证添加到模型中不能为空的列表中。我尝试了几种自定义属性的实现,包括和 我的看法是: <div class="form-group"> @* Model has a list of ints, LocationIDs *@ @Html.LabelFor(model => model.LocationIDs, htmlAttributes: new { @class = "control-label col-md-2" }) <d

我试图使用数据注释将验证添加到模型中不能为空的列表中。我尝试了几种自定义属性的实现,包括和

我的看法是:

<div class="form-group">
    @* Model has a list of ints, LocationIDs *@
    @Html.LabelFor(model => model.LocationIDs, htmlAttributes: new { @class = "control-label col-md-2" })
    <div class="col-md-10">
        <select class="select2 form-control" multiple id="LocationIDs" name="LocationIDs">
            @* Adds every possible option to select box *@
            @foreach (LocationModel loc in db.Locations)
            {
                <option value="@loc.ID">@loc.Name</option>
            }
        </select>
        @Html.ValidationMessageFor(model => model.LocationIDs, "", new { @class = "text-danger" })
    </div>
</div>
我尝试过的功能相同的属性之一:

[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();
    }
}
当前,即使未选择任何内容,检查null或空列表也会通过验证。在这种情况下,将绑定一个长度为1的列表,其中包含第一个选项


我已经确认控制器实际上发送了一个长度为1的列表。然而,我不知道如何改变这种行为。我仍然认为这可能是下面的整句话所描述的

我想我的问题可以在中描述,但我不知道如何解决它

摘录如下:

您还必须注意如何在视图中绑定列表。 例如,如果将列表绑定到如下视图:

MVC模型绑定器将始终在您的 列表,全部为String.Empty。如果视图是这样工作的,那么属性 将需要变得更复杂一些,例如使用反射来拉动 泛型类型参数,并将每个列表元素与 违约之类的


您可以尝试使用一个类型构造验证器,并验证列表中的任何iten是否与您的类型的默认值不同。 更改您提到的示例:

你的CannotBeEmptyAttribute很好。我使用了完全相同的代码,它工作得非常完美。确保将视图模型更改为使用它,而不是使用在本例中不起作用的必需视图模型

除非您实现自定义属性,否则它不会为您提供客户端验证。这意味着表单将被发布,即使它无效,但如果ModelState.IsValid将捕获它。您是否使用调试器查看IsValid是否为false

对于服务器端验证来说,手动创建输入完全可以,但是客户端无法工作,因为缺少必要的数据属性

以下是一个表单的最低版本,该表单包含手动创建的多选输入,可与CannotBeemptyaAttribute一起使用:


我能得到零选择以实际绑定为null的唯一方法是使用Html.listbox,我一开始就不知道这是什么–从一开始就应该这样做:

@Html.ListBoxFor(model => model.SelectedLocations, Model.AllLocations, new { @class = "select2 form-control" })

我还没有让客户端验证正常工作,但我会将其作为另一个问题发布。

您是在尝试验证最终用户是否在select中选择了一个项目,还是在尝试验证该模型。LocationID中有条目,还是两者都有?我想两者都有。客户端将是select,服务器端将是model.LocationIDs。我对automagic验证属性没有100%透彻的了解,但我确实知道,数据批注可以防止保存无效值,但同时也会向最终用户提供错误消息。@mjwills我如何编辑我的问题以使其更清楚?我怀疑ValidationMessageFor可能对前者有所帮助,但对后者没有帮助。如果您想了解valdation,那么我建议你从我不手动创建我想要的selectbox开始-除了扩展HtmlHelper之外,我看不到任何方法,但是我对源代码的探索并没有帮助我创建任何比Html.SimpleTextwords更高级的东西。SimpleTextwords将单词内置到某个字符串中并返回。不,还是不知道为什么。不过,它确实适用于某些种子值,实际上我已经在数据库初始值设定项中将列表设置为null。当我自己发送表单时,IsValid为true。不过,我不知道如何检查发送给控制器的值。我所能想到的是,它实际上正在发送一个列表,其中包含最终保存的第一项。但我不知道如何解决这个问题。选择一个项目是为了有效。我已经确认控制器实际上发送了一个长度为1的列表。然而,我不知道如何改变这种行为。我仍然认为这可能是上面的整句话所描述的。
[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();
    }
}
<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" /> 
public class CannotBeEmptyAttribute : ValidationAttribute
{
    private const string defaultError = "'{0}' must have at least one element.";

    public Type ListType { get; private set; }

    protected CannotBeEmptyAttribute(Type listType) : base(defaultError)
    {
        this.ListType = listType;
    }

    public override bool IsValid(object value)
    {
        object defaultValue = ListType.IsValueType ? Activator.CreateInstance(ListType) : null;

        IEnumerable list = value as IEnumerable;

        if (list != null)
        {
            foreach (var item in list)
            {
                if(item != defaultValue)
                {
                    return true;
                }
            }
        }
        return false;            
    }

    public override string FormatErrorMessage(string name)
    {
        return String.Format(this.ErrorMessageString, name);
    }
}
@using (Html.BeginForm("TestPost", "Home"))
{
    <select multiple="multiple" name="TestList">
        <option value="1">One</option>
        <option value="2">Two</option>
        <option value="3">Three</option>
    </select>
    @Html.ValidationMessage("TestList")
    @Html.ValidationSummary()

    <input type="submit" value="Save"/>
}
@Html.ListBoxFor(model => model.SelectedLocations, Model.AllLocations, new { @class = "select2 form-control" })