Post JSON to MVC controller - c#

I've looked at various questions and answers, however I am only partially successful.
The View is passing this JSON:
{JsonInput: [["208-01", "003158"]], JobNumber: "test"}
$.ajax({
type: "POST",
url: "/Dash/SavePickups",
contentType: 'application/json',
dataType: "json",
data: JSON.stringify({
JsonInput: final,
JobNumber:"test"
}),
The Json String above is sent to the controller at /Dash/SavePickups
[System.Web.Http.Route("Dash/SavePickups/{JsonInput}")]
public JsonResult SavePickups(object[][] JsonInput)
{
var FailResult = new { Success = "False", Message = "Error" };
var SuccessResult = new { Success = "True", Message = "Pickups Scheduled Successfully." };
return Json(SuccessResult, JsonRequestBehavior.AllowGet);
}
Only part of the JSON string is passed to the JsonInput.
In Debug I see the JsonInput Object, with the Obj array 208-01 and 003158.
Why isn't JobNumber included, I can see in chrome Network POST its part of the JSON string sent to the controller..

Continuing maccettura's answer - Your issue is with deserializing the JSON into an object. Your given JSON is formatted as
{ JsonInput : ["1234","5667"], JobNo : "Test" }
Which has one possible data structure of
List<string> , String
which will not deserialize into a 'sqaure' object such as
object [][]
I'd recommend making a model for your json that looks like this:
public class SavePickupsModel
{
public List<string> JsonInput {get; set;}
public string JobNo {get; set; }
}
Then use that model as input into your method:
[HttpPost]
[System.Web.Http.Route("Dash/SavePickups/{JsonInput}")]
public JsonResult SavePickups(SavePickupsModel JsonInput)
{
var FailResult = new { Success = "False", Message = "Error" };
var SuccessResult = new { Success = "True", Message = "Pickups Scheduled Successfully." };
return Json(SuccessResult, JsonRequestBehavior.AllowGet);
}

I would start by tagging your controller with the [HttpPost] attribute
[HttpPost]
[System.Web.Http.Route("Dash/SavePickups/{JsonInput}")]
public JsonResult SavePickups(object[][] JsonInput)
{
}
I would also point out that your parameter for the action (object[][] JsonInput) does not look right to me. You will likely find that the json does not deserialize to that object type.

Related

ValidateAntiForgeryToken in asp.net mvc 5.0 - how to pass array of objects with JSON and ajax

It seems that ValidateAntiForgeryToken attribute prevents the data from being parsed properly when passed to MVC Controller, the code below works when I remove the ValidateAntiForgeryToken attribute but does not work with it, all the parameters in the controller action are passed except array of translations.
Please advise on how to pass array of objects while utilizing ValidateAntiForgeryToken attribute, is it even possible?
This is my code
C#
[HttpPost]
[ValidateAntiForgeryToken]
public void AddComment( string code, string type, string ecomment, IEnumerable<CommentTranslation> translations)
{
//do something later
}
CommentTranslation is
public class CommentTranslation
{
public string LangId { get; set; }
public string LangName { get; set; }
public string Translation { get; set; }
}
js
addComment: function (ecomment, type, translations) {
var data = {
code: '',
type: type,
ecomment: ecomment,
translations: translations
};
var url = 'CommentsAjax/AddComment';
return comments.repository.postDataWithToken(data, url);
},
postDataWithToken: function (data, url) {
return $.ajax({
type: 'POST',
traditional: true,
contentType: 'application/x-www-form-urlencoded; charset=utf-8',
data: comments.repository.addAntiForgeryToken(data),
url: getServerPath() + url
});
}
addAntiForgeryToken: function (data) {
var token = $('input[name="__RequestVerificationToken"]').val();
data.__RequestVerificationToken = token;
return data;
},
Ended up using FormCollection that you can just generically pass anything into the Controller.

Posting to asp.net core mvc app results in null body and null input parameter

This is my first asp.net core app, so I'm probably missing something obvious, but I've looked through the other StackOverflow answers, and the solutions there haven't helped me. I have an asp.net core mvc app that I'm running on service fabric, and I'm trying to post a string to a controller. The string is originally an array of json objects.
My ajax post:
var sendThis = { "operations": JSON.stringify(operations) };
$.ajax({
url: '/Home/Execute',
type: 'POST',
data: sendThis,
dataType: "json",
contentType: 'application/json; charset=utf-8',
error: function (xhr) {
$("#save-footer-text").val("Saving failed. Please contact an administrator");
},
success: function (result) {
$(".save-footer").addClass("slider");
},
async: true
});
My controller on the other side. I took the stream stuff from another stack overflow answer, but it just returns an empty string when it's done.
[HttpPost]
public IActionResult Execute([FromBody] string operations /*this is null*/)
{
var i = 5;
string documentContents; //this will be an empty string.
Request.Body.Position = 0;
using (Stream receiveStream = Request.Body)
{
using (StreamReader readStream = new StreamReader(receiveStream, Encoding.Unicode))
{
documentContents = readStream.ReadToEnd();
}
}
Console.WriteLine(i);
return new OkResult();
}
From the other stackoverflow answers, I've also tried posting with traditional set to to true, and I've tried posting operations into a model, like this
public class M
{
public string status { get; set; }
public string appName { get; set; }
public string startTime { get; set; }
public string endTime { get; set; }
public string description { get; set; }
public string operation { get; set; }
}
with the controller changed to public IActionResult Execute([FromBody] List<M> operations)
I've checked that my javascript does send a request, with Chrome tools reporting that the Request payload is:
operations= my json string here
I also see this in Fiddler, so I know it is going over the wire.
Per this answer, I've also tried updating JsonSettings, but that didn't help either.
I'm using 1.0.0-rc2-final for the asp.net core package, and 5.1.150 for service fabric.
What am I missing here? Sorry if the answer is really trivial. Thank you for any help.
If the operations variable in the script is an array
var operations = new Array();
var op1 = { status: 's1', appName: 'a1', startTime: 'st1', endTime: 'e1', description: 'd1', operation: 'o1' };
operations.push(op1);
var op2 = { status: 's2', appName: 'a2', startTime: 'st2', endTime: 'e2', description: 'd21', operation: 'o2' };
operations.push(op2);
var sendThis = JSON.stringify(operations);
...// ajax call here
And the controller post method is defined as follows then List<M> operations should contain the values sent over the wire as expected.
[HttpPost]
public IActionResult Execute([FromBody]List<M> operations)
{
// ... some code here
return Json("");
}
It is a list of M?
If it is, then your json shouldn't be like this
var sendThis = { "operations": JSON.stringify(operations) };
try this:
var sendThis = JSON.stringify(operations);
I think asp.net is trying to deserialize an object like this one:
public class Operation
{
public List<M> Operations { get; set; }
}

Asp.Net and Angular trying to send an Array of Objects to a Post API

I'm using the USDA food database to try to make an app that will tell you if you've gotten your daily recommendations of vitamins. I'm getting data just fine, but I'm wondering if it was possible to send that data from Angular to the C# api, so I can add the array of strings and int to a total count model.
How would I route this and what kind of data should I tell the API to expect?
The error I'm getting right now is:
Message: "No HTTP resource was found that matches the request URI 'http://localhost/api/apiFood[object Object]'."
MessageDetail: "No type was found that matches the controller named 'apiFood[object Object]'."
I've tried :
public IHttpActionResult Post([FromUri]ValueVM toEat)
{
return Ok();
}
just to see if it would route, but it didn't work out.
I'm sending the data with an ngclick="add(display)" which goes to this function in the controller:
$scope.add = function (display) {
FoodFactory.add(display).then(function (data) {
});
};
and this function in the factory:
o.add = function (display) {
var defer = $q.defer();
var config = { contentType: 'application/json' };
$http.post('api/apiFood' + display, config).success(function (data) {
defer.resolve(data);
});
return defer.promise;
};
In your model
public class toEat
{
public int id {get;set;}
public string name {get;set;}
}
In your ApiController
public class EatController : ApiController
{
[HttpPost]
public HttpResponseMessage Post(List<toEat> list)
{
return Ok();
}
}
Your request
function Request() {
$.ajax({
type: "POST",
url: url,
contentType: "application/json",
data: (your serialized array),
async: false,
success: function(data) {
console.log(data);
}
});
}

cannot pass paramerters as JSON to mvc controller

I am trying to pass an id and an object which has four properties to an action controller but unfortunately it is not getting through and I get the following error.
The parameters dictionary contains a null entry for parameter 'batchID' of non-nullable type 'System.Int32' for method 'System.Web.Mvc.JsonResult GetItems(Int32, Ebiquity.Reputation.Neptune.Web.Models.MyWorkFilterModel)' in 'Ebiquity.Reputation.Neptune.Web.Controllers.MyWorkController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter.
Parameter name: parameters
The JSON being passed is:
{
"batchID": 21610,
"filter":
{
"issueNo": "1",
"messageNo": "2",
"itemDate": "Wed, 05 Feb 2014 00:00:00 GMT",
"mediaName":"3"
}
};
The ajax call:
self.GetItems = function (batchID, issueNo, messageNo, itemDate, mediaName) {
var filter = {
issueNo: issueNo,
messageNo: messageNo,
itemDate: itemDate,
mediaName: mediaName
};
$.ajax({
type: "GET",
url: "/MyWork/GetItems",
data: JSON.stringify({
batchID: batchID,
filter: filter
}),
dataType: "json",
success: function (result) {
self.Items([]);
if (result.Items != null) {
var tempItems = ko.mapping.fromJS(result.Items, mappingOptions);
self.Items.push.apply(self.Items, tempItems());
}
}
});
};
The controller:
[HttpGet]
public JsonResult GetItems(int batchID, MyWorkFilterModel filter)
{
using (var rep = new WorkRepository(CurrentUser))
{
return Json(rep.GetBatch(batchID, filter), JsonRequestBehavior.AllowGet);
}
}
The filter model:
public class MyWorkFilterModel
{
public int? IssueNo { get; set; }
public int? MessageNo { get; set; }
public string MediaName { get; set; }
public DateTime? ItemDate { get; set; }
}
You have to change type of your AJAX call to POST instead of GET. Data parameters will not be send with GET requests.
Looks like your batchID is null. Either set it as 0 in javascript or make it nullable in action
[HttpGet]
public JsonResult GetItems(int? batchID, MyWorkFilterModel filter)
{
}
You may try to make IssueNo and MessageNo as integers instead of strings. And use POST instead of GET.
If you have to use GET, you may pass the parameters as a part of the url only!
We have a lot of discussions here like this (see the below link)
Posting JSON data via jQuery to ASP .NET MVC 4 controller action
Try like below Ajax DataType:
self.GetItems = function (batchID, issueNo, messageNo, itemDate, mediaName) {
var filter = {
issueNo: issueNo,
messageNo: messageNo,
itemDate: itemDate,
mediaName: mediaName
};
$.ajax({
type: "POST",
url: "/MyWork/GetItems",
dataType: 'text',
data: "param=" + JSON.stringify({
batchID: batchID,
filter: filter
}),
success: function (result) {
self.Items([]);
if (result.Items != null) {
var tempItems = ko.mapping.fromJS(result.Items, mappingOptions);
self.Items.push.apply(self.Items, tempItems());
}
}
});
};
The controller
[HttpPost]
public JsonResult GetItems(String Param)
{
}
As mentioned by Semao, if you want that kind of JSON you need to use POST. Since your posting the JSON in that way, I guess you just have a typo and intend to use POST.
If you really want GET, you need to pass the values in the URL.
In your case, youneed to add:
[FromUri]
before the objects.
Example:
public class QueryObj
{
public int Id { get; set; }
public string Name { get; set; }
}
public Result Get([FromUri] QueryObj queryObj)
{...}
http://.../query?Id=1&Name=test
I was missing the contenttype property of the ajax call and instead of GET I used POST and it worked.
$.ajax({
type: "POST",
url: "/MyWork/GetItems",
data: JSON.stringify({
batchID: batchID,
filter: filter
}),
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function (result) {
}
});

Retrieve a value from a request with content type application/json

I have the following script that is sending data to a controller in MVC:
$.ajax({
url: '/products/create',
type: 'post',
contentType: 'application/json; charset=utf-8',
data: JSON.stringify({
'name':'widget',
'foo':'bar'
})
});
My controller looks like this:
[HttpPost]
public ActionResult Create(Product product)
{
return Json(new {success = true});
}
public class Product
{
public string name { get; set; }
}
Is there a way I can get the "foo" variable in my controller action without
modifying the model
modifying the signature of the action
If it was a regular form submission, I would have access to Request.Form["foo"], but this value is null since it was submitted via application/json.
I want to be able to access this value from an Action Filter and that is why I don't want to modify the signature/model.
I wanted to do almost exactly the same today and found this question with no answer. I also solved it with similar solution as Mark.
This works very well for me in asp.net MVC 4. Could maybe help someone else reading this question even if it is an old one.
[HttpPost]
public ActionResult Create()
{
string jsonPostData;
using (var stream = Request.InputStream)
{
stream.Position = 0;
using (var reader = new System.IO.StreamReader(stream))
{
jsonPostData = reader.ReadToEnd();
}
}
var foo = Newtonsoft.Json.JsonConvert.DeserializeObject<IDictionary<string, object>>(jsonPostData)["foo"];
return Json(new { success = true });
}
The important part was to reset the position of the stream because it is already read by some MVC internal code or whatever.
I want to be able to access this value from an Action Filter and that
is why I don't want to modify the signature/model.
Accessing the value from the Action filter would be tricky without changing the signature of the method. The reason will be better understand from this post.
This code will work in an authorization filter or somewhere the code that runs before the model binding.
public class CustomFilter : FilterAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationContext filterContext)
{
var request = filterContext.RequestContext.HttpContext.Request;
var body = request.InputStream;
var encoding = request.ContentEncoding;
var reader = new StreamReader(body, encoding);
var json = reader.ReadToEnd();
var ser = new JavaScriptSerializer();
// you can read the json data from here
var jsonDictionary = ser.Deserialize<Dictionary<string, string>>(json);
// i'm resetting the position back to 0, else the value of product in the action
// method will be null.
request.InputStream.Position = 0;
}
}
Even if this 'foo' is not binded, it will be available in you action filter through :
filterContext.HttpContext.Current.Request.Params
Have a look into these collection if you see your parameter.
So yes just create your action filter and don't change the signature it will works.
Just in case debug your filter to be sure where will be the value.
Lastly you need to have your values provider for json registered in your global.asax :
protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
ValueProviderFactories.Factories.Add(new JsonValueProviderFactory());
}
You parameter is wrong as well it need to be more like :
$.ajax({
url: '/products/create',
type: 'post',
contentType: 'application/json; charset=utf-8',
data: JSON.stringify({
name:'widget',
foo:'bar'
})
});
without quote.
Edit (to be more precise):
your filter will contains these method
public void OnActionExecuting(ActionExecutingContext filterContext)
{
}
public void OnActionExecuted(ActionExecutedContext filterContext)
{
}

Categories

Resources