【问题标题】:DataAnnotation for Required property必需属性的 DataAnnotation
【发布时间】:2012-08-31 14:38:26
【问题描述】:

起初它有效,但今天它失败了!

这就是我定义日期属性的方式:

[Display(Name = "Date")]
[Required(ErrorMessage = "Date of Submission is required.")]        
[DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
[DataType(DataType.Date)]
public DateTime TripDate { get; set; }

过去一直有效。但是今天,当我调用相同的 ApiController 操作时:

[HttpPost]
public HttpResponseMessage SaveNewReport(TripLeaderReportInputModel model)

Firebug 报告:

ExceptionMessage:

"Property 'TripDate' on type 'Whitewater.ViewModels.Report.TripLeaderReportInputModel' 
is invalid. Value-typed properties marked as [Required] must also be marked with
[DataMember(IsRequired=true)] to be recognized as required. Consider attributing the 
declaring type with [DataContract] and the property with [DataMember(IsRequired=true)]."

ExceptionType

"System.InvalidOperationException"

发生了什么?那些[DataContract] 不是WCF 吗?我在MVC4 中使用REST WebAPI

有人可以帮忙吗?请问?

---更新---

我找到了一些类似的链接。

MvC 4.0 RTM broke us and we don't know how to fix it RSS

---再次更新---

这是 HTTP 响应标头:

Cache-Control   no-cache
Connection  Close
Content-Length  1846
Content-Type    application/json; charset=utf-8
Date            Thu, 06 Sep 2012 17:48:15 GMT
Expires         -1
Pragma          no-cache
Server          ASP.NET Development Server/10.0.0.0
X-AspNet-Version    4.0.30319

请求标头:

Accept          */*
Accept-Encoding gzip, deflate
Accept-Language en-us,en;q=0.5
Cache-Control   no-cache
Connection          keep-alive
Content-Length  380
Content-Type    application/x-www-form-urlencoded; charset=UTF-8
Cookie          .ASPXAUTH=1FF35BD017B199BE629A2408B2A3DFCD4625F9E75D0C58BBD0D128D18FFDB8DA3CDCB484C80176A74C79BB001A20201C6FB9B566FEE09B1CF1D8EA128A67FCA6ABCE53BB7D80B634A407F9CE2BE436BDE3DCDC2C3E33AAA2B4670A0F04DAD13A57A7ABF600FA80C417B67C53BE3F4D0EACE5EB125BD832037E392D4ED4242CF6
DNT                 1
Host            localhost:39019
Pragma          no-cache
Referer         http://localhost:39019/Report/TripLeader
User-Agent          Mozilla/5.0 (Windows NT 6.1; WOW64; rv:15.0) Gecko/20100101 Firefox/15.0
X-Requested-With    XMLHttpRequest

---更新---

我找到了一个临时解决方案。请参阅下面的答案。如果有人理解它为什么起作用或有更好的解决方案,请发布您的答案。谢谢。

【问题讨论】:

  • 你改变你的称呼了吗?
  • 我不这么认为。什么变化会出现这样的异常?重新申请[DataContract]标签?
  • 在以前不需要序列化内容的情况下需要序列化内容的任何更改。
  • 我发现Json.NET 已安装在 NuGet 中。这是我应该删除的那个吗?
  • 不,我无法删除 Json.NET。无法卸载“Newtonsoft.Json 4.5.8”,因为“Jang 1.0.1, Microsoft.AspNet.WebApi.Client 4.0.20710.0”依赖于它。

标签: asp.net-mvc-4 asp.net-web-api data-annotations


【解决方案1】:

好的。虽然我还没有完全理解这件事。找到了解决方法。

Global.asax:

GlobalConfiguration.Configuration.Services.RemoveAll(
    typeof(System.Web.Http.Validation.ModelValidatorProvider),
    v => v is InvalidModelValidatorProvider);

我在 aspnetwebstack 的问题跟踪器中找到了它。这是页面的链接:

Overly aggressive validation for applying [DataMember(IsRequired=true)] to required properties with value types

如果有人能告诉我们为什么会这样,请发表您的见解作为答案。谢谢。

【讨论】:

    【解决方案2】:

    2013 年 5 月 24 日更新:负责此错误消息的 InvalidModelValidatorProvider 已从 ASP.NET 技术堆栈中删除。这个验证器被证明会引起比它想要解决的更多的混乱。欲了解更多信息,请参阅以下链接:http://aspnetwebstack.codeplex.com/workitem/270

    当您使用[DataContract] 属性装饰您的类时,您需要使用[DataMember] 属性显式装饰您想要序列化的成员。

    问题在于DataContractSerializer 不支持[Required] 属性。对于引用类型,我们能够在反序列化后检查该值是否不为空。但是对于值类型,如果没有[DataMember(IsRequired=true)],我们就无法为DataContractSerializer 强制执行[Required] 语义。

    因此,您最终可能会将DateTime 标记为[Required],如果未发送DateTime,则可能会出现模型验证错误,但您只会得到DateTime.MinValue 值而没有验证错误。

    【讨论】:

    • 我无意使用[DataContract] 属性。真的不知道为什么它要求这个。我所做的是在 poco 类上使用标准 DataAnnotation 属性。
    • 是的,对值类型有意义。我刚刚设置为可空属性并稍后验证。虽然是错误的错误消息...
    • @ArtificialGold ASP.NET 团队的开发人员似乎同意:该行为已从 ASP.NET 技术堆栈中删除:aspnetwebstack.codeplex.com/workitem/270
    【解决方案3】:

    我添加了一个ModelValidationFilterAttribute 并使其工作:

    public class ModelValidationFilterAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(HttpActionContext actionContext)
        {
            if (!actionContext.ModelState.IsValid)
            {
                // Return the validation errors in the response body.
                var errors = new Dictionary<string, IEnumerable<string>>();
                //string key;
                foreach (KeyValuePair<string, ModelState> keyValue in actionContext.ModelState)
                {
                    //key = keyValue.Key.Substring(keyValue.Key.IndexOf('.') + 1);
                    errors[keyValue.Key] = keyValue.Value.Errors.Select(e => e.ErrorMessage);
                }
                //var errors = actionContext.ModelState
                //    .Where(e => e.Value.Errors.Count > 0)
                //    .Select(e => new Error
                //    {
                //        Name = e.Key,
                //        Message = e.Value.Errors.First().ErrorMessage
                //    }).ToArray();
    
                actionContext.Response =
                    actionContext.Request.CreateResponse(HttpStatusCode.BadRequest, errors);
            }
        }
    }
    

    您可以在操作上添加[ModelValidation] 过滤器。或者添加到Global.asax.cs:

    GlobalConfiguration.Configuration.Services.RemoveAll(
    typeof(System.Web.Http.Validation.ModelValidatorProvider),
    v => v is InvalidModelValidatorProvider);
    

    这样,我继续使用原来的数据标注。

    Reference

    【讨论】:

    • 这对我很有用,问题是验证的输出不是 JSON,而是 XML。在 Global.asax 中强制它为 json 并适用于控制器输出,但我如何将验证模型也设置为输出 JSON?
    • @byte_slave:响应的类型通常由请求中“接受”标头的值决定。如果您将其设置为 'text/json' 或 'application/json' 则框架应将响应正文作为 JSON 返回 - 除非您的代码中的服务器端还有其他内容...
    【解决方案4】:

    如果您尝试将操作的输出作为 XML 返回,那么您将需要使用 DataContracts,因为默认序列化程序需要它们。我猜您之前一直请求将您的操作输出为 Json,Json 序列化程序不需要数据协定。您可以发布您的请求吗?

    【讨论】:

    • 感谢您的快速回复。是的,我要求输出为 Json。而且我仍然想使用Json。我怎样才能在这里“张贴小提琴”?我需要安装 Fiddler2 吗?
    猜你喜欢
    • 1970-01-01
    • 2012-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-31
    • 2011-03-01
    • 1970-01-01
    • 2014-03-22
    相关资源
    最近更新 更多