Posting JSON Data to ASP.NET MVC
Take a look at Phil Haack's post on model binding JSON data. The problem is that the default model binder doesn't serialize JSON properly. You need some sort of ValueProvider OR you could write a custom model binder:
using System.IO;
using System.Web.Script.Serialization;
public class JsonModelBinder : DefaultModelBinder {
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) {
if(!IsJSONRequest(controllerContext)) {
return base.BindModel(controllerContext, bindingContext);
}
// Get the JSON data that's been posted
var request = controllerContext.HttpContext.Request;
//in some setups there is something that already reads the input stream if content type = 'application/json', so seek to the begining
request.InputStream.Seek(0, SeekOrigin.Begin);
var jsonStringData = new StreamReader(request.InputStream).ReadToEnd();
// Use the built-in serializer to do the work for us
return new JavaScriptSerializer()
.Deserialize(jsonStringData, bindingContext.ModelMetadata.ModelType);
// -- REQUIRES .NET4
// If you want to use the .NET4 version of this, change the target framework and uncomment the line below
// and comment out the above return statement
//return new JavaScriptSerializer().Deserialize(jsonStringData, bindingContext.ModelMetadata.ModelType);
}
private static bool IsJSONRequest(ControllerContext controllerContext) {
var contentType = controllerContext.HttpContext.Request.ContentType;
return contentType.Contains("application/json");
}
}
public static class JavaScriptSerializerExt {
public static object Deserialize(this JavaScriptSerializer serializer, string input, Type objType) {
var deserializerMethod = serializer.GetType().GetMethod("Deserialize", BindingFlags.NonPublic | BindingFlags.Static);
// internal static method to do the work for us
//Deserialize(this, input, null, this.RecursionLimit);
return deserializerMethod.Invoke(serializer,
new object[] { serializer, input, objType, serializer.RecursionLimit });
}
}
And tell MVC to use it in your Global.asax file:
ModelBinders.Binders.DefaultBinder = new JsonModelBinder();
Also, this code makes use of the content type = 'application/json' so make sure you set that in jquery like so:
$.ajax({
dataType: "json",
contentType: "application/json",
type: 'POST',
url: '/Controller/Action',
data: { 'items': JSON.stringify(lineItems), 'id': documentId }
});
Posting JSON to controller MVC 5
You cannot possibly expect to map this complex JSON structure to a list of strings (List<String>
) that your controller action currently takes as parameter:
[{"Raw Material Name":"Asphalt","Short Code":"AS02","Price":"20"}]
So you may start by defining the appropriate view models that will reflect this structure (or almost, see the massaging technique required below):
public class MaterialViewModel
{
public string Name { get; set; }
public string ShortCode { get; set; }
public decimal Price { get; set; }
}
which your controller action will take as parameter:
public ActionResult insertRawMaterial(IList<MaterialViewModel> data)
{
...
}
and finally massage your data on the client to match the correct property names (name, shortCode and price of course):
// we need to massage the raw data as it is crap with property names
// containing spaces and galaxies and stuff
var massagedRawMaterials = [];
for (var i = 0; i < rawMaterials.length; i++) {
var material = rawMaterials[i];
massagedRawMaterials.push({
name: material['Raw Material Name'],
shortCode: material['Short Code'],
price: material['Price']
});
}
$.ajax({
url: "/Supplies/insertRawMaterial",
type: "POST",
data: JSON.stringify(massagedRawMaterials),
contentType: "application/json; charset=utf-8",
...
This being said, if the client side library you are currently using produces such undeterministic property names, you might consider replacing it with something more appropriate.
How do you post a JSON file to an ASP.NET MVC Action?
You need to set the HTTP Header, accept, to 'application/json' so that MVC know that you as passing JSON and does the work to interpret it.
accept: application/json
see more info here: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
UPDATE: Working sample code using MVC3 and jQuery
Controller Code
namespace MvcApplication1.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
[HttpPost]
public JsonResult PostUser(UserModel data)
{
// test here!
Debug.Assert(data != null);
return Json(data);
}
}
public class UserModel
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
}
View Code
@{ ViewBag.Title = "Index"; }
<script src="../../Scripts/jquery-1.9.1.min.js"></script>
<script type="text/javascript">
var sample = {};
sample.postData = function () {
$.ajax({
type: "POST", url: "@Url.Action("PostUser")",
success: function (data) { alert('data: ' + data); },
data: JSON.stringify({ "firstName": "Some Name", "lastName": "Some Last Name", "age": "30" }),
accept: 'application/json'
});
};
$(document).ready(function () {
sample.postData();
});
</script>
<h2>Index</h2>
** Update **
I added JSON.stringify
to the JS object before I pass it to the data
element in the AJAX Request. This just makes the payload more readable, however the Controller will interpret both formats of the data
similarly.
How to post JSON data from ASP.Net MVC controller?
After sending JSON with PostMan
I was able to create classes for the JSON request as well as the response. All I had to do next, is add a class which I called Service
. In this class, which has an integer and the url of the JSON server as attributes, I add all my functions to call the API. The integer represents the ID of the request and the url will be used in every function.
Now Here is what really matters.
The following code is for making a Login using credentials from the remote device and sending user input in JSON data:
public Response Login(String usr, String pwd)
{
this.MyId++;
Request model = new Request(id, usr, pwd);
var http = (HttpWebRequest)WebRequest.Create(uri);
http.Accept = "application/json";
http.ContentType = "application/json";
http.Method = "POST";
String json = Newtonsoft.Json.JsonConvert.SerializeObject(model);
UTF8Encoding encoding = new UTF8Encoding();
Byte[] bytes = encoding.GetBytes(json);
Stream newStream = http.GetRequestStream();
newStream.Write(bytes, 0, bytes.Length);
newStream.Close();
var response = http.GetResponse();
var stream = response.GetResponseStream();
var sr = new StreamReader(stream);
var content = sr.ReadToEnd();
Response res= Newtonsoft.Json.JsonConvert.DeserializeObject<Response>(content.ToString());
return res;
}
As you notice here, we create an instance of a c#
class called Request. This class is then serialized into JSON string. The JSON string is then put into the stream and sent with UTF-8 Encoding
. Then we get the response and deserialize it into a c#
class which with it we can know if the user was authenticated or not. Based on the result, we can redirect the client to his home page or prompt him to input a correct login and password.
PS This procedure is totally CORS
free. And this way I send and receive data in my server and assess it then send HTML
views accordingly. This keeps my requests and the remote device totally hidden.
Posting json string to c# mvc method
A better approach would be to take advantage of the model binding instead of trying to post and parse the JSON yourself.
Create a model of the items to be sent
public class ItemModel {
//...include the desired properties
public string Description { get; set; }
public string Name { get; set; }
public decimal TotalPrice { get; set; }
//...
}
next update the action to expect the items
[HttpPost]
public IActionResult PersistSelections([FromBody] ItemModel[] items) {
//access posted items
}
and lastly update the client to post the json data
$.ajax({
url: "/Home/PersistSelections",
type: 'post',
contentType: "application/json; charset=utf-8",
dataType: 'json',
data: JSON.stringify(selectedItems)
})
The framework's built in model binder should parse and bind the posted JSON and populate the objects in the controller
How to: (a) send JSON data from the browser to the controller; and (b) send the transformed data to SQL Server within ASP.NET MVC?
Although there are plenty of questions related to this, the answers to those typically refer to binding to a model instead of just the json string. But those will also help you.
It looks like there are two things:
- I would change the controller to receive a
string
instead of an object. - You'll need to update the json data you're passing to the controller to match the parameter name of the controller. So in this case, the controller would receive a parameter named
jsonFile
. So in the$.ajax
method you'll want update thedata
to something like:
data: { jsonFile: JSON.stringify(myJson) }
UPDATE:
- remove the Content-Type of
application/json
MVC Controller handle POSTed JSON as a string
ASP.Net Core:
You can declare your controller action argument as object
and then call ToString()
on it, like this:
[HttpPost]
public IActionResult Foo([FromBody] object arg)
{
var str = arg?.ToString();
...
}
In this example str
variable will contain JSON string from a request body.
ASP.Net MVC:
Since the previous option does not work in old ASP.Net MVC, as an option you can read data directly from Request
property in your controller's action. The following extension method will help you with it:
public static string GetBody(this HttpRequestBase request)
{
var requestStream = request?.InputStream;
requestStream.Seek(0, System.IO.SeekOrigin.Begin);
using (var reader = new StreamReader(requestStream))
{
return reader.ReadToEnd();
}
}
And your action will look like that:
[HttpPost]
[Route("test")]
public ActionResult Foo()
{
string json = Request.GetBody();
...
}
Passing JSON to ASP.Net MVC Action
Please check follwing code with error line identified.
var data = [];
var questID = 100;
data.push({ QuestionTypeId: '2', QuestionId: questID, Answer: 'asdff' });
data.push({ QuestionTypeId: '2', QuestionId: questID, Answer: 'asdff' });
data.push({ QuestionTypeId: '2', QuestionId: questID, Answer: 'asdff' });
data.push({ QuestionTypeId: '2', QuestionId: questID, Answer: 'asdff' });
//var items = JSON.stringify(data);
//alert(items);
var items = JSON.stringify(data); // HERE IS THE ERROR
alert(items);
$.ajax({
url: '/Dashboard/CreateAssessment',
data: items,
type: 'POST',
contentType: "application/json; charset=utf-8",
dataType: 'json',
traditional: true,
success: function (response) {
if (response.success) {
swal('Password Changed', response.Message, 'success');
window.location.href = "/Account/Management";
} else {
$("update-password").removeAttr("disabled");
swal('Error', response.Message, 'error');
}
},
error: function (response) {
$("update-password").removeAttr("disabled");
}
});
Please recheck your AssessmentAnswerModel with case sensitive consideration
Please mark as answer if found helpful.
Posting JSON data via jQuery to ASP .NET MVC 4 controller action
The problem is your dataType
and the format of your data
parameter. I just tested this in a sandbox and the following works:
C#
[HttpPost]
public string ConvertLogInfoToXml(string jsonOfLog)
{
return Convert.ToString(jsonOfLog);
}
javascript
<input type="button" onclick="test()"/>
<script type="text/javascript">
function test() {
data = { prop: 1, myArray: [1, "two", 3] };
//'data' is much more complicated in my real application
var jsonOfLog = JSON.stringify(data);
$.ajax({
type: 'POST',
dataType: 'text',
url: "Home/ConvertLogInfoToXml",
data: "jsonOfLog=" + jsonOfLog,
success: function (returnPayload) {
console && console.log("request succeeded");
},
error: function (xhr, ajaxOptions, thrownError) {
console && console.log("request failed");
},
processData: false,
async: false
});
}
</script>
Pay special attention to data
, when sending text, you need to send a variable that matches the name of your parameter. It's not pretty, but it will get you your coveted unformatted string.
When running this, jsonOfLog looks like this in the server function:
jsonOfLog "{\"prop\":1,\"myArray\":[1,\"two\",3]}" string
The HTTP POST header:
Key Value
Request POST /Home/ConvertLogInfoToXml HTTP/1.1
Accept text/plain, */*; q=0.01
Content-Type application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With XMLHttpRequest
Referer http://localhost:50189/
Accept-Language en-US
Accept-Encoding gzip, deflate
User-Agent Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)
Host localhost:50189
Content-Length 42
DNT 1
Connection Keep-Alive
Cache-Control no-cache
Cookie EnableSSOUser=admin
The HTTP POST body:
jsonOfLog={"prop":1,"myArray":[1,"two",3]}
The response header:
Key Value
Cache-Control private
Content-Type text/html; charset=utf-8
Date Fri, 28 Jun 2013 18:49:24 GMT
Response HTTP/1.1 200 OK
Server Microsoft-IIS/8.0
X-AspNet-Version 4.0.30319
X-AspNetMvc-Version 4.0
X-Powered-By ASP.NET
X-SourceFiles =?UTF-8?B?XFxwc2ZcaG9tZVxkb2N1bWVudHNcdmlzdWFsIHN0dWRpbyAyMDEyXFByb2plY3RzXE12YzRQbGF5Z3JvdW5kXE12YzRQbGF5Z3JvdW5kXEhvbWVcQ29udmVydExvZ0luZm9Ub1htbA==?=
The response body:
{"prop":1,"myArray":[1,"two",3]}
Related Topics
What Is the Impact of Thread.Sleep(1) in C#
Cancelling a Pending Task Synchronously on the UI Thread
How to Modify or Delete Items from an Enumerable Collection While Iterating Through It in C#
The Maximum Number of Characters a Textbox Can Display
Throw Httpresponseexception or Return Request.Createerrorresponse
Are There Any Reasons to Use Private Properties in C#
Password Masking Console Application
Very Slow Compile Times on Visual Studio 2005
Windows.Ui.Notifications Is Missing
How to Handle JSON That Returns Both a String and a String Array
Using the "Params" Keyword for Generic Parameters in C#
How to Backup and Restore the System Clipboard in C#
How to Treat the Circle as a Control After Drawing It? - Moving and Selecting Shapes