I have an API endpoint which is implemented as follows:
[RoutePrefix("Validations")]
public class ValidationsController : ApiController
{
[HttpPost, Route("Bsb")]
public IHttpActionResult ValidateBsb([FromUri] string value = null)
{
var validator = new BankStateBranchValidator(DbContext.BankStateBranches);
var data = new ValidationsResult
{
IsValid = validator.IsValid(value ?? string.Empty)
};
data.Error = data.IsValid
? null
: "The BSB you have entered does not appear to be valid. Please check the value and try again.";
return Ok(data);
}
}
I can call the API successfully with the following API and get the expected result back:
POST /Validations/Bsb?value=012345
POST /Validations/Bsb
But if I make the following API call, then it fails with a 400 Bad Request generated by the framework itself (i.e. a breakpoint inside the action doesn't get hit):
POST /Validations/Bsb?value=
How can I get the API to accept an empty value of value, when it seems to mess up model binding?
I have an API endpoint which is implemented as follows:
[RoutePrefix("Validations")]
public class ValidationsController
{
[HttpPost, Route("Bsb")]
public IHttpActionResult ValidateBsb(]FromUri] string value)
{
var validator = new BankStateBranchValidator(DbContext.BankStateBranches);
var data = new ValidationsResult
{
IsValid = validator.IsValid(value ?? string.Empty)
};
data.Error = data.IsValid
? null
: "The BSB you have entered does not appear to be valid. Please check the value and try again.";
return Ok(data);
}
}
I can call the API successfully with the following API and get the expected result back:
POST /Validations/Bsb?value=012345
POST /Validations/Bsb
But if I make the following API call, then it fails with a 400 Bad Request generated by the framework itself (i.e. a breakpoint inside the action doesn't get hit):
POST /Validations/Bsb?value=
How can I get the API to accept an empty value of value, when it seems to mess up model binding?
I think in the post action method you should write the parameter like :
public ActionResult Get(string value = "") or public ActionResult Get(string value = null)
Hope it will help you.
Thanks!
ASP.NET consulting companies india
https://www.ifourtechnolab.com/asp-dot-net-enterprise-content-management
But if I make the following API call, then it fails with a 400 Bad Request generated by the framework itself (i.e. a breakpoint inside the action doesn't get hit):
The Web server throws the HTTP 400 Bad Request. No program code for the Web program is ever executed on the Web server, becuase the code was never reached, and therefore, no breakpoint is ever going to be hit.
it fails with a 400 Bad Request generated by the framework itself (i.e. a
breakpoint inside the action doesn't get
hit
Where did you set the breakpoint?
WyldeKarrde
get the API to accept an empty value of value
How do you request the api?
I use "/Validations/Bsb?value=" to test, the value of value is
empty.
Below is the code I tested:
using (var client = new HttpClient())
{
var response = await client.PostAsync("https://localhost:44345/Validations/Bsb?value=",new StringContent(""));
if (response.IsSuccessStatusCode)
{
}
}
Best Regards,
YihuiSun
.NET forums are moving to a new home on Microsoft Q&A, we encourage you to go to Microsoft Q&A for .NET for posting new questions and get involved today.
Thanks for pointing out my copy/paste errors! I've updated the original code example (it was originally a partial class and the `ApiController` base class was defined in a different part of the partial class); I've also added the default value for the parameter.
(your question 1)
To answer your second question: the breakpoint is set at the first line of the controller's action:
var validator = new BankStateBranchValidator(DbContext.BankStateBranches);
For your third question: the API is actually being run by an automated test suite, so I just give the tests a range of URIs to test. It uses RestSharp rather than HttpClient, but apart from that, there's nothing special. I ran Fiddler to capture the raw
failing request:
HTTP/1.1 400 Bad Request
Cache-Control: no-cache
Pragma: no-cache
Content-Length: 127
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/10.0
Date: Wed, 30 Sep 2020 05:18:32 GMT
{"Message":"The request is invalid.","ModelState":{"value.String":["A value is required but was not present in the request."]}}
I tried a different approach. Firstly, create a new class
public class BsbValue
{
public string value { get;set; }
}
then change the controller action to bind to that class:
[HttpPost, Route("Bsb")]
public IHttpActionResult ValidateBsb([FromUri]BsbValue value)
{
var validator = new BankStateBranchValidator(DbContext.BankStateBranches);
var data = new ValidationsResult
{
IsValid = validator.IsValid(value?.value ?? string.Empty)
};
data.Error = data.IsValid
? null
: "The BSB you have entered does not appear to be valid. Please check the value and try again.";
return Ok(data);
}
and that works correctly for all scenarios; the only issue that prevents me from using that is that it messes up the API definition (which is auto-generated using Swashbuckle). But at least it narrows down the issue to how WebAPI binds simple types to parameters.
Which doesn't explain why YihuiSun seems to have it working as expected in their screenshot...
OK, so it's probably a long-winded way of doing it, but this works for me: I created a custom model binder as follows:
public class OptionalSimpleTypeModelBinderProvider : ModelBinderProvider
{
public override IModelBinder GetBinder(HttpConfiguration configuration, Type modelType)
{
return new OptionalSimpleTypeModelBinder();
}
}
public class OptionalSimpleTypeModelBinder : IModelBinder
{
public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
{
var queryString = actionContext.Request.RequestUri.ParseQueryString();
bindingContext.Model = queryString[bindingContext.ModelName] ?? string.Empty;
return true;
}
}
then modify the controller action to be :
public IHttpActionResult ValidateBsb([ModelBinder(typeof(OptionalSimpleTypeModelBinderProvider))]string value = null)
{
// etc etc
}
It probably needs a little more work to make it useful for other types other than string, but at least for my immediate problem, this works (and doesn't break the Swagger definition either).
400 Bad Request generated by the framework itself (i.e. a breakpoint inside the action doesn't get hit):
The 400 (Bad Request) status code indicates that the server cannot or will not process the request because the received syntax is invalid, nonsensical, or exceeds some limitation on what the server is willing to process. It means that the request itself
has somehow incorrect or corrupted and the server couldn't understand it. The server is refusing to service the request because the entity of the request is in a format not supported by the requested resource for the requested method . Therefore, it prevents
the website from being properly displayed. The main thing to understand is that the
400 Bad Request error is a client-side error. The cause of a 400 error can be a wrongly written URL or a URL that contains unrecognizable characters. Another cause of the error might be an invalid or
expired cookie. Also, if you try to upload a file that's too large. If the server is programmed with a file size limit, then you might encounter a 400 error.
None
0 Points
4 Posts
POST with optional querystring values
Sep 29, 2020 02:53 AM|WyldeKarrde|LINK
I have an API endpoint which is implemented as follows:
I can call the API successfully with the following API and get the expected result back:
But if I make the following API call, then it fails with a 400 Bad Request generated by the framework itself (i.e. a breakpoint inside the action doesn't get hit):
How can I get the API to accept an empty value of value, when it seems to mess up model binding?
Member
115 Points
98 Posts
Re: POST with optional querystring values
Sep 29, 2020 04:16 AM|shaili shah|LINK
I think in the post action method you should write the parameter like :
public ActionResult Get(string value = "") or public ActionResult Get(string value = null)
Hope it will help you.
Thanks!
https://www.ifourtechnolab.com/asp-dot-net-enterprise-content-management
Contributor
4933 Points
4205 Posts
Re: POST with optional querystring values
Sep 29, 2020 04:21 AM|DA924|LINK
But if I make the following API call, then it fails with a 400 Bad Request generated by the framework itself (i.e. a breakpoint inside the action doesn't get hit):
The Web server throws the HTTP 400 Bad Request. No program code for the Web program is ever executed on the Web server, becuase the code was never reached, and therefore, no breakpoint is ever going to be hit.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/400
Contributor
2720 Points
777 Posts
Re: POST with optional querystring values
Sep 29, 2020 06:39 AM|YihuiSun|LINK
Hi WyldeKarrde,
I want to confirm some information with you:
public class ValidationsController:ApiController
using (var client = new HttpClient()) { var response = await client.PostAsync("https://localhost:44345/Validations/Bsb?value=",new StringContent("")); if (response.IsSuccessStatusCode) { } }
Best Regards,
YihuiSun
None
0 Points
4 Posts
Re: POST with optional querystring values
Sep 30, 2020 05:39 AM|WyldeKarrde|LINK
Hi YihuiSun,
Thanks for pointing out my copy/paste errors! I've updated the original code example (it was originally a partial class and the `ApiController` base class was defined in a different part of the partial class); I've also added the default value for the parameter. (your question 1)
To answer your second question: the breakpoint is set at the first line of the controller's action:
For your third question: the API is actually being run by an automated test suite, so I just give the tests a range of URIs to test. It uses RestSharp rather than HttpClient, but apart from that, there's nothing special. I ran Fiddler to capture the raw failing request:
and the raw response is:
None
0 Points
4 Posts
Re: POST with optional querystring values
Sep 30, 2020 05:46 AM|WyldeKarrde|LINK
I tried a different approach. Firstly, create a new class
then change the controller action to bind to that class:
and that works correctly for all scenarios; the only issue that prevents me from using that is that it messes up the API definition (which is auto-generated using Swashbuckle). But at least it narrows down the issue to how WebAPI binds simple types to parameters.
Which doesn't explain why YihuiSun seems to have it working as expected in their screenshot...
None
0 Points
4 Posts
Re: POST with optional querystring values
Sep 30, 2020 06:53 AM|WyldeKarrde|LINK
OK, so it's probably a long-winded way of doing it, but this works for me: I created a custom model binder as follows:
then modify the controller action to be :
It probably needs a little more work to make it useful for other types other than string, but at least for my immediate problem, this works (and doesn't break the Swagger definition either).
None
0 Points
14 Posts
Re: POST with optional querystring values
Dec 30, 2020 07:04 AM|EvanChatter|LINK
The 400 (Bad Request) status code indicates that the server cannot or will not process the request because the received syntax is invalid, nonsensical, or exceeds some limitation on what the server is willing to process. It means that the request itself has somehow incorrect or corrupted and the server couldn't understand it. The server is refusing to service the request because the entity of the request is in a format not supported by the requested resource for the requested method . Therefore, it prevents the website from being properly displayed. The main thing to understand is that the 400 Bad Request error is a client-side error. The cause of a 400 error can be a wrongly written URL or a URL that contains unrecognizable characters. Another cause of the error might be an invalid or expired cookie. Also, if you try to upload a file that's too large. If the server is programmed with a file size limit, then you might encounter a 400 error.