Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/287.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# MVC ICollection<;格式文件>;ValidationState始终设置为Skipped_C#_.net_Validation_Asp.net Core_Asp.net Core Mvc - Fatal编程技术网

C# MVC ICollection<;格式文件>;ValidationState始终设置为Skipped

C# MVC ICollection<;格式文件>;ValidationState始终设置为Skipped,c#,.net,validation,asp.net-core,asp.net-core-mvc,C#,.net,Validation,Asp.net Core,Asp.net Core Mvc,作为ASP.NET核心MVC 1.0项目的一部分,我有一个带有ICollection属性的ViewModel。我需要验证此集合是否包含一个或多个项。未执行我的自定义验证属性 在我的实例中,它保存来自多部分/表单数据的多个文件附件 我已使用自定义验证属性装饰ViewModel中的属性: [RequiredCollection] 公共ICollection附件{get;set;} 下面是自定义属性类。它只是检查集合是否不为null,并且包含大于零的元素: 公共类RequiredCollection

作为ASP.NET核心MVC 1.0项目的一部分,我有一个带有ICollection属性的ViewModel。我需要验证此集合是否包含一个或多个项。未执行我的自定义验证属性

在我的实例中,它保存来自
多部分/表单数据的多个文件附件

我已使用自定义验证属性装饰ViewModel中的属性:

[RequiredCollection]
公共ICollection附件{get;set;}
下面是自定义属性类。它只是检查集合是否不为null,并且包含大于零的元素:

公共类RequiredCollectionAttribute:ValidationAttribute
{
受保护的常量字符串DefaultErrorMessageFormatString=“您必须至少提供一个。”;
public RequiredCollectionAttribute():base(DefaultErrorMessageFormatString){}
受保护的重写ValidationResult有效(对象值,ValidationContext ValidationContext)
{
var collection=(ICollection)值;
return collection==null | | collection.Count>0
?验证结果。成功
:新建验证结果(ErrorMessageString);
}
}
最后,在控制器中,我要确保
POST
请求中的ViewModel有效,这将触发验证:

[HttpPost]
公共异步任务方法(MethodViewModel viewModel)
{
如果(!ModelState.IsValid)
返回视图(viewModel);
...
}
如果在调用
ModelState.IsValid
时中断,
Attachments
属性的
ModelState.Values
的内容是:

问题:
  • 为什么
    RequiredCollectionAttribute.IsValid()方法中的断点没有被命中?
    方法
  • 为什么
    Attachments
    属性的
    ValidationState
    设置为
    Skipped
--

编辑1: MethodViewModel定义,根据要求:

public class MethodViewModel
{
    ...
    [Display(Name = "Attachments")]
    [RequiredCollection(ErrorMessage = "You must attached at least one file.")]
    public ICollection<IFormFile> Attachments { get; set; }
    ...
}
--

编辑3: 视图的razor语法用于呈现
附件
输入字段

<form role="form" asp-controller="Controller" asp-action="Method" method="post" enctype="multipart/form-data">
    ...
    <div class="form-group">
        <label asp-for="Attachments" class="control-label col-xs-3 col-sm-2"></label>
        <div class="col-xs-9 col-sm-10">
            <input asp-for="Attachments" class="form-control" multiple required>
            <span asp-validation-for="Attachments" class="text-danger"></span>
        </div>
    </div>
    ...
</form>

...
...

部分答案(仅用于代码共享目的)

试试这个:

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
public sealed class RequiredCollectionAttribute : ValidationAttribute
{

    public override bool IsValid(object value)
    {
        ErrorMessage = "You must provide at least one.";
        var collection = value as ICollection;

        return collection != null || collection.Count > 0;
    }
}
另外,尝试添加一个过滤器

GlobalConfiguration.Configuration.Filters.Add(new RequestValidationFilter());
并将过滤器本身写入:

public class RequestValidationFilter : ActionFilterAttribute
{
    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        if (actionContext.ModelState.IsValid == false)
        {
            var errors = actionContext.ModelState
                                      .Values
                                      .SelectMany(m => m.Errors
                                                        .Select(e => e.ErrorMessage));

            actionContext.Response = actionContext.Request.CreateErrorResponse(
                HttpStatusCode.BadRequest, actionContext.ModelState);

            actionContext.Response.ReasonPhrase = string.Join("\n", errors);
        }
    }
}

只供我们检查是否在过滤器内部触发了断点。

如果发现
ifformfile
ifformfile
的集合不为空,MVC似乎正在抑制进一步的验证。

如果您查看
FormFileModelBinder.cs
代码。如果绑定器能够从上面的if/elseif/else子句中获得非空结果,则将禁止验证

在测试中,我使用如下代码创建了一个视图模型:

[ThisAttriuteAlwaysReturnsAValidationError]
public IFormFile Attachment { get;set; }
当我实际上传一个文件到这个例子中时,上面的always erroring属性永远不会被调用

由于这是来自MVC本身,我认为最好的选择是实现
ivalidTeableObject
接口

public class YourViewModel : IValidatableObject
{
    public ICollection<IFormFile> Attachments { get;set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        var numAttachments = Attachments?.Count() ?? 0;
        if (numAttachments == 0)
        {
            yield return new ValidationResult(
                "You must attached at least one file.",
                new string[] { nameof(Attachments) });
        }
    }
}
公共类YourViewModel:IValidatableObject
{
公共ICollection附件{get;set;}
公共IEnumerable验证(ValidationContext ValidationContext)
{
var numAttachments=附件?计数()?0;
如果(numAttachments==0)
{
返回新的ValidationResult(
“您必须至少附加一个文件。”,
新字符串[]{nameof(附件)});
}
}
}
此方法仍将被调用,因为它不与任何单个属性关联,因此不会像属性一样被MVC抑制

如果您必须在多个地方执行此操作,您可以创建一个扩展方法来提供帮助

public static bool IsNullOrEmpty<T>(this IEnumerable<T> collection) =>
        collection == null || !collection.GetEnumerator().MoveNext();
publicstaticbool为空(此IEnumerable集合)=>
集合==null | |!collection.GetEnumerator().MoveNext();
更新
这在1.0.0 RTM中已经并且应该得到修复。

尝试覆盖上面建议的方法签名,但这无法解决问题。
viewModel.Attachments
ValidationState
仍然设置为
Skipped
。请提供MethodViewModel的声明好吗?\n为问题添加了定义我编辑了一个错误,我在这里检查集合是否为null而不是与null不同。你注意到了吗?在我的服务器上,它正在工作,所以我们可能缺少smth。在我给你的代码中,是否触发了错误消息行上的断点?你是对的,这是一个输入错误,应该是
!=空
。我在
IsValid
方法的条目上有一个断点,它从不中断。我认为不会为此ICollection属性触发此验证。相反,在类级别应用属性并检查集合。@E-Bat请您解释一下“在类级别应用属性”是什么意思?我的意思是,您是如何具体化集合的,您在运行时使用的ICollection实现是什么?@E-Bat通过对视图中的
POST
数据进行反序列化,“幕后”初始化该集合。查看“我的本地人”窗口,它的形式是ASP.NET标记帮助程序自动添加的
System.Collections.Generic.List
@E-Bat
type=“file”
。感谢您的精彩回答和提出错误报告。很好,ASPNET团队承认这是一个有效的问题。赏金。
public static bool IsNullOrEmpty<T>(this IEnumerable<T> collection) =>
        collection == null || !collection.GetEnumerator().MoveNext();