2013-06-14 2 views
6

私はこのような、たとえば、見えDTOクラス、持っている:.NETのWeb API:クラス・レベルの検証属性は、インスタンスがnullの場合は例外ArgumentNullExceptionをスローするには、Web APIを起こし

public class ExampleDto 
{ 
    [DataMember(Name = "Date", IsRequired = true, Order = 1), Required] 
    public DateTime Date { get; set; } 

    [DataMember(Name = "ParentExample", IsRequired = false, Order = 2, EmitDefaultValue = false)] 
    public Guid? ParentExampleId { get; set; } 
} 

を、もし一例として、ユーザーはこのような、誤った日付を提供しています。

<?xml version="1.0" encoding="UTF-8" ?> 
<ExampleDto xmlns="http://customurl/"> 
     <Date>2012-05-25T18:23:INCORRECTDATE</Date> 
     <ParentExample>B62F10A8-4998-4626-B5B0-4B9118E11BEC</ParentExample> 
</ExampleDto> 

または単にちょうど空のボディ、そして行動に渡さExampleDto引数はnullになります(そして前者の場合には、にModelStateにエラーがあります)。

私はクラスにCustomValidationAttributeを適用し、そのクラス宣言は次のようになります。今ExampleDto引数があるため、空体(nullの場合、または私は、これを追加しましたことを

[CustomValidation(typeof(CustomExampleValidator), "Validate")] 
public class ExampleDto 

シリアル化の問題)、例外ArgumentNullExceptionがスローされます。

<?xml version="1.0" encoding="UTF-8"?> 
<Response xmlns="http://customurl" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> 
    <Type>Failure</Type> 
    <Message>An unknown error has occurred</Message> 
    <Errors> 
     <Error> 
      <Message>System.ArgumentNullException</Message> 
      <MessageDetail>Value cannot be null. Parameter name: 
       instance</MessageDetail> 
      <StackTrace> at System.ComponentModel.DataAnnotations.ValidationContext..ctor(Object 
       instance, IServiceProvider serviceProvider, 
       IDictionary`2 items) at System.Web.Http.Validation.Validators.DataAnnotationsModelValidator.Validate(ModelMetadata 
       metadata, Object container) at System.Web.Http.Validation.DefaultBodyModelValidator.ShallowValidate(ModelMetadata 
       metadata, ValidationContext validationContext, 
       Object container) at System.Web.Http.Validation.DefaultBodyModelValidator.ValidateNodeAndChildren(ModelMetadata 
       metadata, ValidationContext validationContext, 
       Object container) at System.Web.Http.Validation.DefaultBodyModelValidator.Validate(Object 
       model, Type type, ModelMetadataProvider metadataProvider, 
       HttpActionContext actionContext, String keyPrefix) 
       at System.Web.Http.ModelBinding.FormatterParameterBinding.&lt;&gt;c__DisplayClass1.&lt;ExecuteBindingAsync&gt;b__0(Object 
       model) at System.Threading.Tasks.TaskHelpersExtensions.&lt;&gt;c__DisplayClass36`1.&lt;&gt;c__DisplayClass38.&lt;Then&gt;b__35() 
       at System.Threading.Tasks.TaskHelpersExtensions.&lt;&gt;c__DisplayClass49.&lt;ToAsyncVoidTask&gt;b__48() 
       at System.Threading.Tasks.TaskHelpers.RunSynchronously[TResult](Func`1 
       func, CancellationToken cancellationToken)</StackTrace> 
     </Error> 
    </Errors> 
</Response> 

リフレクターnull引数のチェックがCustomValidationAttributeが実行される直前に、ValidationContextのコンストラクタでオブジェクトに対して実行されていることを示しています。ヌル引数はコントローラのアクションの引数として受け入れることができるので、少し奇妙なようです。私はここでnull引数のチェックは、フレームワークではなく、ユーザのコードで、または検証属性によって明示的に実行されるべきだと思います。

ユーザーが正しいXML/JSONを送信した場合、この例外はスローされず、期待通りにCustomValidationAttributeが実行されますが、ユーザーは常に正しいXML/JSONを送信するとは信用できません。また、ArgumentNullException彼らの努力のために、私は自分自身を返すことができるものの代わりに。

私はこれを経験した誰かを見つけるのに苦労しています。プロパティレベルで "複合"バリデータを適用する例はたくさんありますが、ここではクラスレベルで検証を適用する方が理にかなっています(特定のプロパティがnullでない場合は複数のプロパティが必要なため、別のプロパティはnullではありません)、クラスレベルで適用された検証属性がサポートされていないとは何も見つかりません。

+1

回避策として:

public class GeneralExceptionFilterAttribute : ExceptionFilterAttribute { public override void OnException(HttpActionExecutedContext context) { var exceptionType = context.Exception.GetType(); HttpResponseMessage response = null; if(exceptionType == typeof(ArgumentNullException) && context.Exception.StackTrace.TrimStart().StartsWith("at System.ComponentModel.DataAnnotations.ValidationContext..ctor")) { response = new HttpResponseMessage(HttpStatusCode.BadRequest) { Content = new StringContent(context.Exception.Message) }; } else { response = new HttpResponseMessage(HttpStatusCode.InternalServerError) { Content = new StringContent(context.Exception.Message), ReasonPhrase = "Unhandled exception" }; } context.Response = response; _errorLogger.LogError(response?.ReasonPhrase, context.Exception); } } 

そしてWebApiConfig.csでグローバルフィルタを登録します。だから、私の迅速かつ汚いソリューションは、フィルタでこれらの例外をキャッチし、適切な応答を返送することでした検証を実行するためにIValidatableObjectを明示的に実装しました。私は検証属性を使用することを好むので、これについての説明を探しています。 –

+0

私はあなたの問題を再現しようとしましたが運がなかった...この画像を見てください:http://tallmaris.com/blog/wp-content/uploads/2013/06/Capture.png。あなたが見ることができるように、値はバリデーターに到着し、それはヌルではありません。それがコントローラに到達すると、 'IsValid'はコースの日付のためにfalseになります。その結果の投稿情報は次のとおりです。var example = new {Chi = "YYY"、PatientStatus = 1、Date = "2012-05-25T18:23:XXXX"、ParentExample = "B62F10A8-4998-4626-B5B0-4B9118E11BEC "};'(その後、Jsonはシリアライズしてアップロードしました)。 – Tallmaris

+0

こんにちはタルマリス、それを与えてくれてありがとう。値がnullでない場合、例外はスローされません。var example = null;で投稿するか、jsonを手動で、構文エラーで送信してください。 –

答えて

1

私は同じ問題があります。残念ながら、かなりの数のValidationAttributesがあります。したがって、リリース直前にIValidatableObjectにすべてを書き直すことは実際には実現できません。 、

config.Filters.Add(new GeneralExceptionFilterAttribute()); 
関連する問題