I have the following method in my WebAPI 2 project.
public class TestController : ApiController
{
[HttpPost]
public void Test(HttpRequestMessage request)
{
var content = request.Content;
string jsonContent = content.ReadAsStringAsync().Result;
}
}
My custom object looks like this;
public class Test
{
public int Id { get; set; }
public string Name { get; set; }
}
If I post some sample data like
<Test>
<Id>12345</Id>
<Name>My Name</Name>
</Test>
The resulting value in jsonContent is correct. My question is how best should I serialise the HttpRequestMessage (content) into my object Test so that I can perform additional validation / tasks etc.
Should I pass HttpRequestMessage into the method or is it possible to pass something like
public void Test(Test oTest)
It sounds like you're asking how to deserialize jsonContent into a new instance of your Test class, as the first comment mentions above. I would suggest looking into Json.NET. Then you could do something like:
public class TestController : ApiController
{
[HttpPost]
public void Test(HttpRequestMessage request)
{
var content = request.Content;
string jsonContent = content.ReadAsStringAsync().Result;
Test test = new Test();
test = JsonConvert.DeserializeObject<Test>(jsonContent);
//Do validation stuff...
}
}
You can use a parameter in your action method like this.
[HttpPost]
public void Test(Test oTest)
ASP.NET Web API will deserialize the request message body (JSON or XML) into Test. Based on the content type header in the request, web API can handle both JSON and XML content out-of-box. In the case of XML, Web API uses DCS, by default. The XML you have shown in your post will not get deserialized as-is. Try returning a Test object and see how it gets serialized by web API and use the same XML in your POST request for binding to work correctly.
BTW, if you use the Test parameter in your action method, Web API will consume the request body stream. So, you will not be able to read it inside the action method like what you are doing.
Related
I tried to send a JSON object with the same name that action argument has but It seems not working I don't know what I did wrong.
My question is how to bind simple types like the example shown, without the need to create complex type that wrap my value property?
Action
public IActionResult Test([FromBody] string value)
{
}
PostMan : raw > JSON
{
"value":"testValue"
}
public class MyRequest {
public string Value { get; set; }
}
//controller
IActionResult Test([FromBody] MyRequest request)
This should do the job.
The class/type related to the frombody object should match the whole json object and not only one property of it
This cannot work with GET requests, so try a POST
I have ApiController which receives a specific object of a class. That works perfect but what if, HTTP Request which contains a body with JSON is not matching with the object of a class? I will receive a null value of object because there is not a match between JSON and object of a class. My question is, how to get original JSON request when a user sends JSON with an incorrect format?
public class Document{
string name;
int number;
}
JSON REQUEST
{
"name":"Default name",
"number":91526861713"
}
JSON IS INCORRECT BECAUSE DATA TYPE OF number is int, not string "234" !
Automatically documentObject in function is equal to null.
How to get original JSON REQUEST?
[HttpPost]
public IHttpActionResult Receiving([FromBody]Document documentObject)
{
}
you can use Request.Content , But output is raw string.
like this:
[HttpPost]
public async Task<IHttpActionResult> Receiving([FromBody]Document documentObject)
{
var content = await Request.Content.ReadAsStringAsync();
return Json(content); // output => "name=xxx&number=123"
}
I'm having a problem with a Get method in my Web API: The API gets the object but with the default values.
For instance:
myRefitClient.GetSummary(new MyClass() { Prop = 1 });
The Web API correctly receives a MyClass instance, but Prop is 0!
This is all that I have:
The Get method (Controller in the Web API):
[HttpGet]
async Task<ActionResult> Get([FromQuery]MyClass req)
MyClass is:
public class MyClass
{
public int Prop { get; set; }
}
and my Web API interface for Refit is:
public interface IMyWebApi
{
[Get("/api/mycontroller")]
Task<PositionSummary> GetSummary(MyClass req);
}
So, as I said, upon the call:
service.GetSummary(new MyClass() { Prop = 1 });
I'm getting a MyClass Instance in my Controller, but Prop is 0, instead of 1.
What am I doing wrong?
To force ASP.NET Web API (not ASP.NET Core) to read a complex type from the URI, add the [FromUri] attribute to the parameter:
[HttpGet]
public async Task<ActionResult> Get([FromUri]MyClass req)
If you are using ASP.NET Core then use [FromQuery] attribute
[HttpGet]
public async Task<ActionResult> Get([FromQuery]MyClass req)
I'm getting a MyClass Instance in my Controller, but Prop is 0,
instead of 1.
If /api/mycontroller is set as launchUrl in launchSettings.json then you will get MyClass Instance with Prop = 0 at the start of application. But next call using Refit should pass parameters
I think your problem is model binding. The way refit serializes your object and how API serialization/deserialization works should match. Refit has serialization settings, you need to adjust. can you look it that?
Take a look at :
https://reactiveui.github.io/refit/
Under JSON content section.
Similarly, your API should work with the same serialization settings. You can configure it at your services in Startup.cs
The solution was to implement IFormattable. Found that after going through the Refit source code, weird it's not documented.
I am making an HTTP POST method to get data. I have an idea to create a method to get a specific arguments but when I don't have idea to get the arguments taken. In HTTP GET, arguments are in the URL and is more easy to get the arguments. How do I create a method to take all the data in HTTP Post? In PHP for example when you show the var $_POST you show all data in the body post. How can I do this in C#?
My method is this:
[HttpPost]
[AllowAnonymous]
public IHttpActionResult Test()
{
// Get URL Args for example is
var args = Request.RequestUri.Query;
// But if the arguments are in the body i don't have idea.
}
Web API has a feature which automatically binds argument posted to an action inside a controller. This is called Parameter Binding. It allows you to simply request the object inside the URL or the body of the POST request, and it does the deserialization magic for you using a thing called Formatters. There is a formatter for XML, JSON, and other known HTTP request types.
For example, lets say I have the following JSON:
{
"SenderName": "David"
"SenderAge": 35
}
I can create an object which matches my request, we'll call it SenderDetails:
public class SenderDetails
{
public string SenderName { get; set; }
public int SenderAge { get; set; }
}
Now, by receiving this object as a parameter in my POST action, I tell WebAPI to attempt to bind that object for me. If all goes well, I'll have the information available to me without needing to do any parsing:
[Route("api/SenderDetails")]
[HttpPost]
public IHttpActionResult Test(SenderDetails senderDetails)
{
// Here, we will have those details available,
// given that the deserialization succeeded.
Debug.Writeline(senderDetails.SenderName);
}
If I get you Correctly, in C# you use the [HttpPost] attribute to expose a post method.
[HttpPost]
public IHttpActionResult Test()
{
// Get URL Args for example is
var args = Request.RequestUri.Query;
// But if the arguments are in the body i don't have idea.
}
I have this code:
[Route]
public HttpResponseMessage PostData[FromBody] DataModel data)
{
... implementation...
}
This automatically binds / converts the json data to my data model. However, I would like to save / catch the raw json file that was posted and save it for logging purposes.
Any suggestions on how I can achieve this?
You can just do the below and then use JSON converter to convert the string to JSON later.
[HttpPost]
public HttpResponseMessage PostData([FromBody] string text)
{
// log text.
DataModel data = JsonConvert.DeSerialize<DataModel>(text);
}
Or you can also do,
[HttpPost]
public HttpResponseMessage PostData()
{
string text = Request.Content.ReadAsStringAsync().Result;
//log text
DataModel data = JsonConvert.DeSerialize<DataModel>(text);
}
Since you mention it is for logging, you might want to consider doing this in a Web API filter or a delegating handler - to make the logic more centralized instead of having the logic in each action method.
public class LogApiRequest : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
var text = actionContext.Request.Content.ReadAsStringAsync().Result;
MyLogger.Log(LogLevel.INFO, text);
base.OnActionExecuting(actionContext);
}
}
and then register your filter - typically in WebApiConfig.cs or decorate your action method or controller class with the filter.
config.Filters.Add(new LogApiRequest());