{"action":"created","issue":{"url":"https://api.github.com/repos/JeremySkinner/FluentValidation/issues/801","repository_url":"https://api.github.com/repos/JeremySkinner/FluentValidation","labels_url":"https://api.github.com/repos/JeremySkinner/FluentValidation/issues/801/labels{/name}","comments_url":"https://api.github.com/repos/JeremySkinner/FluentValidation/issues/801/comments","events_url":"https://api.github.com/repos/JeremySkinner/FluentValidation/issues/801/events","html_url":"https://github.com/JeremySkinner/FluentValidation/issues/801","id":336148694,"node_id":"MDU6SXNzdWUzMzYxNDg2OTQ=","number":801,"title":"Handling Null Object during model binding [AspNetCore / MVC5 / WebApi]","user":{"login":"AdemCatamak","id":6951884,"node_id":"MDQ6VXNlcjY5NTE4ODQ=","avatar_url":"https://avatars1.githubusercontent.com/u/6951884?v=4","gravatar_id":"","url":"https://api.github.com/users/AdemCatamak","html_url":"https://github.com/AdemCatamak","followers_url":"https://api.github.com/users/AdemCatamak/followers","following_url":"https://api.github.com/users/AdemCatamak/following{/other_user}","gists_url":"https://api.github.com/users/AdemCatamak/gists{/gist_id}","starred_url":"https://api.github.com/users/AdemCatamak/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AdemCatamak/subscriptions","organizations_url":"https://api.github.com/users/AdemCatamak/orgs","repos_url":"https://api.github.com/users/AdemCatamak/repos","events_url":"https://api.github.com/users/AdemCatamak/events{/privacy}","received_events_url":"https://api.github.com/users/AdemCatamak/received_events","type":"User","site_admin":false},"labels":[],"state":"closed","locked":false,"assignee":null,"assignees":[],"milestone":{"url":"https://api.github.com/repos/JeremySkinner/FluentValidation/milestones/10","html_url":"https://github.com/JeremySkinner/FluentValidation/milestone/10","labels_url":"https://api.github.com/repos/JeremySkinner/FluentValidation/milestones/10/labels","id":3429934,"node_id":"MDk6TWlsZXN0b25lMzQyOTkzNA==","number":10,"title":"7.6.104","description":"","creator":{"login":"JeremySkinner","id":90130,"node_id":"MDQ6VXNlcjkwMTMw","avatar_url":"https://avatars3.githubusercontent.com/u/90130?v=4","gravatar_id":"","url":"https://api.github.com/users/JeremySkinner","html_url":"https://github.com/JeremySkinner","followers_url":"https://api.github.com/users/JeremySkinner/followers","following_url":"https://api.github.com/users/JeremySkinner/following{/other_user}","gists_url":"https://api.github.com/users/JeremySkinner/gists{/gist_id}","starred_url":"https://api.github.com/users/JeremySkinner/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/JeremySkinner/subscriptions","organizations_url":"https://api.github.com/users/JeremySkinner/orgs","repos_url":"https://api.github.com/users/JeremySkinner/repos","events_url":"https://api.github.com/users/JeremySkinner/events{/privacy}","received_events_url":"https://api.github.com/users/JeremySkinner/received_events","type":"User","site_admin":false},"open_issues":0,"closed_issues":2,"state":"open","created_at":"2018-06-17T08:50:33Z","updated_at":"2018-06-29T19:43:04Z","due_on":null,"closed_at":null},"comments":5,"created_at":"2018-06-27T09:29:25Z","updated_at":"2018-06-29T19:43:04Z","closed_at":"2018-06-29T19:43:04Z","author_association":"CONTRIBUTOR","body":"Hi,\r\n\r\nI have an API and when request comes to my controller, I want to call `Validate` function. However, I firstly have to check if the request object is null or not. Otherwise, `ArgumentNullException` occurs. I created my concrete validator against this situation like below.\r\n\r\n    public class ConcreteValidator : AbstractValidator<DummyClass>\r\n    {\r\n        public ConcreteValidator()\r\n        {\r\n            ...\r\n        }\r\n        \r\n        public override ValidationResult Validate(ValidationContext<OrderClass> context)\r\n        {\r\n            if (context.InstanceToValidate == null)\r\n                return new ValidationResult(new List<ValidationFailure>{new ValidationFailure(\"Dummy\", \"Instance should not be null\")});\r\n            return base.Validate(context);\r\n        }\r\n        \r\n        public override Task<ValidationResult> ValidateAsync(ValidationContext<OrderClass> context, CancellationToken cancellation = new CancellationToken())\r\n        {\r\n            if (context.InstanceToValidate == null)\r\n                return Task.FromResult(new ValidationResult(new List<ValidationFailure>{new ValidationFailure(\"Dummy\", \"Instance should not be null\") }));\r\n            return base.ValidateAsync(context, cancellation);\r\n        }\r\n    }\r\n\r\nIn situations that I accept null objects as valid, I create my derived/concrete validator classes like below.\r\n\r\n    public class ConcreteValidator : AbstractValidator<DummyClass>\r\n    {\r\n        public ConcreteValidator()\r\n        {\r\n            ...\r\n        }\r\n        \r\n        public override ValidationResult Validate(ValidationContext<OrderClass> context)\r\n        {\r\n            if (context.InstanceToValidate == null)\r\n                return new ValidationResult();\r\n            return base.Validate(context);\r\n        }\r\n        \r\n        public override Task<ValidationResult> ValidateAsync(ValidationContext<OrderClass> context, CancellationToken cancellation = new CancellationToken())\r\n        {\r\n            if (context.InstanceToValidate == null)\r\n                return Task.FromResult(new ValidationResult());\r\n            return base.ValidateAsync(context, cancellation);\r\n        }\r\n    }\r\n\r\nMy question is that: Is there any good solution to do null check and other validation checks in the same validation class. Would you give me some advice on how to achieve this without overriding `Validate` and `ValidateAsync` methods.\r\n\r\nA possible solution may be adding `pre-` and `post-` pipes in `AbstractValidator`.\r\n\r\nMy basic idea is:\r\n\r\n    public virtual ValidationResult Validate(ValidationContext<T> context) {\r\n        context.Guard(\"Cannot pass null to Validate.\", nameof(context));\r\n        ValidationResult shortcut = PreValidation(context.InstanceToValidate);\r\n        if(shortcut != null)\r\n            return shortcut;\r\n        EnsureInstanceNotNull(context.InstanceToValidate);\r\n        var failures = NestedValidators.SelectMany(x => x.Validate(context));\r\n        return new ValidationResult(failures);\r\n    }\r\n    \r\n    /// <summary>\r\n\t/// PreValidation operation is executed. If return null as result, Validate will be executed.\r\n    /// If return ValidationResult object as result, Validate operation return immediatly this result.\r\n\t/// </summary>\r\n\t/// <returns>A ValidationResult object. Default method return null.</returns>\r\n\tprotected virtual ValidationResult PreValidation(object instanceToValidate) => Noop();\r\n\r\n\tprivate ValidationResult Noop() {\r\n\t\treturn null;\r\n\t}\r\n\r\nIn this case, people can use PreValidation method with different scenarios such as null instance assumed valid\r\n\r\n    protected override ValidationResult PreValidation(object instanceToValidate) {\r\n\t\tValidationResult shortcut = null;\r\n\t\tif (instanceToValidate == null)\r\n\t\t\tshortcut = new ValidationResult();\r\n\t\treturn shortcut;\r\n    }\r\n\r\nor scenarios such as null instance not valid. In this case, exception does not occur, but validationResult.IsValid returns false.\r\n\r\n    protected override ValidationResult PreValidation(object instanceToValidate) {\r\n        ValidationResult shortcut = null;\r\n\t\tif (instanceToValidate == null)\r\n\t\t\tshortcut = new ValidationResult(new[] {new ValidationFailure(\"MyClassName may be used\", \"MyClass should be supplied\")});\r\n\t\treturn shortcut;\r\n    }"},"comment":{"url":"https://api.github.com/repos/JeremySkinner/FluentValidation/issues/comments/401454943","html_url":"https://github.com/JeremySkinner/FluentValidation/issues/801#issuecomment-401454943","issue_url":"https://api.github.com/repos/JeremySkinner/FluentValidation/issues/801","id":401454943,"node_id":"MDEyOklzc3VlQ29tbWVudDQwMTQ1NDk0Mw==","user":{"login":"JeremySkinner","id":90130,"node_id":"MDQ6VXNlcjkwMTMw","avatar_url":"https://avatars3.githubusercontent.com/u/90130?v=4","gravatar_id":"","url":"https://api.github.com/users/JeremySkinner","html_url":"https://github.com/JeremySkinner","followers_url":"https://api.github.com/users/JeremySkinner/followers","following_url":"https://api.github.com/users/JeremySkinner/following{/other_user}","gists_url":"https://api.github.com/users/JeremySkinner/gists{/gist_id}","starred_url":"https://api.github.com/users/JeremySkinner/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/JeremySkinner/subscriptions","organizations_url":"https://api.github.com/users/JeremySkinner/orgs","repos_url":"https://api.github.com/users/JeremySkinner/repos","events_url":"https://api.github.com/users/JeremySkinner/events{/privacy}","received_events_url":"https://api.github.com/users/JeremySkinner/received_events","type":"User","site_admin":false},"created_at":"2018-06-29T19:43:04Z","updated_at":"2018-06-29T19:43:04Z","author_association":"OWNER","body":"Implemented for the 7.6.104 release."}}
{"actor":{"display_login":"JeremySkinner"}}