0

This project I've inherited is a bit of a botch job; it's a Windows Service with an api layer tacked onto it... I don't think this is the issue though

Example controller

[Route("Test/GetUsers")]
[HttpGet]
public string GetUsers(bool? enabled=null, bool? sync=null)
{
   // do whatever
}

So calling https://myapi/Test/GetUsers?enabled=true&sync=true would work just fine

However, if I call https://myapi/Test/GetUsers?enabled=true I get 400 Bad Request: "Arguments cannot be null" back from the server

After fiddling around a bit, I found

[Route("Test/GetUsers")]
[HttpGet]
public string GetUsers(bool enabled=false, bool sync=false)
{
   // do whatever
}

would mean https://myapi/Test/GetUsers?enabled=true would work fine.

I actually want the null bool though, because the logic works like this

if (enabled != null)
{
    // add Enabled = True/False clause to the query
}

So if enabled were null, it's going to get both enable and disabled users

p3tch
  • 1,414
  • 13
  • 29
  • Just use: `public string GetUsers(bool? enabled, bool? sync)` – Kirk Larkin Feb 15 '18 at 14:01
  • Will those still be optional? I'll give it a try now – p3tch Feb 15 '18 at 14:02
  • Nope, I'm just getting `404 not found, "No HTTP resource was found that matches the request URI 'https://myapi/Test/GetUsers?enabled=true'."` @KirkLarkin – p3tch Feb 15 '18 at 14:07
  • Have a try with Nullableenabled – Marcus Höglund Feb 15 '18 at 14:07
  • Same result @MarcusHöglund :( – p3tch Feb 15 '18 at 14:10
  • Are you sure you are not hitting the endpoint (maybe somewhere within the logic exception is thrown)? Try putting breakpoint on initial line of controller method. If it doesn't hit the endpoint try looking for some global handler that might cause this. – zhuber Feb 15 '18 at 14:12
  • Have you already looked at [this similar question](https://stackoverflow.com/a/38249991/1260204)? Note the route used as well. – Igor Feb 15 '18 at 14:19
  • @Igor you mean having {enabled?} in the route? That's actually how it started out, but that had the exact same results – p3tch Feb 15 '18 at 14:20
  • @zhuber it doesn't break on the first line when the parameters aren't given as part of the http request (when it returns `"Message": "Arguments cannot be null"` ) – p3tch Feb 15 '18 at 14:41
  • @zhuber could DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes be something to do with it? This has come up in my searched but due to this services architecture I don't have the Application_Start method – p3tch Feb 15 '18 at 14:43
  • Do you have any custom code in your `WebApiConfig.cs` file? – Igor Feb 15 '18 at 14:44
  • @Igor there's no such file, again, weird setup going on here that I am reluctant to start messing with should it break everything (I didn't write the app and it's a behemoth) – p3tch Feb 15 '18 at 14:46
  • Are you using Ajax? If so, can you post that? – Grizzly Feb 15 '18 at 14:47
  • @GTown-Coder no ajax – p3tch Feb 15 '18 at 14:47
  • Okay, how are you sending the data to the api method? I believe the problem is that the values are being received as strings.. and behind the scenes.. api cannot convert "null" to a boolean object because it is not "true" or "false" – Grizzly Feb 15 '18 at 14:48
  • @GTown-Coder Currently? In Postman, with the exact urls you see in the OP – p3tch Feb 15 '18 at 14:49
  • In postman can you change the dataType? contentType? – Grizzly Feb 15 '18 at 14:50
  • @GTown-Coder Honestly, that's got nothing to do with this. If in my controller I have `bool enabled=false` it works perfectly - the issue is when I have the default value of the optional parameter as null. I don't see why changing any of those settings will affect anything when I'm literally just omitting a parameter – p3tch Feb 15 '18 at 14:51
  • There is some bootstrap method that is responsible for initializing the WebAPI framework. You need to find out where this occurs and see if there is something there that pops out at you, if you do not see anything in that bootstrap config then update your question with the relevant code. – Igor Feb 15 '18 at 14:55
  • What if you try calling it without actually using null and just leaving that part blank in the url? `https://myapi/Test/GetUsers/true/`.. so only enabled will have a value and sync will be blank – Grizzly Feb 15 '18 at 15:01
  • 1
    @Igor sigh... within all the spaghetti code, there's a class initialisaton that adds an `IFilter` to a poorly named `HttpSelfHostConfiguration` object. Sure enough, there's a null check in the filter :) – p3tch Feb 15 '18 at 15:10
  • Glad you found the cause. – Igor Feb 15 '18 at 15:11
  • 1
    Thanks for the help everyone, especially @Igor for pointing me in the right direction. I'm going to close the question as it's not going to be of use to anyone – p3tch Feb 15 '18 at 15:13
  • @p3tch it is still an interesting question for people with similar problems. You can just write an answer with your findings – jps Feb 15 '18 at 15:20

1 Answers1

0

I'm not sure how much use this will be to anyone, but I'll leave it as an asnwer regardless

There was a private readonly HttpSelfHostConfiguration field in the class used as the service's ServiceBase

In the constructor of that class, it instantiated and added a custom ActionFilterAttribute to the HttpSelfHostConfiguration.Filter collection

public class ValidateViewModelAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        if (actionContext.ActionArguments.Any(kv => kv.Value == null))
        {
            actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest, "Arguments cannot be null");
        }

        if (actionContext.ModelState.IsValid == false)
        {
            actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest, actionContext.ModelState);
        }
    }
}

Removing the first if statement obviously resolved my issue, as that was stopping any actions that had a null argument. I realise, to my embarassment, searching the project for "Arguments cannot be null" would have probably lead me directly to the culprit

p3tch
  • 1,414
  • 13
  • 29