I've got a service that I use to send requests to an MVC controller in C#.
This has been working fine until now that I have a complex object I'm trying to send. The param postDto in C# is always null. I've tried a few different solutions but haven't been able to solve this issue. If I remove the list from the object, the object comes across successfully. Any help would be appreciated.
service.ts
...
post$(postDto: MyTSPostDto): Observable<MyTSDto> {
return this.http.post<MyTSDto>(
location.origin + '/api/mycontroller',
postDto,
{ headers: new HttpHeaders({ 'Content-Type': 'application/json' }) }
).pipe(
map((response: MyTSDto) => response)
);
}
myTSPostDto.ts
export class MyTSPostDto {
firstPostDto: FirstPostDto;
secondPostDto: SecondPostDto;
thirdPostDtos: ThirdPostDto[] = [];
}
postDto.cs
public class PostDto
{
public FirstPostDto FirstPostDto { get; set; }
public SecondPostDto SecondPostDto { get; set; }
public List<ThirdPostDto> ThirdPostDtos { get; set; }
}
MyController.cs
...
[HttpPost]
[ProducesResponseType(typeof(MyDto), 200)]
public async Task<IActionResult> Migrate([FromBody] PostDto postDto)
{
...
So it turns out I had some model validation happening in C# that was causing the postDto parameter to come across as null. As soon as I fixed up my model to provide valid inner models, then everything started working.
Related
I'm working on a simple notes api, I'm trying to create a Put method to update a note in my notes list, but when I try to update any note through the SwaggerUI I get a the 404 status code. I think that I'm missing something in the structure.
This is my [HttpPut] request:
[HttpPut("{id}")]
public IActionResult Put([FromBody] Note requestParam)
{
if (!ModelState.IsValid)
{
return BadRequest("Not a valid model");
}
using (_datacontext)
{
var ExistingNote = _datacontext.Note.Where(n => n.Id == requestParam.Id)
.FirstOrDefault<Note>();
if (ExistingNote != null)
{
ExistingNote.Title = requestParam.Title;
ExistingNote.Description = requestParam.Description;
ExistingNote.Completed = requestParam.Completed;
_datacontext.SaveChanges();
} else
{
return NotFound();
}
}
return Ok();
}
My DataContext:
public class DataContext : DbContext
{
public DataContext(DbContextOptions<DataContext> option) : base(option)
{
}
public DbSet<Note> Note { get; set; }
}
And lastly my Note Model:
public class Note
{
[Key]
public int Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public bool Completed { get; set; }
}
After looking for different examples I haven't found a standard approach so I'm not sure what to do about it
I've researched about Http bodies since it seemed like it needed to be part of the request but still get the error code. What could be wrong with it? (Both post and get methods work!).
Also, the error code:
When using the [HttpPut("{id}")] attribute on your controller, you need to add a parameter to the controller method's signature:
IActionResult Put([FromRoute] int Id, [FromBody] Note requestParam)
You can then call the API like this when Id=123
PUT http://{base-url}/123
Then you need to query the data context using the id from the route (which means you can remove it from the body)
On the other hand, if you don't want the Id as part of the request URL and keep it in the body, you need to remove the Id from the route template:
[HttpPut] without {id}.
Needless to say, make sure the Id actually exists in the data context. Otherwise your code will return, yes, a 404.
I have an Angular app that invokes a c#mvc method:
AngularJS:
var data = JSON.stringify({ 'panelists': $scope.arr, 'webId': $scope.webinarId });
//Call the services
$http.post('/Home/CreatePanelists', JSON.stringify(data))
.then(function (response) {
if (response.data)
$scope.msg = 'Post Data Submitted Successfully!';
}, function (response) {
$scope.msg = 'Service not Exists';
});
Contents of data:
{"panelists":[{"name":"ali","email":"ali#email.com"},{"name":"tom","email":"tom#email.com"},{"name":"arthur","email":"arthur#email.com"}],"webId":94395753244}
Added the following Files:
/Models/Home/Panelist.cs
public class Panelist
{
public string name { get; set; }
public string email { get; set; }
}
/Models/Home/Parameters.cs
public class Parameters
{
public IList<Panelist> panelists { get; set; }
public string webId { get; set; }
}
Updated the Controller:
/Controllers/HomeController.cs:
public ActionResult CreatePanelists(Parameters data)
{
System.Diagnostics.Debug.WriteLine(data.webId);
System.Diagnostics.Debug.WriteLine(data.panelists);
return new EmptyResult();
}
By the time when the debugger enters the CreatePanelists method, I added a watch on data, and both, panelists, and webId are null.
I don't understand where the problem resides. When I debug the AngularJS code in Chrome, and get to the step in which the post request is made, I see that the variable data, does have the array of objects with values (as shown above).
Why is the MVC Controller method CreatePanelist is not seeing these values?
If somebody have an idea and would not mind offering it, that would be nice.
Thank you in advance for your help.
Your problem comes from calling JSON.stringify twice. You are already stringifying it when setting the variable data, don't do it a second time in your post.
This question already has answers here:
Angular2 HTTP Post ASP.NET MVC Web API
(7 answers)
Closed 6 years ago.
I have a WebAPI controller
public class MyController : ApiController
{
[HttpPost]
public SomeResult MyAction(string name, string message)
{
return SomeResult.???;
}
}
I have an angular controller calling this method
$http
.post("/api/My/MyAction", { name: "bob", message: "hello" })
.then(function(xhr) { ... }, function(xhr) { ... });
I get this result
Server Error in '/' Application.
The resource cannot be found.
What did I do wrong?
P.S. It's not the URL...It works when I use HttpGet and append the parameters to the query string.
For more than one attribute for post requests, you can use [FromBody] in your controller and make a ViewModel class. Example:
[HttpPost]
public HttpResponseMessage UpdateNumber([FromBody]UpdateNumberViewModel model)
{
//To do business
return Request.CreateResponse(HttpStatusCode.OK);
}
UpdateViewModel:
public class UpdateViewModel
{
public int Id{ get; set; }
public string Title{ get; set; }
}
Angular:
var model = {
Id: 1,
Title: 'Vai filhão'
}
$http.post('/api/controller/updateNumber/',model).then(function () { alert("OK"); }, function () {alert("something wrong"); });
You can see more details about how web api it works here: https://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api
I've faced that problem, if you google there are different ways to solve it. One of the easiest requires to use only one input object in you WebApi controller, so in you case just crate a class
public class InputData {
public string name { get; set; }
public string message { get; set; }
}
Then change your input to the new create object with [FromBody] prefix (maybe not mandatory, see #ADyson comment)
public SomeResult MyAction([FromBody]InputData inputData)
This question already has an answer here:
Simple post to Web Api
(1 answer)
Closed 7 years ago.
I am trying to pass data to my web API using JSON objects. Sending a single object does seems to work fine but as soon as I put a second parameter, the second object does not even seems to initialize on the server side?
Please view the code below to see how I am handling the data parameter
[HttpPost("")]
public JsonResult Post([FromBody]Log_Header headerData,
[FromBody]Log_Detail detailData)
{
return Json("Test");
}
Each of the classes above have simple string data, eg of class below:
public class Log_Header
{
public int Id { get; set; }
public string Name{ get; set; }
}
Example of data being sent:
var header = {
Id: 0,
Name: "Test 3",
}
var detail = {
Id: 0,
Desc: "Test 1",
}
$http({
method: 'POST',
url: "api/addLog",
data : {
header: header,
detail: detail
}
})
This is all just demo data.
I have tried sending the data up in few different ways e.g below:
var data = {
Id: 0,
Name: "Test 3",
LogID: 0,
Desc: "Test",
}
But nothing seems to get this working, I'm guessing I am setting up the web API incorrectly?
Overall, the problem is [FromBody]Release_Log_Detail detailData does not receive any data at all and when viewing the object from a breakpoint it appears as null.
if anyone has any ideas please leave a comment or answer below. If you need anymore information from me please ask.
Whatever we post from angular $http, it consider a single object, so we need to read it in a single object on server
we can do like this
[HttpPost("")]
public JsonResult Post([FromBody]PostData data)
{
return Json("Test");
}
class PostData
{
public Log_Header LogHeader { get; set; }
public Log_Detail LogDetail { get; set; }
}
angular post
$http({
method: 'POST',
url: "api/addLog",
data : {
LogHeader : header,
LogDetail : detail
}
})
In the javascript
$http({
method: 'POST',
url: "api/addLog",
data : JSON.stringify({
header: header,
detail: detail
})
})
create a model
public class dataViewModel
{
public string[] header{ get; set; }
public string[] detail{ get; set; }
}
You have create a controller of name api and action name addLog
[HttpPost]
public JsonResult addLog(dataViewModel data)
{
return Json("Test");
}
hope this helps
I have following controller:
[HttpPost]
public JsonResult SaveCompensationComponent(int agencyId, CompensationComponentAllData compensationComponent)
{
int? id = _dmsCompensation.SaveCompensationComponent(agencyId, compensationComponent);
return Json(id, JsonRequestBehavior.AllowGet);
}
Definition of the CompensationComponentAllData class:
public class CompensationComponentAllData
{
some properties
...
public CompensationObject CompensationElement { get; set; }
public CompensationObject CompensationBasis { get; set; }
...
some properties
...
}
CompensationObject class:
public class CompensationObject
{
some properties
...
public ActivityData ByActivity { get; set; }
...
some properties
...
}
ActivityData class:
public class ActivityData
{
some properties
...
public List<int> GoalCategories { get; set; }
public List<int> Policies { get; set; }
...
some properties
...
public ActivityData() { }
public ActivityData(CompensationObjectByActivity record) {
...
}
}
In javascript I create appropriate objects and send that through ajax (contentType: 'application/json' and JSON.stringify used before sending data). Everything is correctly sent to server because I executed following code in the controller:
HttpContext.Request.InputStream.Seek(0, SeekOrigin.Begin);
var jsonStringData = new StreamReader(HttpContext.Request.InputStream).ReadToEnd();
And jsonStringData had correct value:
"{\"agencyId\":\"332\",\"compensationComponent\":{\"Id\":431,\"CompensationComponentInfoId\":509,\"AgencyJobPositionId\":\"306\",\"Name\":\"ggggggg44\",\"Description\":\"fdssssssss\",\"CompensationComponentImpactLevelId\":\"1\",\"CompensationProductionTypeId\":\"1\",\"CompensationFrequency\":{\"Id\":\"1\"},\"CompensationDateTypeId\":\"3\",\"EffectiveDate\":\"06/10/2015\",\"BasisDifferentThanElement\":false,\"CompensationElement\":{\"ObjectTypeId\":\"3\",\"ByActivity\":{\"CompensationAttributeId\":\"21\",\"UnitsId\":\"3\",\"PoliciesLevel\":\"Individual Company/Policy\",\"Policies\":[\"572\",\"139\",\"138\"],\"VerificationLevelId\":\"1\"}},\"CompensationBasis\":{\"ObjectTypeId\":\"3\",\"ByActivity\":{\"CompensationAttributeId\":\"21\",\"UnitsId\":\"3\",\"PoliciesLevel\":\"Individual Company/Policy\",\"Policies\":[\"572\",\"139\",\"138\"],\"VerificationLevelId\":\"1\"}},\"CompensationStructureId\":\"2\",\"CompensationRateId\":\"1\",\"FixedValue\":\"10.00\",\"UseChargeback\":false}}"
Now problem is that after binding compensationComponent.CompensationElement.ByActivity.Policies has a null value even though it should be a list with 3 elements.
What makes me even more confused is that in the same time compensationComponent.CompensationBasis.ByActivity.Policies is bound correctly. Also compensationComponent.CompensationElement.ByActivity.GoalCategories is bound correctly too.
EDIT:
This is my ajax call:
$.ajax({
type: type,
url: url,
data: JSON.stringify(data),
success: callback,
error: function (xhr, ajaxOptions, thrownError) {
...
},
contentType: 'application/json',
cache: cache
});
If I remove JSON.stringify and try something as suggested in this post I get error in binding so 500 is just returned.
Please help.
I think that's a little bit strange that you want to receive part of the JSON as method parameters. I think you need to introduce a class for root object:
public class CompensationModel
{
public int AgencyId { get; set; }
public CompensationComponentAllData CompensationComponent { get; set; }
}
And your controller method will take this class as a parameter:
[HttpPost]
public JsonResult SaveCompensationComponent(CompensationModel model)
I suggest you to use services like json2csharp, let's computer does the boring work.
And few comments about JSON that you send. JSON.stringify doesn't change types:
JSON.stringify({a: [1, 2, 3]}) // -> "{"a":[1,2,3]}"
JSON.stringify({a: ["1", "2", "3"]}) // -> "{"a":["1","2","3"]}"
So if you get strings in your JSON that menas that javascript values are of type string. In C# models you expect to have int, so you might consider to convert data in javascript, though MVC is smart enough to convert these values.