2

I'm using C# web api and want to create a filter to all requests.

I have a designated class to every request so I just want to add some data annotations and get the validation over with.

The problem is that I'm getting true every time on actionContext.ModelState.IsValid

I have added my filter in the config:

config.Filters.Add(new RequestValidationFilter());

validation method looks like every other in the web

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);
        }
    }
}

I have the following method:

[HttpPost, Route("User/Login")]
public async Task<Responses.Login> Login(Requests.Login request)
{
      ...//some login logic
}

And also, I have my model which is:

public class Requests
{
    public class Login
    {
        [Required(AllowEmptyStrings = false, ErrorMessage = "Email address  cannot be empty!")]
[MinLength(5)]
            public string Email;
        [Required]
        public string Password;
    }
}

I'm sending both an empty request or request which Email and Password are null and still the actionContext.ModelState.IsValid evaluate it as true

Attached is an image when email was sent but password wasn't.

enter image description here

Following a comment, here is my request via Advanced Rest Client chrome plugin

enter image description here NOTE

the image actually shows that Keys and Values are empty when in fact they are supplied..

EDIT

number of things i've also tried:

  1. removing all other filters, why? maybe the context was messed up by another reading.
  2. sending valid request in terms of fields, but email was 1 char long.why? maybe Requiredis working differently than others, still nothing about the min-length issue.
  3. instead of nested objects, i created a seperate stand-alone class for the Login object. why? thought maybe the fact that it's nested the validation is not recursive.
  4. Looping the Arguments list one-by-one and validate as object, answer is always true. never fails, why? cause Im almost admitting defeat.
  5. instead of adding filter to config as i described in the question, tried GlobalConfiguration.Configuration.Filters.Add(new RequestValidationFilter()); instead
9
  • 1
    There's a lot of good info on this post. You can try implementing IValidatableObject and ModelState should look at the object's Validate method. stackoverflow.com/questions/3400542/… Commented Mar 2, 2016 at 17:27
  • i really want to avoid making something manual. can i implement whats in there and still work with the custom error message and all the tools that annontion provide me? Its important for me to implement the validation preior to the invocation on the method in the controller Commented Mar 2, 2016 at 17:30
  • This post might be helpful: strathweb.com/2012/10/… Commented Mar 2, 2016 at 19:11
  • @CodingGorilla well. unfortunatly, it didn't. the only difference there that they built another filter for null handling. that's not my concern here. if you can give another suggestion or a feedback it would be lovely Commented Mar 2, 2016 at 19:22
  • @OriRefael Sorry, I've never used this feature myself, I just found that after a quick search and thought it might be helpful to you. Commented Mar 2, 2016 at 19:29

1 Answer 1

2

You need to add { get; set; } after your model properties:

public class Login
{
    [Required(AllowEmptyStrings = false, ErrorMessage = "Email address cannot be empty!")]
    [MinLength(5)]
    public string Email { get; set; }

    [Required]
    public string Password { get; set; }
}

This is necessary because the default model validation for ASP.NET only includes properties with a public get method. From PropertyHelper.cs, here's some of the code which determines whether a property on the model will be included in validation:

// Indexed properties are not useful (or valid) for grabbing properties off an object.
private static bool IsInterestingProperty(PropertyInfo property)
{
    return property.GetIndexParameters().Length == 0 &&
        property.GetMethod != null &&
        property.GetMethod.IsPublic &&
        !property.GetMethod.IsStatic;
}

This method is used to filter the properties that are used in the default model binding in MVC/Web API. Notice that it's checking whether the GetMethod exists on the property and that it's public. Since your class didn't have the get methods on its properties, they were being ignored.

If you want to know more, you can kill a lot of time looking through the ASP.NET MVC source. I think the code on github is for a newer version of ASP.NET, but it seems like a lot of the same logic applies in the version you are using.

Sign up to request clarification or add additional context in comments.

3 Comments

Good spotting! I think this is the issue. Only difference I can see.
Bullcrap! i can't bealieve it was it. i thought to myself: "what the hell?" and you just spotted it. amazing. can you explain?
I think it has something to do with the validator not being able to see the fields in your class unless they have a getter method. I will play around with it later and see if I can come up with a real explanation

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.