Post json data in body to web api - asp.net

I get always null value from body why ?
I have no problem with using fiddler but postman is fail.
I have a web api like that:
[Route("api/account/GetToken/")]
[System.Web.Http.HttpPost]
public HttpResponseBody GetToken([FromBody] string value)
{
string result = value;
}
My postman data:
and header:

WebAPI is working as expected because you're telling it that you're sending this json object:
{ "username":"admin", "password":"admin" }
Then you're asking it to deserialize it as a string which is impossible since it's not a valid JSON string.
Solution 1:
If you want to receive the actual JSON as in the value of value will be:
value = "{ \"username\":\"admin\", \"password\":\"admin\" }"
then the string you need to set the body of the request in postman to is:
"{ \"username\":\"admin\", \"password\":\"admin\" }"
Solution 2 (I'm assuming this is what you want):
Create a C# object that matches the JSON so that WebAPI can deserialize it properly.
First create a class that matches your JSON:
public class Credentials
{
[JsonProperty("username")]
public string Username { get; set; }
[JsonProperty("password")]
public string Password { get; set; }
}
Then in your method use this:
[Route("api/account/GetToken/")]
[System.Web.Http.HttpPost]
public HttpResponseBody GetToken([FromBody] Credentials credentials)
{
string username = credentials.Username;
string password = credentials.Password;
}

You are posting an object and trying to bind it to a string.
Instead, create a type to represent that data:
public class Credentials
{
public string Username { get; set; }
public string Password { get; set; }
}
[Route("api/account/GetToken/")]
[System.Web.Http.HttpPost]
public HttpResponseBody GetToken([FromBody] Credentials value)
{
string result = value.Username;
}

Related

Cannot parse Json from HTTP request to Model class C#

I have a HTTP Post request like below:
[HttpPost]
[Route("edit-request")]
public async Task<IActionResult> EditRequet(Json request)
{
var response = await _claimProcessorService.ProcessClaim(request);
return Accepted(response);
}
The model class Json has:
public class Json
{
public string Prop1 { get; set; }
public string Prop2 { get; set; }
}
The Request data can be both cases as shown below.
Case I:
{
"Prop1": 1234,
"Prop2": "test"
}
Case II
{
"Prop1": "1234",
"Prop2": "test"
}
The Case I does not trigger the API whereas, the Case II is running smoothly. But I need both of the request to run
Since Json's Prop1 is a string and in Case I you pass an integer this will not work.
You should probably make Prop1 an integer and have the client always send this value as an integer instead of a string.
Alternatively you could create a second endpoint that accepts Prop1 as a string.
Finally, you could create a custom JsonConverter that converts strings to numbers - if convertible.
However both the second and the third solution are really bad, I would go with the first and avoid these.

Swagger UI doesn't render body parameter field for my complex type parameter in GET action of my Controller

I have an ASP.NET Web API 2 project to which I have added Swagger - Swashbuckle v5.6.0. Everything works fine. Swagger UI renders test endpoints for my API as expected.
I added a new Controller to my API. There is a GET action with a complex type parameter. For complex types, Web API tries to read the value from the message body. This is the default behaviour.
Here is my GET action:
[HttpGet]
[Route("search")]
[ResponseType(typeof(List<SearchModel>))]
public IHttpActionResult Search(SearchModel searchOptions)
{
//....
return Ok();
}
And her is my complex type:
public class SearchModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
[DataType(DataType.EmailAddress)]
[EmailAddress]
public string Email { get; set; }
public string AddressLine1 { get; set; }
public string City { get; set; }
public string Telephone { get; set; }
public string MobilePhone { get; set; }
}
The problem:
But Swagger UI doesn't render body parameter field for my complex type in the GET action. For POST and PUT actions Swagger UI renders body parameter fields as expected but not for the complex type in my GET action.
As can be seen in the screenshot Swagger UI renders query parameters fields for attributes in my complex type instead of rendering a body parameter field for my type as it does in the case of POST and PUT.
My GET action is working fine when testing from Postman and filling the json in the body of the request. By setting breakpoint in the action inside Visual Studio I can see the values are bound to my object in the action parameter.
I have tried to decorate the parameter in my action with [FromBody] (which is the default for complex type) but same result.
Is this a bug in Swagger? Or am I missing something?
Sadly, you can't do what you want with Swagger. You can't send a request model in an HTTP GET method. You can however change the swagger UI to look like this:
but you won't be able to receive the model in your controller.
This is a known issue within the Swagger developers and it was discussed in 2016 and the final decision is that swagger won't support a request body in an HTTP GET method. Here is the link to the already closed issue.
You have three options here:
Leave the method as it is, and test it in Postman, but not in Swagger.
Follow the below steps to achieve the picture above, but please note, that it will only fix the UI part and you will always end up with null SearchModel in the controller when you press Try it out! in swagger.
Make it a [HttpPost method instead of [HttpGet].
How to make swagger UI display GET method with request body:
First, create one Attribute class:
public class ModelInBodyAttribute : Attribute
{
public ModelInBodyAttribute(string modelName, string description, bool isRequired)
{
this.ModelName = modelName;
this.Description = description;
this.IsRequired = IsRequired;
}
public string ModelName { get; set; }
public bool IsRequired { get; set; }
public string Description { get; set; }
}
Then you can decorate your method in the controller:
[ModelInBody(modelName: nameof(SearchModel), description: "My model description", isRequired: true)]
[HttpGet]
[Route("search")]
[ResponseType(typeof(List<SearchModel>))]
public IHttpActionResult Search(SearchModel searchOptions)
{
//....
return Ok(new List<SearchModel>());
}
After that create IOperationFilter class (ModelInBodyOperationFilter):
public class ModelInBodyOperationFilter : IOperationFilter
{
public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
{
var attribute = apiDescription.GetControllerAndActionAttributes<ModelInBodyAttribute>().FirstOrDefault();
if (attribute == null)
{
return;
}
operation.parameters.Clear();
operation.parameters.Add(new Parameter
{
name = attribute.ModelName,
description = attribute.Description,
#in = "body",
required = attribute.IsRequired,
schema = new Schema { #ref = $"#/definitions/{attribute.ModelName}" }
});
}
}
Lastly, don't forget to register the IOperationFilter in SwaggerConfig:
c.OperationFilter<ModelInBodyOperationFilter>();
When you send the request via swagger, you will notice that the Curl part is absolutely correct, but still, in your controller there is nothing.
There are endless discussions on whether you should have a PAYLOAD "Body content" in a GET request. As you mentioned it's supported by HTTP but you will find in the internet that many people suggest not to do it. I guess that swagger team also expect you not to use it.

Asp.Net Web Api multiple files with additional data for each

I am trying to send multiple files along with some data for every file. This is my model:
public class FileDTO
{
[Required]
public IFormFile File { get; set; }
[Required]
public string CategoryName { get; set; }
[Required]
public string CategoryDescription { get; set; }
public string Detail { get; set; }
}
This is my controller:
[HttpPost("Upload/{id:int}")]
public async Task<IActionResult> Upload(int id, IEnumerable<FileDTO> appFileDTOs)
{
...
}
Is this even a correct way to do so? How do I send such a request in Postman to simulate it?
Thanks in advance!
Edit
I tried it like this in Postman:
Everything submits correctly besides the image. For some reason the image is always null...
[] represents collection/dictionary index while dot(.) represents there's a property.
So you should rename all the field names with the dot representation.
For example, change
appFileDTOs[0][File]
to
appFileDTOs[0].File
Demo
try this it may help you,
send from formData.
in model key send value as
[
{
"CategoryName":"Category1",
"CategoryDescription ":"Category1 Description",
"Detail":"Details "
},
{
"CategoryName":"Category2",
"CategoryDescription ":"Category2 Description",
"Detail":"Details2"
}
]
and for file send first file as file1 and second file as file2;
In server side , remove IEnumerable of FileDTO appFileDTOs from method name.
get value of model as
var data = JsonConvert.DeserializeObject<List<FileDTO>>(Request.Form["model"]);
simillary for file
var fileUpload1 = Request.Form.Files["file1"];
var fileUpload2 = Request.Form.Files["file2"];

Deserializing of untrusted data using C#

I have the following C# code which is getting a "high" error from Checkmarx. I can't see anything wrong with it.
var dataDirectoryPath = AppDomain.CurrentDomain.GetData("DataDirectory").ToString();
var json = File.ReadAllText($"{dataDirectoryPath}{Path.DirectorySeparatorChar}somefile.json");
var settings = new
JsonSerializerSettings{TypeNameHandling=TypeNameHandling.None};
var targetPathSettings = JsonConvert.DeserializeObject<List<TargetPathSetting>>(json, settings);
It gives this error:
The serialized object ReadAllText processed in xxx in the file yyy is deserialized by DeserializeObject in the file zzz
The C# code is as follows:
public class TargetPathSetting
{
public string PathSettingName { get; set; }
public PathSetting PathSetting { get; set; }
}
public class PathSetting
{
public string BaseUrl { get; set; }
public string ApplicationIdUri { get; set; }
}
I can't see that anything that is ever in the file is going to cause any sort of problem, especially with the TypeNameHandling.None setting.
The problem is with the standard Checkmarx query for c #. In this case, Checkmarx does not recognize the correction of this code. To fix it you should use CxAudit and modify this query.

Deserializing a PHP json encoded (json_encode) string with ASP.NET webservices

I am really struggling deserializing a PHP json encoded string in ASP.NET.
I am using nusoap and CakePHP 1.3 on the PHP side and mvc.net 4.0 on the web service side and everything was working well. However, I couldn’t figure out how to pass a complex array as one parameter of the webservice, so I had the idea of serializing it as json and passing a simple string. So far so good...
But I cannot for the life of me de-serialize the json_encoded string in ASP.NET [well, I’ve been trying for the last two hours at least ;)]
Here is what I have so far:
The PHP sends an array of products (product id as a GUID - sent as a string then converted on the web service side) and the number of products:
$args['products'] = json_encode($booking['Booking']['prs_products']);
This is received ok by the webservice as the following json string (products):
[{"BookingProducts":{"id":"2884f556-67ed-4eb8-98ca-a99dc27a2665","quantity":2}},{"BookingProducts":{"id":"f57854ba-0a9b-400b-bea0-bafdcb179b01","quantity":2}},{"BookingProducts":{"id":"7ff81128-c33c-4e6c-a33c-3ca40ccfb5d0","quantity":2}}]
I then try and populate a BookingProducts List<>. The BookingProducts class is as follows:
public class BookingProducts
{
public String id { get; set; }
public int quantity { get; set; }
public BookingProducts()
{
}
public BookingProducts(string id, int quantity)
{
this.id = id;
this.quantity = quantity;
}
}
I have tried both the [System.Web.Script.Serialization][2] and Newtonsoft.Json libraries as follows, but without success:
List<BookingProducts> productsList = new List<BookingProducts>();
try
{
productsList = JsonConvert.DeserializeObject<List<BookingProducts>>((products));
}
catch (Newtonsoft.Json.JsonSerializationException)
{
productsList = new JavaScriptSerializer().Deserialize<List<BookingProducts>>(products);
}
In both cases I get a list of empty products (or a serialization exception).
Hopefully someone has done this before, or can spot an obvious mistake!
What you really have here is a list of objects containing BookingProducts object. In order to deserialize it, you need to have something like this for your entity:
public class BookingProductsWrapper
{
public class BookingProductsInner
{
public string id { get; set; }
public int quantity { get; set; }
}
public BookingProductsInner BookingProducts { get; set; }
}
Now you can deserialize it using JavaScriptSerializer (for example):
System.Web.Script.Serialization.JavaScriptSerializer jsSerializer = new System.Web.Script.Serialization.JavaScriptSerializer();
List<BookingProductsWrapper> productsList = jsSerializer.Deserialize<List<BookingProductsWrapper>>(products);
That will do the trick.

Resources