MVC5 WebApi 2 create not getting value from body ([FromBody]) - c#

I created a simple create Web API 2 action that will get an object from the post body and then will set it to the DAL layer. However no matter what I do using postman to get the object into the method, it always stays null.
The model looks like this:
namespace WebApi.Models
{
using System;
using System.Collections.Generic;
public partial class Classes
{
public int Id { get; set; }
public string ClassName { get; set; }
public int MaxStudents { get; set; }
}
}
My controller is as follows:
[HttpPost]
public IHttpActionResult CreateClass([FromBody] Classes classObj)
{
if (classObj == null)
{
return BadRequest("missing parameters.");
}
var newClass = new Classes()
{
ClassName = classObj.ClassName,
MaxStudents = classObj.MaxStudents
};
_context.Classes.Add(newClass);
_context.SaveChanges();
var newClassUrl = Url.Content("~/") + "/api/classes/";
return Created(newClassUrl, newClass);
}
Now when I use postman I tried two options.
option 1:
URL: http://localhost:53308/api/classes/
Headers: Content-Type: applications/json
[
"classObj": {
ClassName = "test"
MaxStudents = 100
}
]
option 2:
URL: http://localhost:53308/api/classes/
Headers: Content-Type: applications/json
ClassName = "test"
MaxStudents = 100
but in both cases classObj stays empty and it returns "missing parameters.". So obviously I'am missing something here.
What am I doing wrong?

Your payloads do not match the expectation of the action.
For example
[HttpPost]
public IHttpActionResult CreateClass([FromBody] Classes classObj) {
//...
}
Would expect JSON data that looks like this
{
"ClassName": "test"
"MaxStudents": 100
}
Also given that the model posted into the action is the same type added to the store there isn't really a need to create a new instance.
[HttpPost]
public IHttpActionResult CreateClass([FromBody] Classes classObj) {
if (classObj == null) {
return BadRequest("missing parameters.");
}
_context.Classes.Add(classObj);
_context.SaveChanges();
var newClassUrl = Url.Content("~/") + "/api/classes/" + classObj.Id.ToSTring();
return Created(newClassUrl, classObj);
}

Related

Using model to save a list, works first time but second time it saves 62 count item list as 1 list item [duplicate]

I want to know, there is any technique so we can pass Model as a parameter in RedirectToAction
For Example:
public class Student{
public int Id{get;set;}
public string Name{get;set;}
}
Controller
public class StudentController : Controller
{
public ActionResult FillStudent()
{
return View();
}
[HttpPost]
public ActionResult FillStudent(Student student1)
{
return RedirectToAction("GetStudent","Student",new{student=student1});
}
public ActionResult GetStudent(Student student)
{
return View();
}
}
My Question - Can I pass student model in RedirectToAction?
Using TempData
Represents a set of data that persists only from one request to the
next
[HttpPost]
public ActionResult FillStudent(Student student1)
{
TempData["student"]= new Student();
return RedirectToAction("GetStudent","Student");
}
[HttpGet]
public ActionResult GetStudent(Student passedStd)
{
Student std=(Student)TempData["student"];
return View();
}
Alternative way
Pass the data using Query string
return RedirectToAction("GetStudent","Student", new {Name="John", Class="clsz"});
This will generate a GET Request like Student/GetStudent?Name=John & Class=clsz
Ensure the method you want to redirect to is decorated with [HttpGet] as
the above RedirectToAction will issue GET Request with http status
code 302 Found (common way of performing url redirect)
Just call the action no need for redirect to action or the new keyword for model.
[HttpPost]
public ActionResult FillStudent(Student student1)
{
return GetStudent(student1); //this will also work
}
public ActionResult GetStudent(Student student)
{
return View(student);
}
Yes you can pass the model that you have shown using
return RedirectToAction("GetStudent", "Student", student1 );
assuming student1 is an instance of Student
which will generate the following url (assuming your using the default routes and the value of student1 are ID=4 and Name="Amit")
.../Student/GetStudent/4?Name=Amit
Internally the RedirectToAction() method builds a RouteValueDictionary by using the .ToString() value of each property in the model. However, binding will only work if all the properties in the model are simple properties and it fails if any properties are complex objects or collections because the method does not use recursion. If for example, Student contained a property List<string> Subjects, then that property would result in a query string value of
....&Subjects=System.Collections.Generic.List'1[System.String]
and binding would fail and that property would be null
[HttpPost]
public async Task<ActionResult> Capture(string imageData)
{
if (imageData.Length > 0)
{
var imageBytes = Convert.FromBase64String(imageData);
using (var stream = new MemoryStream(imageBytes))
{
var result = (JsonResult)await IdentifyFace(stream);
var serializer = new JavaScriptSerializer();
var faceRecon = serializer.Deserialize<FaceIdentity>(serializer.Serialize(result.Data));
if (faceRecon.Success) return RedirectToAction("Index", "Auth", new { param = serializer.Serialize(result.Data) });
}
}
return Json(new { success = false, responseText = "Der opstod en fejl - Intet billede, manglede data." }, JsonRequestBehavior.AllowGet);
}
// GET: Auth
[HttpGet]
public ActionResult Index(string param)
{
var serializer = new JavaScriptSerializer();
var faceRecon = serializer.Deserialize<FaceIdentity>(param);
return View(faceRecon);
}
[NonAction]
private ActionResult CRUD(someModel entity)
{
try
{
//you business logic here
return View(entity);
}
catch (Exception exp)
{
ModelState.AddModelError("", exp.InnerException.Message);
Response.StatusCode = 350;
return someerrohandilingactionresult(entity, actionType);
}
//Retrun appropriate message or redirect to proper action
return RedirectToAction("Index");
}
i did find something like this, helps get rid of hardcoded tempdata tags
public class AccountController : Controller
{
[HttpGet]
public ActionResult Index(IndexPresentationModel model)
{
return View(model);
}
[HttpPost]
public ActionResult Save(SaveUpdateModel model)
{
// save the information
var presentationModel = new IndexPresentationModel();
presentationModel.Message = model.Message;
return this.RedirectToAction(c => c.Index(presentationModel));
}
}

Angular 11 and .Net post method not working

I am trying to post data from Angular side to .Net and I'm not hits the breakpoint at Controller c#.
Do I need some configuration? I have already sent data in this way in Angular 8 before and it was working.
c#
public class UpdateViewModel
{
public int Id { get; set; }
public string Title { get; set; }
}
[HttpPost]
[Route("delete")]
public void delete(UpdateViewModel model)
{
//return Ok();
}
ts
var model = {
Id: 1,
Title: 'test'
}
return this.http.post(this.baseURL + "home/delete/", model)
.pipe(
retry(1),
catchError(this.errorHandler)
);
the http client of angular is based on observables. This means, the request will only be sent if you subscribe to the observable. You can do this with .subscribe()or with .toPromise().
For your code:
return this.http.post(this.baseURL + "home/delete/", model)
.pipe(
retry(1),
)
.subscribe({
error: this.errorHandler
});

MVC4 web api model not binding when called from angularjs

I have a action method with this signature:
public List<Member> Get([FromUri]MemberSearchModel searchModel)
The model looks like this:
public class MemberSearchModel
{
public string SearchBy { get; set; }
public string SearchValue { get; set; }
}
and im calling the api like this:
dataFactory.getMembers = function () {
var memberSearchModel = {
SearchBy: 'Name',
SearchValue: 'jaredites'
};
return $http.get(urlBase, memberSearchModel);
};
the method is hit but the model comes through with null values
Ive tried not using [FromUri] but then the model itself is null
Ive tried [FromBody] and the model comes through as null as well.
Is there something Im missing here?
It works when I call it specifying the params in the url
Please try this that :
dataFactory.getMembers = function () {
var memberSearchModel = {
SearchBy: 'Name',
SearchValue: 'jaredites'
};
return $http.get(urlBase, {params: memberSearchModel});
};

Web API Complex and primitive parameters in one action

I have an ASP.NET Web API action:
[HttpPost]
public void test(myCustomObj Entity)
{
}
And the JSON data is:
{
"ID": "1",
"Name": "ilhan",
"surname": "aksu"
}
So far my code works well. However, when I add a new primitive parameter:
[HttpPost]
public void test(myCustomObj Entity, [FromBody] string strdata)
{
}
and when I post the following JSON:
{
"Entity": {
"ID": "1",
"Name": "ilhan",
"surname": "aksu"
},
"strdata": "testdata"
}
the server returns 500 Internal Server Error.
How can I format my JSON data or change my action method to fix this problem?
If you're posting json, you could accept a string parameter:
[HttpPost]
public void Test(string jsonString)
{
}
And maybe a serializer helper to avoid polluting the code:
public static class JsonSerializer
{
public static string Serialize<T>(T t) where T : class
{
return JsonConvert.SerializeObject(t);
}
public static T Deserialize<T>(string s) where T : class
{
return (T)JsonConvert.DeserializeObject(s, typeof(T));
}
}
Then in your method you can materialize the json payload:
[HttpPost]
public void Test(string jsonString)
{
var o = JsonSerializer.DeserializeObject(jsonString, typeof(MyObject));
// ...
}
And if you're returning json, it could be as follows:
[HttpGet]
public JsonResult GetTest()
{
var i = YourService.GetSomethingById(1);
iSerialized = JsonSerializer.Serialize(i);
return new JsonResult
{
ContentEncoding = System.Text.Encoding.UTF8,
ContentType = "application/json",
JsonRequestBehavior = JsonRequestBehavior.AllowGet,
Data = iSerialized
};
}
As always write a view model
public class MyViewModel : myCustomObj
{
public string Strdata { get; set; }
}
Now have your controller action take this view model as argument:
[HttpPost]
public void test(MyViewModel model)
{
...
}
and now you could hit your action with the following JSON payload:
{"ID":"1","Name":"ilhan","surname":"aksu","strdata":"testdata"}
and everything's gonna get properly bound.
Alternatively your view model might look like this:
public class MyViewModel
{
public myCustomObj Entity { get; set; }
public string Strdata { get; set; }
}
and now you could hit your action with this payload:
{"Entity":{"ID":"1","Name":"ilhan","surname":"aksu"},"strdata":"testdata"}
So it's basically up to you to decide how your view model will look like depending on the JSON payload that you would like to use to call your controller action. So, never think of having more than 1 action argument in a controller action. Always think in terms of how your view model will look like.
Yes, controller actions always take view models as arguments and always return view models. That's the correct design. In ASP.NET MVC and in ASP.NET Web API.

connecting controller with model to display results in view page

So i have this aps.net mvc project in which i created a service layer, model views, controller, and a view page. But i am having trouble displaying my results to the view page. I am starting this would by passing in a specific linq statement in the service layer so i should be able to return it to show up on the view. Here is what i have:
Service:
public IEnumerable<RoleUser> GetUsers(int sectionID)
{
var _role = DataConnection.GetRole<RoleUser>(9, r => new RoleUser
{
Name = RoleColumnMap.Name(r),
Email = RoleColumnMap.Email(r)
}, resultsPerPage: 20, pageNumber: 1);
return _role;
}
Models:
public partial class Role
{
public RoleView()
{
this.Users = new HashSet<RoleUser>();
}
public ICollection<RoleUser> Users { get; set; }
}
public class RoleUser
{
public string Name { get; set; }
public string Email { get; set; }
}
Controller:
public ActionResult RoleUser(RoleView rvw)
{
var rosterUser = new RosterService().GetUsers();
ViewBag.RosterUsers = rosterUser;
return View();
}
View:
<div>
<span>#Model.Name</span>
</div>
I am not sure what i am missing or doing wrong but any tips will be great. I basically want to return the results from the linq statement i am testing to see that the connection is correct and functionality is there before enhancing. Thanks...
Well, if I were to go off the code you've provided I would say that I'm unsure how this compiles:
public partial class Role
{
public RoleView()
{
this.Users = new HashSet<RoleUser>();
}
public ICollection<RoleUser> Users { get; set; }
}
it feels like that should be:
public partial class RoleView
and then I would say that at the top of your view you're missing this:
#model NamespaceToClass.RoleView
and then I would say you're not going to be able to issue this:
#Model.Name
because RoleUser isn't your model. You're going to need to loop through the users:
#foreach (RoleUser ru in Model.Users)
and then inside that loop you can build some HTML with this:
ru.Name
but I would also question your controller. Right now it's receiving a model to return that model. There is some code missing here but generally speaking, inside the method:
public ActionResult RoleUser(RoleView rvw)
you would actually go get the data, construct the model, and then return that:
var users = serviceLayer.GetUsers(...);
// now construct the RoleView model
var model = ...
return View(model);
Based off of our conversation you currently have something like this in your controller:
public ActionResult View(int id)
{
// get the menu from the cache, by Id
ViewBag.SideBarMenu = SideMenuManager.GetRootMenu(id);
return View();
}
public ActionResult RoleUser(RoleView rvw)
{
var rosterUser = new RosterService().GetUsers();
ViewBag.RosterUsers = rosterUser;
return View();
}
but that really needs to look like this:
public ActionResult View(int id)
{
// get the menu from the cache, by Id
ViewBag.SideBarMenu = SideMenuManager.GetRootMenu(id);
var rosterUser = new RosterService().GetUsers();
ViewBag.RosterUsers = rosterUser;
return View();
}
because you're launching this page from the sidebar which is hitting this action because you're passing the id in the URL. You don't even need the other action.

Categories

Resources