Parameters not passing through to MVC Controller with Guid ID - asp.net

I have the following controller action using the web api on a .net 4.0 web forms web application.
public dynamic Post(Guid id, string adminNotes = "", string artNotes = "")
{
dynamic response = new ExpandoObject();
response.Success = false;
Udac udac = CustomerUdacs.Where(x => x.EditKey == id).FirstOrDefault();
if (udac != null)
{
udac.AdminNotes = adminNotes.Trim();
udac.ArtNotes = artNotes.Trim();
response.Success = true;
}
return response;
}
I'm using jQuery ajax() to post the data through. I am using a Guid as my id (which is stored in ajax_edit_key in my javascript). When I use this:
$.ajax({
type: "POST",
url: "/api/notes/"+ajax_edit_key,
data: { adminNotes: $("#tbEditNotesAdmin").val(), artNotes: $("#tbEditNotesArt").val() }
}).done(function (data) {
if (data.Success) {
$("#tbEditNotesAdmin").val(''); //td.id-notes-admin
$("#tbEditNotesArt").val(''); //td.id-notes-art
ajax_edit_key = '';
$dialog.dialog("close");
}
}).fail(function () {
alert('fail');
});
it calls the action but my adminNotes and artNotes are passing through from the browser as empty strings.
If I change the url to include the parameters in the querystring it works fine.
url: "/api/notes/"+ajax_edit_key+"?"+ "adminNotes="+$('#tbEditNotesAdmin').val()+"&artNotes="+$('#tbEditNotesArt').val()
//data: { adminNotes: $("#tbEditNotesAdmin").val(), artNotes: $("#tbEditNotesArt").val() }
Why is this? How can I get it to use the data parameter

The problem here is the way how WebAPI engine parses multiple parameters. It can parse only one parameter, which comes from body request by default, and you have two.
The solution would be:
To create your own model binder (this article would help you: http://blogs.msdn.com/b/jmstall/archive/2012/04/18/mvc-style-parameter-binding-for-webapi.aspx)
To create a separate model class that will contain all your passing parameters (which is easier to me).
For the second option you need simply to create the model:
public class NotesModel
{
public string AdminNotes { get; set; }
public string ArtNotes { get; set; }
}
And change signature of your action to:
public dynamic Post(Guid id, NotesModel model)
And you don't need to change your JS.

Related

JsonRequestBehavior.AllowGet does not work with HttpGet

I've read MSDN documentation of JsonRequestBehavior.AllowGet and many answers here at SO. I experimented and I am still confused.
I have the following action method. It works fine if I use POST method in my ajax call. It fails with status 404 (Resource not found) if I use GET method in my ajax call. So, the question is what exactly does the JsonRequestBehavior.AllowGet enum do in this Json method? The MSDN documentation says: AllowGet HTTP GET requests from the client are allowed. (https://msdn.microsoft.com/en-us/library/system.web.mvc.jsonrequestbehavior(v=vs.118).aspx), but then why does it fail when I use GET method in my ajax call? Changing the attribute from HttpPost to HttpGet does not help, it fails with either POST or GET method.
[HttpPost]
public JsonResult Create(Model m)
{
m.Ssn = "123-45-8999";
m.FirstName = "Aron";
m.LastName = "Henderson";
m.Id = 1000;
return Json(m, JsonRequestBehavior.AllowGet);
}
public class Model
{
public int Id { get; set; }
public string Ssn { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
Here is my jQuery ajax call:
$(function () {
console.log("hola");
$("button").on("click", function () {
$.ajax({
method: "POST", //Try changing this to GET and see.
url: "Home/Create",
data: { Id: 123, Ssn: "585-78-9981", FirstName: "John", LastName: "Smith" }
})
.done(function (msg) {
alert("Data Saved: " + msg);
});
});
})
A 404 (Resource not found) means the method is not found (and has nothing to do with JsonRequestBehavior).
Change your ajax to use
$.ajax({
url: "/Home/Create", // note leading forward slash
....
or better, use url: '#Url.Action("Create", "Home")', to correctly generate your url.
404's are due to the attributes, nothing to do with "AllowGet" on the JSON.
You need one or the other [HttpVERB] attributes... not both attributes.
This would work if it is your scenario.
[AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
You should check out this well documented post
AllowGet will simply allow that JSON response to work over the GET scenario without exception. If you do not, you will see this message:
This request has been blocked because sensitive information could be
disclosed to third party web sites when this is used in a GET request.
To allow GET requests, set JsonRequestBehavior to AllowGet.

JSON Post Request is not working in ASP.NET5 MVC but is working in ASP.NET4.5 MVC

I have an example which sends a JSON post request to MVC controller. This example works in ASP.NET 4.5 but won’t work in the newest ASP.NET 5 release. Do I miss anything in this example?
I created a model, but I didn’t bind it to database. It will be just the object created in the memory.
public class SalesOrder
{
public int SalesOrderId { get; set; }
public string CustomerName { get; set; }
public string PONumber { get; set; }
}
I use Visual Studio 2015 to create that model based controller and its associated CRUD views. However, in this example, I will only run the “Create” view.
Inside the controller, I hard coded a SalesOrder object list and it only contains an item. I will use it to work with the CRUD views.
private List<SalesOrder> salesOrderList =
new List<SalesOrder> (
new SalesOrder[]
{
new SalesOrder()
{
SalesOrderId = 1,
CustomerName = "David",
PONumber = "123"
}
});
Inside the controller, I also create a new function to process the “Save” request. The request will just change the CustomerName property of the model then bounce back with the JSON result.
[HttpPost]
public JsonResult Save(SalesOrder salesOrderViewModel)
{
salesOrderViewModel.CustomerName = "David returns";
return Json(new { salesOrderViewModel });
}
In the Create.cshtml, I created a button and attach JQuery script to its click event.
<p><button id="saveButton">Save</button></p>
This is the JQueryScript.
$(function () {
var clickFunc = function () {
var salesOrderViewModel = {
"salesOrderViewModel": {
"SalesOrderId": 123,
"CustomerName": "ab",
"PONumber": "2",
}
}
$.ajax({
url: "/SalesOrders/Save/",
type: "POST",
cache: false,
data: JSON.stringify(salesOrderViewModel),
contentType: "application/json; charset=utf-8"
});
}
$('#saveButton').click(clickFunc)
})
I click the "Save" button in Create.cshtml to trigger the post request.
I set the debug break point in the controller and verify the coming post request. In ASP.NET 4.5, the JSON deserialization is working, and it shows all the values.
However, in ASP.NET 5, an empty object is returned.
In ASP.NET 5 case, if press F12 to start the debugger in Microsoft Edge, then it shows the Post request does have the correct values, but for some reasons, they are not passed to MVC controller.
Please see these screen shots:
http://i63.tinypic.com/68vwnb.jpg
Do I miss anything?
Thanks for helping…
I don't think you need to specify the name of the parameter. Try:
var salesOrderViewModel = {
"SalesOrderId": 123,
"CustomerName": "ab",
"PONumber": "2",
}
I think you need to especify fromBody in the Controller.
[HttpPost]
public JsonResult Save([FromBody]SalesOrder salesOrderViewModel)
{
salesOrderViewModel.CustomerName = "David returns";
return Json(new { salesOrderViewModel });
}
Thanks for DCruz22 and Stephen Muecke.
The working version of the script is:
$(function () {
var clickFunc = function () {
var salesOrderViewModel = {
"salesOrderViewModel": {
"SalesOrderId": 0,
"CustomerName": "ab",
"PONumber": "2",
"MessageToClient": "POST to server"
}
}
$.ajax({
url: "/SalesOrders/Save/",
type: "POST",
cache: false,
data: salesOrderViewModel
});
}
$('#saveButton').click(clickFunc)
})
I found the parameter name "salesOrderViewModel" is not a problem. With it, the script is still working.
Actually, this question is a simplified version of my original problem. My originally problem is starting from the knockoutJs. Below is the script doing the data binding. After user clicks the "Save" button, the self.save function() is called and the script will send the post request including the data model to the MVC controller.
SalesOrderViewModel = function (data) {
var self = this;
ko.mapping.fromJS(data, {}, self);
self.save = function () {
$.ajax({
url: "/SalesOrders/Save/",
type: "POST",
cache: false,
data: ko.toJSON(self),
success: function (data) {
}
});
}
}
The problem is "ko.toJSON(self)" includes some other information. Below is the request body I captured from the Microsoft Edge debugger.
{"SalesOrderId":0,
"CustomerName":"chiang123",
"PONumber":"123",
"MessageToClient":null,
"__ko_mapping__":{
"ignore":[],
"include":["_destroy"],
"copy":[],
"mappedProperties":{
"SalesOrderId":true,
"CustomerName":true,
"PONumber":true,
"MessageToClient":true}}}
You can see all data starts from "ko_mapping" is KnockoutJs specific. Do I need to manually trim those data in order to make this work? Per information, obviously the same implementation should work in ASP.NET 4.5 but I just haven't try it yet. Many thanks...

AJAX Passing multiple parameter to WebApi

AJAX request:
$.ajax({
url: url,
dataType: 'json',
type: 'Post',
data: {token:"4", feed:{"id":0,"message":"Hello World","userId":4} }
});
Server Side Web API:
[HttpPost]
public HttpResponseMessage Post(string token, Feed feed)
{
/* Some code */
return new HttpResponseMessage(HttpStatusCode.Created);
}
Error Code 404: {"message":"No HTTP resource was found that matches
the request URI 'localhost:8080/api/feed'.","messageDetail":"No action
was found on the controller 'Feed' that matches the request."}
Why I am getting this error and Why I am not able POST multiple parameters to my API?
Start by writing a view model:
public class MyViewModel
{
public string Token { get; set; }
public Feed Feed { get; set; }
}
that your controller action will take as parameter:
[HttpPost]
public HttpResponseMessage Post(MyViewModel model)
{
/* Some code */
return new HttpResponseMessage(HttpStatusCode.Created);
}
and finally adapt your jQuery call to send it as JSON:
$.ajax({
url: url,
type: 'POST',
contentType: 'application/json',
data: JSON.stringify({
token: '4',
feed: {
id: 0,
message: 'Hello World',
userId: 4
}
})
});
Important things to note for the AJAX call:
setting the request contentType to application/json
wrapping the data in a JSON.stringify function to effectively convert the javascript object to a JSON string
removed the useless dataType: 'json' parameter. jQuery will automatically use the Content-Type response header sent by the server to deduce how to parse the result passed to the success callback.
Try this server-side (from memory you can only have a single FromBody parameter so it needs to contain all the incoming properties):
public class TokenAndFeed
{
public String token {get; set;}
public Feed feed {get; set;}
}
public HttpResponseMessage Post([FromBody]TokenAndFeed tokenAndFeed)
{
/* Some code */
return new HttpResponseMessage(HttpStatusCode.Created);
}
I had a similar problem recently and here's some info on how I solved it. I think the problem is to do with how WebApi handles parameters. You can read a bit about it here and here but essentially there are two ways to post parameters, in the body or in the uri. The body can only contain one parameter, but it can be a complex parameter, whereas the uri can contain any number of parameters (up to the uri character limit) but they must be simple. When jquery does a POST ajax call it tries to pass all data parameters in the body, which does not work in your case since the body can only have one parameter.
In code terms I think you need something like this:
var token = "4";
var feed = {Id:0, Message:"Hello World", UserId:4};
$.ajax({
url: "/api/Feed/?token=" + token,
dataType: 'json',
type: 'Post',
data: JSON.stringify(feed)
});
Hope that helps.
Can you post your Feed class, just to make sure the properies match up.
var data = {
token: "4",
feed: {Id:0,Message:"Hello World",UserId:4}
}
$.ajax({
url: "/api/Feed/",
dataType: 'json',
type: 'Post',
data: JSON.stringify(data)
});
Try with this one. You have to get json object data from body. Read Request's input streem and map it to your data model.
public class TokenAndFeed
{
public string Token { get; set; }
public Feed Feed { get; set; }
}
[HttpPost]
public HttpResponseMessage Post()
{
System.IO.Stream str;
String jsonContents;
Int32 strLen, strRead;
str = HttpContext.Current.Request.InputStream;
strLen = Convert.ToInt32(str.Length);
byte[] byteArray = new byte[strLen];
strRead = str.Read(byteArray, 0, strLen);
jsonContents = Encoding.UTF8.GetString(byteArray);
TokenAndFeed tAndf = JsonConvert.DeserializeObject<TokenAndFeed>(jsonContents);
// some code here
return new HttpResponseMessage(HttpStatusCode.Created);
}
hope this will help.

Pass an array of objects using jquery.load to MVC 3

I have run into an issue attempting to pass an array of objects to an MVC3 controller/action. I've found several discussions on the web (including here at SO) but none have solved my problem. Here is what I'm working with:
public class Person
{
public Guid TempId { get; set; }
public bool ReadOnly { get; set; }
[Required(ErrorMessage = "Required")]
public string Name { get; set; }
}
Here is what my controller action (currently, I've tried many variations) looks like:
[HttpGet]
public ActionResult AddPerson(List<Person> people)
{
if (null != people)
{
foreach (var person in people)
{
Debug.WriteLine(person );
}
}
return View();
}
I have tried numerous ways of structuring my jquery in order to call to action, but so far the only one I can get to work is if I manually encode the array of objects into the URL string like so:
var url = "AddPerson?people%5B0%5D.TempId=9FBC6EF8-67DB-4AB4-8FCE-5DFC0F2A69F9&people%5B0%5D.ReadOnly=true&people%5B0%5D.Name=Bob+Jones&people%5B1%5D.TempId=9FBC6EF8-67DB-4AB4-8FCE-5DFC0F2A6333&people%5B1%5D.ReadOnly=false&people%5B1%5D.Name=Mary+Jones #peopleDiv";
$("#peopleDiv").load(url, updatePeopleDiv);
The people%5B1%5D.ReadOnly=false is the encoded version of people[1].ReadOnly=false
I've tried other things such as:
var url = "AddPerson #peopleDiv";
var people = [];
people.push({'[0].TempId': '<valid guid>', '[0].ReadOnly': true, '[0].Name': 'Bob Jones' });
$("#peopleDiv").load(url, people, updatePeopleDiv); // nope
$("#peopleDiv").load(url, $.param(people, false), updatePeopleDiv); // nada
$("#peopleDiv").load(url, $.param(people, true), updatePeopleDiv); // nyet
I have also tried modifying the above by wrapping that people[] inside an object: var data = { arr: people } and then trying to send that data object various ways. All the ways (other than the one I got to work by manually encoding) result in one of three outcomes:
No controller action called (mismatch between how it's defined and how I called it)
Controller action called but param is null
Controller action called, and correct number of object elements in the array BUT none of the actual values from those objects is transferred (so I have an array of objects all with default values).
Any suggestions?
Just set contentType to 'application/json' and use JSON.stringify().
$.ajax({
contentType: 'application/json',
type: 'POST',
url: '/Controller/AddPerson',
data: JSON.stringify({
people: [
{
ReadOnly: false,
Name: 'Cristi'
},
{
ReadOnly: true,
Name: 'Matt'
}
]
}),
success: function (data) {
$("#peopleDiv").html(data);
},
error: function () {
console.trace();
}
});
Also, add/edit/delete requests should be done via POST.
[HttpPost]
public ActionResult AddPerson(List<Person> people)
{
if (null != people)
{
foreach (var person in people)
{
Debug.WriteLine(person );
}
}
return PartialView("viewname");
}

How to get Json Post Values with asp.net webapi

i'm making a request do a asp.net webapi Post Method, and i'm not beeing able to get a request variable.
Request
jQuery.ajax({ url: sURL, type: 'POST', data: {var1:"mytext"}, async: false, dataType: 'json', contentType: 'application/x-www-form-urlencoded; charset=UTF-8' })
.done(function (data) {
...
});
WEB API Fnx
[AcceptVerbs("POST")]
[ActionName("myActionName")]
public void DoSomeStuff([FromBody]dynamic value)
{
//first way
var x = value.var1;
//Second way
var y = Request("var1");
}
i Cannot obtain the var1 content in both ways... (unless i create a class for that)
how should i do that?
First way:
public void Post([FromBody]dynamic value)
{
var x = value.var1.Value; // JToken
}
Note that value.Property actually returns a JToken instance so to get it's value you need to call value.Property.Value.
Second way:
public async Task Post()
{
dynamic obj = await Request.Content.ReadAsAsync<JObject>();
var y = obj.var1;
}
Both of the above work using Fiddler. If the first option isn't working for you, try setting the content type to application/json to ensure that the JsonMediaTypeFormatter is used to deserialize the content.
After banging my head around for a while on this and trying many different things I ended up putting some breakpoints on the API server and found the key value pairs stuffed down in the request. After I knew where they were, it was easy to access them. However, I have only found this method to work with WebClient.UploadString. However, it does work easily enough and allows you to load up as many parameters as you like and very easily access them server side. Note that I am targeting .net 4.5.
CLIENT SIDE
// Client request to POST the parameters and capture the response
public string webClientPostQuery(string user, string pass, string controller)
{
string response = "";
string parameters = "u=" + user + "&p=" + pass; // Add all parameters here.
// POST parameters could also easily be passed as a string through the method.
Uri uri = new Uri("http://localhost:50000/api/" + controller);
// This was written to work for many authorized controllers.
using (WebClient wc = new WebClient())
{
try
{
wc.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
response = wc.UploadString(uri, login);
}
catch (WebException myexp)
{
// Do something with this exception.
// I wrote a specific error handler that runs on the response elsewhere so,
// I just swallow it, not best practice, but I didn't think of a better way
}
}
return response;
}
SERVER SIDE
// In the Controller method which handles the POST request, call this helper:
string someKeyValue = getFormKeyValue("someKey");
// This value can now be used anywhere in the Controller.
// Do note that it could be blank or whitespace.
// This method just gets the first value that matches the key.
// Most key's you are sending only have one value. This checks that assumption.
// More logic could be added to deal with multiple values easily enough.
public string getFormKeyValue(string key)
{
string[] values;
string value = "";
try
{
values = HttpContext.Current.Request.Form.GetValues(key);
if (values.Length >= 1)
value = values[0];
}
catch (Exception exp) { /* do something with this */ }
return value;
}
For more info on how to handle multi-value Request.Form Key/Value pairs, see:
http://msdn.microsoft.com/en-us/library/6c3yckfw(v=vs.110).aspx
I searched all morning to find an answer that depicted both client and server code, then finally figured it out.
Brief intro - The UI is an MVC 4.5 project that implements a standard view. The server side is an MVC 4.5 WebApi. The objective was to POST the model as JSON and subsequently update a database. It was my responsibility to code both the UI and backend. Below is the code. This worked for me.
Model
public class Team
{
public int Ident { get; set; }
public string Tricode { get; set; }
public string TeamName { get; set; }
public string DisplayName { get; set; }
public string Division { get; set; }
public string LogoPath { get; set; }
}
Client Side (UI Controller)
private string UpdateTeam(Team team)
{
dynamic json = JsonConvert.SerializeObject(team);
string uri = #"http://localhost/MyWebApi/api/PlayerChart/PostUpdateTeam";
try
{
WebRequest request = WebRequest.Create(uri);
request.Method = "POST";
request.ContentType = "application/json; charset=utf-8";
using (var streamWriter = new StreamWriter(request.GetRequestStream()))
{
streamWriter.Write(json);
streamWriter.Flush();
streamWriter.Close();
}
WebResponse response = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(response.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
}
catch (Exception e)
{
msg = e.Message;
}
}
Server Side (WebApi Controller)
[Route("api/PlayerChart/PostUpdateTeam")]
[HttpPost]
public string PostUpdateTeam(HttpRequestMessage context)
{
var contentResult = context.Content.ReadAsStringAsync();
string result = contentResult.Result;
Team team = JsonConvert.DeserializeObject<Team>(result);
//(proceed and update database)
}
WebApiConfig (route)
config.Routes.MapHttpRoute(
name: "PostUpdateTeam",
routeTemplate: "api/PlayerChart/PostUpdateTeam/{context}",
defaults: new { context = RouteParameter.Optional }
);
Try this.
public string Post(FormDataCollection form) {
string par1 = form.Get("par1");
// ...
}
try using following way
[AcceptVerbs("POST")]
[ActionName("myActionName")]
public static void DoSomeStuff(var value)
{
//first way
var x = value;
}

Resources