How can I debug an invalid POST body? - serialization

I have a method in my controller whose signature looks like this:
[HttpPost]
public IActionResult Post([FromBody] MyDataType value)
When my frontend sends the POST data, it never even reaches this method, erroring out and returning HTTP 400 (Bad Request). The response body says:
{"lastUpdated":["The supplied value is invalid."]}
The value of the invalid lastUpdated property being sent is:
"June 13, 2018, 14:05:48"
On my MyDataType class, the LastUpdated property is defined like so:
[JsonConverter(typeof(Converters.DateFormatConverter))]
public DateTime LastUpdated { get; set; }
And the DateFormatConverter is a Newtonsoft.Json serialization converter that specifies the correct format for datetime values:
public class DateFormatConverter : IsoDateTimeConverter
{
public DateFormatConverter()
{
DateTimeFormat = "MMM' 'dd', 'yyyy', 'HH':'mm':'ss";
}
}
As near as I can tell, this format matches the data being sent, and yet it's failing to validate. Whatever's going wrong is not in any code of mine that I can place a breakpoint in, so how do I debug this and figure out what's going wrong?

The correct format is "MMMM' 'dd', 'yyyy', 'HH':'mm':'ss"

Related

asp.net core api - how to distinguish between `api/cars` and `api/cars?color=red` calls with [FromQuery] object

I am using [FromQuery] atribute in controller's Get method:
//CarsController, etc..
[HttpGet]
public async Task<ActionResult<IEnumerable<CarsDto>>> Get([FromQuery] CarsParameter? carsParam = null)
{
//param is always not null here
}
Inside the method I need to distinguish between api/cars and api/cars?color=red calls. Problem is, that carsParam object is never null, so I cannot say if the Color="" (defailt value) is intended to be empty string or it's because of the call was api/cars
CarsParameter is a simple class:
public class CarsParameter
{
public string Color {get; set;} = "";
//more params here
}
Yes, I can use different path, like api/cars/withParams?color=red, but i am looking for more subtle solution.
I need to distinguish between api/cars and api/cars?color=red calls. Problem is, that carsParam object is never null
Please note that default model binding starts by looking through the sources for the key carsParam.Color. If that isn't found, it looks for Color without a prefix, which cause the issue.
To achieve your requirement, you can try to specify prefix explicitly, like below.
public async Task<ActionResult<IEnumerable<CarsDto>>> Get([FromQuery][Bind(Prefix = "carsParam")] CarsParameter? carsParam = null)
{
Request to api/cars?color=red&carsParam.color=yellow&carsParam.brand=test and following is test result

What's causing the parameter to be null?

I am using Asp.Net Core 2.0 and web api to build a rest service. All works fine except for HTTPPost.
[HttpPost("LoginUser")]
public IActionResult LoginUser(LoginUser loginUser)
{
return Ok(loginUser);
}
loginUser is always null. I am testing with fiddler and my route is http://localhost:53250/api/User/LoginUser
and the body is
{"EmailAddress":"xx#xx.com","Password":"123456789"}
Fiddler hits the link just fine, but payload is always null.
I have also tried
[HttpPost("LoginUser")]
public IActionResult LoginUser([FromBody] LoginUser loginUser)
{
return Ok(loginUser);
}
In this case, it doesn't hit the function.
This is the LoginUser definition:
public class LoginUser
{
public string EmailAddress { get; set; }
public string Password { get; set; }
}
Any Ideas?
Your action should be:
[Route("api/[controller]")]
public class UserController : Controller
{
[HttpPost("LoginUser")]
public IActionResult LoginUser([FromBody] LoginUser loginUser)
{
return Ok(loginUser);
}
}
See, [HttpPost("LoginUser")] affects only route and doesn't relate to LoginUser object type.
Update: you need [FromBody] as ASP.NET Core model binding by default looks into [FromForm] binding source. And [FromBody] attribute indicates that you want to bind a parameter to data in the request body.
Update 2: you also should add Content-Type: application/json header to request. ASP.NET Core selects input formatters based on the this header.
Update 3: if you really need to get body data as raw string, look into ASP.NET Core MVC : How to get raw JSON bound to a string without a type?. It suggests using [FromBody] dynamic data
JSON parsing is case sensitive. Your JSON is in the wrong case.
Should be: {"EmailAddress":"xx#xx.com","Password":"123456789"}.
Issue has been solved. When I added my UserController, I did so as a class and derived from controller. I deleted it and added it as a new item and picked web api core controller. Now all is working just fine. Thanks for your help.
If you have properties in your request model that are set to {get;
private set;}, the values will not get populated. Make them public by removing private. Also constructors
aren't utilized.
If you're reading plain text from the body, see if [FromForm]
works.

Is there an automated mechanism where I can detect if any email field is missing?

Let's assume this class:
public class AccountInfo
{
public string Email;
public string Username;
public string Password;
}
and this ASP api:
[HttpPost, Route("create")]
public IActionResult CreateUser([FromBody]AccountInfo Info)
{
...
}
If a user passes something like this:
{
"eail" : "ndienw", <--- notice the mispelling
"username" : "djiw",
"password" : "dow"
}
The email field will be null, so I need in each call to check for every fields.
Is there an automated mechanism where I can detect if any field is missing? I'm looking for something generic that can be applied through all calls.
Being able to opt out and mark some parameters optional would be great, but in our case, everything is always needed so far.
In this scenario, the ModelState is still valid; is that the expected behavior?
You can use data annotations on your Email property. RegularExpression attribute will check the field that located on, whether the value which provided is matching with this pattern. Required attribute checks whether this field is empty or not.
[RegularExpression(#"\w+([-+.']\w+)*#\w+([-.]\w+)*\.\w+([-.]\w+)*", ErrorMessage = "Email was invalid.")]
[Required]
public string Email;

ASP.NET Web API 2 primitive type from body (boolean) error

I have an action
[HttpPatch]
public IHttpActionResult foo(int id, [FromBody]bool boolVariable)
{
return Ok();
}
I am still debugging and when I try to send some data with Postman I get a strange error
"Message": "The request is invalid.",
"MessageDetail": "The parameters dictionary contains a null entry for parameter 'boolVariable' of non-nullable type 'System.Boolean' for
method 'System.Web.Http.IHttpActionResult foo(Int32,
Boolean)' in 'ProjectName.Controllers.NameController'. An optional
parameter must be a reference type, a nullable type, or be declared as
an optional parameter."
The problem is that it isn't binding boolVariable with my json body... yea I can easily solve the problem with a bind model
public class FooBindModel
{
public bool boolVariable{ get; set; }
}
public IHttpActionResult foo(int id, FooBindModel bindModel)
{
return Ok();
}
However it's bugging me why doesn't it bind the variable from the json's body? I am specifying [FromBody] in the action parameters...
This is actually a case where you really need to use the often misused [FromBody] attribute.
Web Api will by default try to read the request body as an object which makes the [FromBody] attribute redundant when dealing with objects.
But when you have a value type in your request body then you need to tell Web Api that you want to get your value type from the body and that is what [FromBody] does.
So to solve this you should specify the [FromBody] bool boolVariable and only send the bool value in the body, i.e
true
Read more under the Using [FromBody] section

WCF 4: Passing Empty parameters on a GET request

I'm creating an API which will just use a get request to return some search results from the database, I'm trying to make it so that optional parameters can be passed (easy with WCF) but also so that if parameters are specfied in the query string as long as they are empty they will be ignored by the service.
However if you have the a query string with empty parameters it will return a bad request (400) by the server e.g.
Using a end-user point of your choice pass the following querystring
http://www.exampleservice.com/basic/?apiKey=1234&noOfResults=3&maxSalary=&minSalary=&ouId=0&keywords=Web+Developer
Note that maxSalary and minSalary are not passing values
You then have the following WCF service:
[OperationContract]
[WebGet(UriTemplate = "basic/?apiKey={apiKey}&noOfResults={noOfResults}&maxSalary={maxSalary}&minSalary={minSalary}&ouId={ouId}&keywords={keywords}", BodyStyle = WebMessageBodyStyle.Bare)]
public List<SearchResultsDto> BasicSearch(string keywords, string apiKey, int noOfResults, int maxSalary, int minSalary, int ouId)
{
//Do some service stuff
}
This will cause a 400 error, please can someone explain how you pass empty parameters across to a WCF service or is this just not possible?
Currently passing null or an empty parameter is not supported in WCF, the main solution to this problem is to override the querystringconverter which handles the url as it comes through the pipe but before it reaches the operation contract.
An excellent example of implmenting an extension of the querystringconverter is found here:
In the WCF web programming model, how can one write an operation contract with an array of query string parameters (i.e. with the same name)?
HOWEVER
sadly there is a bug in WCF 4 where you cannot override the querystringconverter, this has been addressed by Microsoft and will be fixed in the SP1 release coming this year.
Until then there is no clean way to deal with this situation other than to handle the exception and return a status code of 400 (bad request) - good documentation of the api should handle this in the interim.
Is it just the integers giving you trouble? Maybe you can try making them nullable?
int? MaxSalary
hope this helps
You could send in "-1", and treat that in your business logic as not sent.
It can be handled in multiple ways. Since you are talking about a REST service that can have optional parameters, my suggestion will be do the something like this.
Create a DataObject that will be accepeted as parameter to this method.
[ServiceContract]
public interface IService1
{
[OperationContract]
[WebGet(RequestFormat=WebMessageFormat.Json)]
RequestObject BasicSearch(RequestObject apiKey);
}
public class Service1 : IService1
{
public RequestObject BasicSearch(RequestObject obj)
{
//Do some service stuff
return obj;
}
}
[DataContract]
public class RequestObject
{
[DataMember]
public string Keywords {get; set;}
[DataMember]
public string ApiKey {get; set;}
[DataMember]
public int NoOfResults { get; set; }
}
Advantages (am going to be short, ping me back for details)
No change in service signature
contract does not change
you will get the flexibility of have
null parameters
you can always extend the number of
parameters without any impact to
existing services
below is the sample input and output from fiddler
note: in the request part i havent passed anything to NumberOfResults intentionally to prove