ASP.NET WebAPI Null value in post body? - asp.net-mvc

I have just started learning WebAPI today and I can't figure out why "account" is always null.
Request
Content-Type: application/json; charset=utf-8
Request-Body: {"account":{"email":"awd","password":"awad","isNewsletterSubscribed":false}}
WebAPI
public class AccountsController : ApiController
{
public void Post([FromBody] string account)
{
// account is null
}
}
Shouldn't account contain a json string in this case?

Shouldn't account contain a json string in this case?
That would depend on the specific Content-Type request header you set when you send the request. For example if you used application/x-www-form-urlencoded which is the default then your request body payload must have looked like this:
={"account":{"email":"awd","password":"awad","isNewsletterSubscribed":false}}
Notice the = character at the beginning. That's one of the biggest weirdest things I have ever encountered. Since you can bind only one parameter from the body if the request the Web API doesn't expect a parameter name, but just the value.
This being said, your request payload looks more like a JSON. So it would make far more sense to design a view model and use Content-Type: application/json when sending the request. Binding a JSON object to a string is not common practice.
So:
public class UserViewModel
{
public string Email { get; set; }
public string Password { get; set; }
public bool IsNewsletterSubscribed { get; set; }
}
public class AccountViewModel
{
public UserViewModel Account { get; set; }
}
and then your controller action will simply take the view model as parameter. In this case yo udon't need to decorate it with the [FromBody] attribute because by convention in Web API the default model binder will attempt to bind complex types from the body of the request:
public class AccountsController : ApiController
{
public HttpResponseMessage Post(AccountViewModel model)
{
// work with the model here and return some response
return Request.CreateResponse(HttpStatusCode.OK);
}
}
Also notice that since HTTP is a request/response protocol it makes much more sense to have your Web API controller actions return response messages as shown in my example rather than just having some void methods. This makes the code more readable. You immediately understand how the server will respond and with what status code to the specified request.

Related

QueryString is always empty ASP.net Core 3.1

The query string I use is always empty. I have no idea why, and have tried for hours with
The HttpContext.Request returns all other parts of the URL except the querystring.
With this url https://localhost:44394/Trackers/Create?Place=Vision_College
and this Model
[BindProperties(SupportsGet = true)]
public partial class Tracker
{
[FromQuery(Name = "Place")] //populates it from the query
public string Place { get; set; }
...}
and this controller
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Name, Phone, Place")] Tracker tracker)
{
OK I found an answer.
I was trying to use it in the POST of the CREATE, when I should have been using it in the GET part of CREATE
Thanks for everyones help!
Since you are using the query parameters in httpPost you should use, [FromQuery] inside your arguments. Follow this
Your DTO class would be,
public class Tracker
{
[FromQuery(Name = "Place")]
public string Place{ get; set; }
}
In your controller class
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([FromQuery]Tracker tracker)
{
}
Note: If your query parameters match with the model property names, specifically annotating the properties would not be necessary.
Better you can get by body itself since this is a post request. otherwise make this as a get request. If converting to get by body, simply use [FromBody] in endpoint arguments instead of [FromQquery]

MVC 3 JSON string not serializing into Controller action

Currently using MVC3 and using jQuery $.post function to send the ajax request to the controller action called "SearchInitiated". I'm having a little bit of a head-scratcher here because I'm not sure exactly where my issues lies. I'm sure its something minor that I have overlooked.
When I call my Controller method from an AJAX call, I am passing a json object (stringified) to a controller action. See below:
Request Headers from Chrome
Accept:/ Content-Type:application/x-www-form-urlencoded;
charset=UTF-8 User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64)
AppleWebKit/537.17 (KHTML, like Gecko)
Chrome/24.0.1312.52 Safari/537.17
X-Requested-With:XMLHttpRequest
Form Dataview
connectorId:1
sessionId:97e2d8b2-be9e-4138-91ed-42ef9c6a2cd6
party:
{"Tag":null,"PartyIdentifier":"1","Address":null,"Address2":null,"BusinessName":"","CellPhoneNumber":null,"CIF":"","City":null,"Country":null,"DateOfBirth":null,"EMailAddress":null,"EmploymentTitle":null,"EmployerAddress":null,"EmployerAddress2":null,"EmployerCity":null,"EmployerName":null,"EmployerPhoneNumber":null,"EmployerState":null,"EmployerZip":null,"Fax":null,"Firstname":"TEST","Lastname":"USER","MailingAddress":null,"MailingAddress2":null,"MailingCity":null,"MailingState":null,"MailingZip":null,"Middlename":null,"PhoneNumber":null,"State":null,"TIN":"1111111","WorkPhoneNumber":null,"Zip":null}
javascript
var parties = #(Html.Raw(Json.Encode(Model.SearchParties)));
function SearchForCustomer(id)
{
var currentSelectedParty = GetPartyById(id)
//SearchPost is a wrapper for $.ajax using default values for dataType and contentType
SearchPost(URL, {
'connectorId': '#Model.ConnectorId',
'sessionId': '#Model.SessionId',
'party' : JSON.stringify( currentSelectedParty )
}
}
Controller
public ActionResult SearchInitiated(int connectorId, string sessionId, SearchParty party)
{
code here....
}
public class SearchParty
{
public SearchParty();
public SearchParty(string lastname, string firstname);
public string Address
{
get;
set;
}
public string City
{
get;
set;
}
public string Country
{
get;
set;
}
public string DateOfBirth
{
get;
set;
}
.... etc etc
}
However, the party object is null.
If I change the code to the following, everything deserializes correctly into the strongly typed object.
public ActionResult SearchInitiated(int connectorId, string sessionId, string party)
{
JavaScriptSerializer json_serializer = new JavaScriptSerializer();
SearchParty sp =
json_serializer.Deserialize<SearchParty>(party);
}
I know my json string is valid since it is working in the second code snippet and the value is being passed in the call. What else could I be missing?
Try this.
public class SearchParty
{
public string party { get; set; }
}
[HttpPost]
public ActionResult SearchInitiated(SearchParty party)
{
....
return View();
}
probably you need to set the traditional prop of jQuery.ajax to true in order to achieve traditional style of param serialization
put the below line of code immediatly after the document ready like
$(function(){
jQuery.ajaxSettings.traditional = true;
});
This SO question may help you further
I would make sure you have the [Serializable] attribute on your model. Also, make sure your request specifies party={myjson} .
You just need to declare a class 'SearchParty' in the controller to retrieve the strongly typed object in the controller without serializing.
public class SearchParty
{
public string party { get; set; }
}
public ActionResult SearchInitiated(SearchParty party)
{
code here....
}
Please check this link too
I resolved my error by modifying the javascript ajax call to this:
SearchPost(URL, JSON.stringify( {
'connectorId': '#Model.ConnectorId',
'sessionId': '#Model.SessionId',
'party' : currentSelectedParty
}))
I needed to stringify the entire data object sent in the ajax call, not just the 'party' object

asp.net MVC 3 - reading POST payload in paramterized controller method

I had
[HttpPost]
public ActionResult Foo()
{
// read HTTP payload
var reqMemStream = new MemoryStream(HttpContext.Request.BinaryRead(HttpContext.Request.ContentLength));
....
}
The payload is application/json; worked fine; then I changed to
public ActionResult Foo(string thing)
{
....
}
The intention being to post to MyController/Foo?thing=yo
Now I cant read the payload(the length is correct but the stream is empty). My guess is that the controller plumbing has eaten the payload looking for form post data that can be mapped to the method parameters. Is there some way that I can stop this behavior (surely MVC should not have eaten a payload whose type is marked as JSON , it should only look at form post data). My work around is to add 'thing' to the json but I dont really like that
Try resetting the input stream position before reading:
public ActionResult Foo(string thing)
{
Request.InputStream.Position = 0;
var reqMemStream = new MemoryStream(HttpContext.Request.BinaryRead(HttpContext.Request.ContentLength));
....
}
Now this being said, if you are sending an application/json payload why on the holy Earth are you bothering to read directly the request stream instead of simply defining and using a view model:
public class MyViewModel
{
public string Thing { get; set; }
public string Foo { get; set; }
public string Bar { get; set; }
...
}
and then:
public ActionResult Foo(MyViewModel model)
{
// use the model here
....
}
ASP.NET MVC 3 has a built-in JsonValueProviderFactory which allows you to automatically bind JSON requests to models. And if you are using an older version it is trivially easy to add such factory your self as Phil Haack illustrates in his blog post.

Cannot bind JSON to ASP.NET Model in multi part post

I am using ASP.NET MVC3 controller to receive multi-part form post from WP7 app. The format of the post is something as follows:
{User Agent stuff}
Content-Type: multipart/form-data; boundary=8cdb3c15d07d36a
--8cdb3c15d07d36a
Content-Disposition: form-data; name="user"
Content-Type: application/json
{"UserName":"ashish","Password":"ashish"}
--8cdb3c15d07d36a--
And my controller looks like:
public class User
{
public string UserName { get; set;}
public string Password { get; set; }
}
[HttpPost]
public JsonResult CreateFeed(User user)
{
}
What I am seeing is that User is not bound to json and user object is always null. I tried making user string and manually bound it to User class using DataContractJsonSerializer and it does create and assign an object but I am baffled as to why it does not work.
I tried using non-multi-form post and found it works with the same json. Any help would be appreciated.
I saw these posts: ASP.NET MVC. How to create Action method that accepts and multipart/form-data and HTTP spec http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.2 while coming up with my code.
The answer you're looking for is here
You have to read it in as a string and parse that internally.
So your action would look like this:
[HttpPost]
public JsonResult CreateFeed(string jsonResponse)
{
JavaScriptSerializer jsonSerializer = new JavaScriptSerializer();
User user = jsonSerializer.Deserialize<User>(jsonResponse);
}
Or if you don't have nice helpful Content-Disposition with names to associate with the controller action methods you can do something like the below:
[HttpPost]
public JsonResult CreateFeed()
{
StreamReader reader = new StreamReader(Request.InputStream);
string jsonResponse = reader.ReadToEnd();
JavaScriptSerializer jsonSerializer = new JavaScriptSerializer();
User user = jsonSerializer.Deserialize<User>(jsonResponse);
}
This approach is further outlined here

Using Asp.net mvc 2 and WCF - Passing generic object to the Service call?

[DataContract]
public class UserCertification
{
…
}
[DataContract]
public class UserPhone
{
…
}
[DataContract]
public class UserAddress
{
…
}
[DataContract]
public abstract class Request
{
[DataMember]
public int UserMakingRequest { get; set; }
[DataMember]
public Guid RequestId { get; set; }
[DataMember]
public Object RequestObjectDTO { get; set; }
}
var request = new Request
{
RequestId = new Guid(),
UserMakingRequest = loggedInUserId,
RequestObjectDTO = userCertification,
};
I have DataContracts: UserCertification, UserAddress and UserPhone
I also have a DataContact Request. This is what I would like to pass to each WCF service method.
So notice in the Request DataContract is DataMember called RequestObjectDTO. I made this of type object, hoping I would then be able to attach my other DataContracts to it.
This did not work - it throws the error "Cannot create an abstract class."
What type should it be of? Can I do this?
That is the point of abstract class - you can't create its instance. You must create instace of derived non abstract class but in such case you must mark your Request class with KnownTypeAttribute describing child classes which can be transported by WCF messages. Moreover WCF doesn't like object type as DataMember - it will not work because WCF must know what type should be deserialized on a client.
Keep in mind that everything you send to a service must be serialized and deserialized, in most cases, as XML.
Exactly what XML would you have sent to the service, and what XML Schema would describe it? If you can't answer those questions, then neither can WCF.

Resources