OWIN ApiController access to the request body/stringified JSON - c#

This is in OWIN & .Net 4.5.2
Using debug I'm proving this controller's method is being called by the web request.
My thing is the request body contains a JSON stringified object:
"{ 'id':'12', 'text1':'hello', 'test2':'world' }"
Which is applicably encoded as it is transferred on the line.
I've tried so many things I'm so confused now.
How do I get the decoded string so I can JSON.Parse() that or better yet get .Net to just given me an object?
In one version (long ago now) I had a defined type for this object. If I need that great, not a high challenge. But if I only have the JSON object from the string that's fine too.
public class cController : ApiController {
[HttpPut]
public string put(string id) {
var bdy = this.Request.Content;
//Console.WriteLine("PUT containers {0}", body);
return string.Empty;
}
}
In case it helps, the bdy.ContentReadStream is null. I don't know if this is good, bad, or important. Maybe Request.Content isn't the way to go but seems to me like if I'm going to read the body as a stream then it shouldn't be null.
I also tried working through System.Web.HttpContext. If that is somehow the answer I have no problem going back to that. But I couldn't find the secret sauce.

Pass the desired model as a parameter to the action and the frame work should be able to parse it provided it is valid JSON
public class cController : ApiController {
[HttpPut]
public IHttpActionResult Put(string id,[FromBody] Model body) {
if(ModelState.IsValue) {
return Ok(body.text1);
}
return BadRequest();
}
}
Where Model is defined as
public class Model {
public string id { get; set; }
public string text1 { get; set; }
public string test2 { get; set; }
}

Related

Converting from a dynamic data type in c# to a .net Object

I have a method that receives some data from a 3rd party. The data is a JSON object (not a string, I tried receiving as a string and data was not accessable - the data property was null)
[HttpPost]
[Route("com/sendemail")]
public async Task<IActionResult> SendEmail(dynamic data)
{
mailData = JsonConvert.DeserializeObject<EmailTemplate>(data);
}
I am trying to get it into a .net object which is needed to be passed into another function I dont control. It has to be an EmailTemplate object, which is defined as:
public class EmailTemplate
{
public string From { get; set; }
public string To { get; set; }
public string Subject { get; set; }
public string EmailHtml { get; set; }
}
mailData is of type EmailTemplate. The Deserialize object call fails because that method requires a string, which this isnt. Ive tried other methods, such as
mailData = (EmailTemplate)data;
and
mailData.To = data.To
but neither work. Any pointers gratefully received.
PS. Heres what the data looks like in visual studio
Your controller couldn't accept a string, because (I assume) the request's content-type is 'application/json' and the framework couldn't convert it to a string. You should change your controller's data parameter type to EmailTemplate:
[HttpPost]
[Route("com/sendemail")]
public async Task<IActionResult> SendEmail([FromBody] EmailTemplate data)
{
//...
}
When your class matches the Json-object that is sent, this will work:
public async Task<IActionResult> SendEmail([FromBody]EmailTemplate data)
When you use your dynamic approach, you need to access the dynamic objects members and create your .NET object with them.
public async Task<IActionResult> SendEmail([FromBody]dynamic data)
{
mailData = new EmailTemplate {
From = data.From,
To = data.To,
Subject = data.Subject,
EmailHtml = data.EmailHtml
};
}

How to Send Object Values in PostMan From FromData Calling a Web Api .net Method

I have a post Api method in my web api net core application thats has a Dto Class with the follow parameters:
public class ClassDto
{
public int Id { get; set; }
public Comunicacao Comunicacao { get; set; }
}
Comunicacao Class:
public class Comunicacao
{
public int Id { get; set; }
public string Name { get; set; }
}
Api Action(route has been setted correctly):
[HttpPost]
public async Task<IActionResult> Add([FromForm]ClassDto bannerDto, IFormFile imgDesktop)
{
try
{
if (ModelState.IsValid)
{
var result = await _banner.Add(classDto, imgDesktop);
return Ok(new { message = result.messageReturning, result.classDto });
}
else
{
return BadRequest(ModelState);
}
}
catch (Exception ex)
{
return BadRequest(ex.ToLogString(Environment.StackTrace));
}
}
So my question is, how can i send in postman using FormData passing Comunicacao Object Values? Because when i sent "Id", it works fine, but i cant find a way to send objects!
what i have tried yet
I cannot use FromBody because as you all can see im sending a File as well.
Finally got it.
Have to use the object.property!
put the iformfile object inside your dto making it a single dto method then ur endpoint will look like public async Task Add([FromForm]ClassDto bannerDto)
if you have put the iformfile outside cos of automapper then u can use [ignore] attribute over the property
sorry wanted to put this as comment for the previous answer but i am typing from mobile phone so ...meh
you can set body type to form-data and then in key value pair side just select file instead of text for your file upload

How do I put things in my RequestBody for my POST Method to find?

I am very new to ASP.NET Core, C#, and RESTful APIs. I'm trying to create a simple practice application right now to practice the different REST commands. The "database" I am working with is a List of objects that have a Name, Age, and Weight.
Currently I am trying to implement a POST method. I could potentially use a [FromQuery] in order to get the data I need for creating the new object and adding it. However, I think it would be better to access it FromBody, especially if I want to add more fields later on.
I don't quite understand/know how I would be able to put stuff/ask the user (??) for data for this in the body. I think I grasp that, when the URL is called, it parses through whatever is in the body of the page/the returned .json and finds it that way, but I don't know how to populate this in the first place.
So far this is just my code for the POST:
[HttpPost]
public ActionResult<List<Objects>> Post([FromQuery] String NewName, [FromQuery] int NewAge, [FromQuery] double NewWeight)
{
return MyList.AddItem(NewName, NewAge, NewWeight);
}
I would love any descriptions on how this works or how I can make this happen...thanks!
Create a model that holds all the required data
public class NewModel {
public String NewName { get; set; }
public int NewAge { get; set; }
public double NewWeight { get; set; }
}
update the action to expect that data and annotate it with [FromBody]
[HttpPost]
public ActionResult<MyModelType> Post([FromBody] NewModel data) {
if (ModelState.IsValid) {
var model = MyList.AddItem(data.NewName, data.NewAge, data.NewWeight);
return model;
}
return BadRequest(ModelState);
}
Consumers of your service would then post a request with the required data in the body of the request and the model binder should populate the model in the controller action.

define routing for complex data transport objects

Being able to define the routing like so:
Route("Calculator/AddTwoNumbers/a/{a}/b/{a}")]
public IHttpActionResult AddTwoNumbers(double a, double b)
is great to invoke an endpoint like this:
http://localhost:64466/Calculator/AddTwoNumbers/a/1/b/2
I am curious what to do in scenarios where the payload/data transport object (DTO) becomes more complex (i.e. hierarchical). Take above's excample, this may be a corresponding DTO:
public class PayLoad
{
public double a { get; set; }
public double b { get; set; }
}
something like this:
Route("Calculator/AddTwoNumbers/a/{a}/b/{a}")]
public IHttpActionResult AddTwoNumbers(PayLoad payLoad)
does not work as there does not seem to be 'model binding' (?) as in asp.net mvc.
What am I suppose to do if the DTOs are more complex?
You need to decorate your payLoad parameter definition with the [FromUri] attribute:
public IHttpActionResult AddTwoNumbers([FromUri] PayLoad payLoad)
See MSDN
I think there are 2 ways to solve get data with WepApi:
1- Using [FromUri]:
To force Web API to read a complex type from the URI, add the [FromUri] attribute to the parameter. The following example defines a GeoPoint type, along with a controller method that gets the GeoPoint from the URI.
public class GeoPoint
{
public double Latitude { get; set; }
public double Longitude { get; set; }
}
public ValuesController : ApiController
{
public HttpResponseMessage Get([FromUri] GeoPoint location) { ... }
}
The client can put the Latitude and Longitude values in the query string and Web API will use them to construct a GeoPoint. For example:
http://localhost/api/values/?Latitude=47.678558&Longitude=-122.130989
2- Using [FromBody]:
To force Web API to read a simple type from the request body, add the [FromBody] attribute to the parameter:
public HttpResponseMessage Post([FromBody] string name) { ... }
This code is explained here: Parameter Binding in ASP.NET Web API

POST object in .NET WebAPI

I have a small problem with the WebApi.
Problem:
If I want to post a model using JSON, I can add as many members I want, as long as the members defined in model are present.
Question:
How can I trigger an exception, if an undefined member is present in my Json object. Is this achievable without a custom JsonConverter?
What I'm looking for is a generic solution, not a convertion for every different model.
Example:
Model:
public class Person
{
[Required]
public string Name { get; set; }
}
Api Controller:
public class PersonController : ApiController
{
public HttpResponseMessage Post(Person person)
{
if (person != null)
{
if (ModelState.IsValid)
{
//do some stuff
return new HttpResponseMessage(HttpStatusCode.OK);
}
}
return new HttpResponseMessage(HttpStatusCode.BadRequest);
}
}
Json posts (body)
{"Name":"Joe"} --> valid
{"Name":"Joe","InvalidMember","test","Name","John"} --> also valid. In this case I want to trigger an Exception. Because if you look at it, it doesn't match my modeldefinition exactly.
One thing you could try is playing around with this setting:
config.Formatters.JsonFormatter.SerializerSettings.MissingMemberHandling = MissingMemberHandling.Error;
It should give you an invalid model state when there are extra properties that aren't recognized in the JSON.

Categories

Resources