Why is my request always coming in with null values - c#

I am writing a very basic and hacky React and c#/.NET app to try to sharpen my skills.
I am sending an axios request from the front but when it hits the route the data is always null.
call from the front end
axios
.post(URL, {
"name": "me",
"text": "Hello World",
"date": "today",
"userId": 1
})
.then(res => {return res})
My Message Class
public class Message
{
[Key]
public int MessageId { get; set; }
public string Date { get; set; }
public string Text { get; set; }
public int UserID { get; set; }
}
}
My controller method
public async Task<object> Post(Message message)
{
using (var context = new DbContext())
{
System.Diagnostics.Debug.WriteLine(message);
context.Messages.Add(message);
await context.SaveChangesAsync();
}
}
When I debug and hit the breakpoint all of my values are null.
What am I missing here?

The answer is to put the [FromBody] attribute before my argument like this
public async Task<object> Post([FromBody] Message message)
{
using (var context = new DbContext())
{
System.Diagnostics.Debug.WriteLine(message);
context.Messages.Add(message);
await context.SaveChangesAsync();
}
}
Thanks to the comment on on my original post!

Related

Add root element to response model

I'm writing an ASP.NET Core API, which should follow an existing format.
The response should always start with a data element in the json
{
"data": {
"batch_id": null,
"created_at": "2019-01-29T16:58:04+00:00",
"current_operation": null,
"description": "This watch has a new name",
"model": {
"brand_id": null,
"created_at": null,
...
}
}
}
I created a class Batch which contains all the properties that we see, and my controller is taking care of serialize it in the background.
public class Batch
{
[JsonProperty("label")]
public string Label { get; set; }
[JsonProperty("serial_number")]
public string SerialNumber { get; set; }
[HttpGet("{id}")]
public ActionResult<Batch> Get(string id)
{
...
return batch;
}
Is there a way to write something so that every payload has to start with a data property?
I would like to avoid writing a class DataWrapper<T> that I have to use for every response.
You could just use an anonymous object to wrap the response from the controller:
[HttpGet("{id}")]
public ActionResult<Batch> Get(string id)
{
...
return Ok(new { data = batch });
}
You can use GenericClass
public class GenericResponseClass<T>{
public T data;
}
then you can pass your batch(or any other) class to GenericResposneClass just like
public class Batch
{
[JsonProperty("label")]
public string Label { get; set; }
[JsonProperty("serial_number")]
public string SerialNumber { get; set; }
}
GenericResponseClass<Batch> response = new GenericResponseClass<Batch>();
Batch batch = new Batch();
batch.Label = "New Label";
batch.SerialNumber = "Serial Number";
response.data = batch;
then pass/serialize your response

Underlying class is not converted to json

Question:
Originally command is returning ExecutionResult, which contains Data property of type DomainOperationResult.
Only in one case I need to return some other data, which is defined as CreateOrderCommandResult which is descendant of DomainOperationResult, it contains additional field - Url.
Calling command with swagger, in the debugger, everything is shoing fine, visible id and url with Quick View.
Json(result);
it shows that it is returning Id and Url properties.
but in swagger, curl, postman, etc. only id is returned, tried everything.
there is no Url in response.
controller is working fine, no middlewares, that may change returned response.
Controller method:
{
public async Task<IActionResult> Create([FromBody] CreateOrderCommand command)
{
if (!ModelState.IsValid)
{
return await Task.FromResult(BadRequest(ModelState));
}
var result = await _commandExecutor.ExecuteAsync(command);
if (result.Success)
{
return Json(result);
}
return Json(result);
}
}
CreateOrderCommand:
{
public override async Task<CommandExecutionResult> ExecuteAsync()
{
// .....
return await OkAsync(new CreateOrderCommandResult(orderId, payment.RedirectUrl));
}
}
DomainOperationResult:
{
public class DomainOperationResult
{
public DomainOperationResult()
{
}
public DomainOperationResult(long id)
{
Id = id;
}
public long Id { get; }
}
CreateOrderCommandResult:
{
public class CreateOrderCommandResult : DomainOperationResult
{
public CreateOrderCommandResult()
: base() { }
public CreateOrderCommandResult(long id, string url)
: base(id)
{
Url = url;
}
public string Url { get; set; }
}
}
Execution result:
public class ExecutionResult
{
public ExecutionResult()
{
}
public DomainOperationResult Data { get; set; }
}
returned response:
{
"success": true,
"data": {
"id": 0
},
"error": {
"errors": null
}
}
Still no idea, why this does not works.
After some digging, found workaround.
Response.Headers.Add("Content-type", "application/json"); return Content(JsonConvert.SerializeObject(result, new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() }));
returning content like this works ok - at least it generates everything I need.

WEB API post from uri/ Query string in post

i have a model
public partial class TalentVendorShots
{
public int Id { get; set; }
public string Email { get; set; }
public string One { get; set; }
public string Two { get; set; }
public string Three { get; set; }
public string Four { get; set; }
public string Five { get; set; }
public string Six { get; set; }
public string Seven { get; set; }
public string Eight { get; set; }
public string Nine { get; set; }
public string Ten { get; set; }
}
and basic controllers
[Route("api/[controller]")]
[ApiController]
public class TalentVendorShotsController : ControllerBase
{
private readonly champagneDatabase _context;
public TalentVendorShotsController(champagneDatabase context)
{
_context = context;
}
// GET: api/TalentVendorShots
[HttpGet]
public async Task<ActionResult<IEnumerable<TalentVendorShots>>> GetTalentVendorShots()
{
return await _context.TalentVendorShots.ToListAsync();
}
// GET: api/TalentVendorShots/5
[HttpGet("{id}")]
public async Task<ActionResult<TalentVendorShots>> GetTalentVendorShots(int id)
{
var talentVendorShots = await _context.TalentVendorShots.FindAsync(id);
if (talentVendorShots == null)
{
return NotFound();
}
return talentVendorShots;
}
// PUT: api/TalentVendorShots/5
[HttpPut("{id}")]
public async Task<IActionResult> PutTalentVendorShots(int id, TalentVendorShots talentVendorShots)
{
if (id != talentVendorShots.Id)
{
return BadRequest();
}
_context.Entry(talentVendorShots).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!TalentVendorShotsExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return NoContent();
}
// POST: api/TalentVendorShots
[HttpPost]
public async Task<ActionResult<TalentVendorShots>> PostTalentVendorShots(TalentVendorShots talentVendorShots)
{
_context.TalentVendorShots.Add(talentVendorShots);
await _context.SaveChangesAsync();
return CreatedAtAction("GetTalentVendorShots", new { id = talentVendorShots.Id }, talentVendorShots);
}
// DELETE: api/TalentVendorShots/5
[HttpDelete("{id}")]
public async Task<ActionResult<TalentVendorShots>> DeleteTalentVendorShots(int id)
{
var talentVendorShots = await _context.TalentVendorShots.FindAsync(id);
if (talentVendorShots == null)
{
return NotFound();
}
_context.TalentVendorShots.Remove(talentVendorShots);
await _context.SaveChangesAsync();
return talentVendorShots;
}
private bool TalentVendorShotsExists(int id)
{
return _context.TalentVendorShots.Any(e => e.Id == id);
}
}
}
all of this works fine. i get information from the database fine. now i want to make a post to the table via uri. no body.for example
/api/TalentVendorShots/id=1,email=testemail should create a new record with id of 1 and email of testemail. how can i accomplish this?
The basic rule is, You should use POST if the action is not idempotent. Though you can pass the query parameters and no body to POST. But It would not make sense in this scenario. Basically query parameters are used to get/filter information.
Similar way many Web API testing tools like ARC, Swagger, and PostMan (chrome extension does not allow, but standalone application allows) does not allow to send body with the GET request. Though you can send the body in GET requests.

How to send individual variables from collected API data to another location

I'm trying to collect data from a client through an API. Eventually sending individual parts of the data that I collected to another project.
So for example I'm collecting an entire data object with id,Name,Status, etc. And I only want the id variable with it's value to be send to another project.
Everything works fine except from the sending part. I still had to paste all related classes to make it easier to understand.
I'm trying to send a list of objects. The problem is that I don't know how to send it the right way. You can see what I tried below. I'm creating my own object named WatchdogDTO which contains only the values that I want to send. Eventually I serialize it to send it to http://localhost:53661/api/Values. Which is another project I use to test if it works. Now it just literally sends the name of the list instead of the actual WatchdogDTO.
This is the data I'm collecting:
[
{
"id": "200",
"name": "Kerno (Camera)",
"hostName": "Amsterdam",
"status": false,
"hasCamera": true,
"cameraStatus": "0",
"lastSeen": "34324"
},
{
"id": "202",
"name": "Bassy (Location)",
"hostName": "Limburg",
"status": true,
"hasCamera": false,
"cameraStatus": "-1",
"lastSeen": "2344"
}
]
I created a corresponding model:
public class ServerStateDto
{
public string id { get; set; }
public string Name { get; set; }
public string HostName { get; set; }
public bool Status { get; set; }
public bool hasCamera { get; set; }
public string CameraStatus { get; set; }
public DateTime LastSeen { get; set; }
}
In the class ApiManager I collect the data above and deserialize it:
class ApiManager
{
HttpClient client = new HttpClient();
public List<ServerStateDto> CollectWatchdogData()
{
client.BaseAddress = new Uri("https://classified.Data.net:4802");
HttpResponseMessage response = client.GetAsync("/api/pdf/process/getalldata").Result;
if (response.IsSuccessStatusCode)
{
string dto = response.Content.ReadAsStringAsync().Result;
List<ServerStateDto> model = Newtonsoft.Json.JsonConvert.DeserializeObject<List<ServerStateDto>>(dto);
return model;
}
else
{
Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase);
return null;
}
}
}
This is just a general class that calls the functions CollectWatchdogData(); and PostWatchdogData();
{
public bool Start(HostControl hostControl)
{
ApiManager x = new ApiManager();
List<ServerStateDto> returnedData = x.CollectWatchdogData();
if (returnedData == null)
{
return false;
}
WatchdogApiClient cli = new WatchdogApiClient();
cli.PostWatchdogData(returnedData);
return true;
}
}
This is a model for the object that I'm sending. I only want to send Id from the model above:
public class WatchdogDTO
{
public string id { get; set; }
}
This class actually sends the WatchdogDTO from above to localhost:53661 which is another visual studio project of my which I use to test if the sending works.
public class WatchdogApiClient
{
private static readonly HttpClient client = new HttpClient();
//public async void PostWatchdogData(ServerStateDto toSend)
public async void PostWatchdogData(List<ServerStateDto> toSend)
{
//to actually send the data
WatchdogDTO toActuallySend = new WatchdogDTO()
{
id = toSend.ToString()
};
//Serialize data to bytestream so it can be sent
string serializedWatchDogData = JsonConvert.SerializeObject(toActuallySend);
if (string.IsNullOrEmpty(serializedWatchDogData))
{
return;
try
{
var response = await client.PostAsync("http://localhost:53661/api/Values", new StringContent(serializedWatchDogData, Encoding.UTF8, "application/json"));
}
catch (Exception ex)
{
Console.WriteLine($"Encountered an exception during PostAsync in method PostWatchDogData: {ex.Message}");
throw ex;
}
}
}
Eventually the destination of the data has a class and a model aswell to receive the data sent
model:
public class WatchdogDTO
{
public string id { get; set; }
}
This is the sending part, the sending works but the problem is that the value of WatchdogDTO data is the name of the list instead of the actual list with its values.
Class to receive the data send:
public class ValuesController : ApiController
{
[HttpPost]
public void PostWatchdogData([FromBody] WatchdogDTO data)
{
var hubContext = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
hubContext.Clients.All.BroadcastMessage("Server", "b");
}
}
How can I send individual parts like for example only the id, or the host name, or the id AND the hostname.
Thanks in advance and sorry for the bunch of code.

The Input was not valid

While calling an apiController method from Postman I encountered a problem.
the method with params mentioned in Postman client call below method
[AllowAnonymous]
[HttpPost]
public IActionResult Register([FromBody]UserDto userDto)
{
// map dto to entity
//var user = _mapper.Map<User>(userDto);
return Ok(new
{
userDto
});
//try
//{
// // save
// _userService.Create(user, userDto.Password);
// return Ok();
//}
//catch (AppException ex)
//{
// // return error message if there was an exception
// return BadRequest(new { message = ex.Message });
//}
}
which maps the UserDto..
public class UserDto
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Username { get; set; }
public string Password { get; set; }
}
but instead I get the error below :
Use raw option and select json from dropdown
and add your dto value in the body.
Raw
{
"FirstName" : "yourname",
"LastName": "lastname"
}

Categories

Resources