This is my model class:
public class SearchForFlight
{
public SearchForFlight()
{
Segments = new otherType();
}
public int AdultCount { get; set; }
public JourneyType JourneyType { get; set; }
public string Sources { get; set; }
public otherType Segments { get; set; }
}
public class otherType
{
public string Origin { get; set; }
public string Destination { get; set; }
public FlightCabinClass FlightCabinClass { get; set;}
public DateTime PreferredDepartureTime { get; set;
public DateTime PreferredArrivalTime { get; set; }
}
Now, My requirement is to post objects along with nested object to an external api.
The required form is something like this:
{
AdultCount: $("#AdultCount").val(),
JourneyType: $("#JourneyType :selected").text(),
PreferredAirlines: null,
Segments: [
{
Origin: $("#Origin").val(),
Destination: $("#Destination").val(),
FlightCabinClass: $("#FlightCabinClass").val(),
PreferredDepartureTime:$("#PreferredDepartureTime").val(),
PreferredArrivalTime: $("#PreferredArrivalTime").val(),
}
]
}
So, i have created another class OtherType and put all those nested objects into it.
I got the idea from this so question
How to send nested json object to mvc controller using ajax
Now, this is my Script tag with all the code inside to post simple objects along with nested objects.But nested objects value comes out to be null.
How should i model this code here.
<script>
$(document).ready(function () {
$("#btnPost").click(function () {
var sof = {
AdultCount: $("#AdultCount").val(),
JourneyType: $("#JourneyType :selected").text(),
PreferredAirlines: null,
Segments: [
{
Origin: $("#Origin").val(),
Destination: $("#Destination").val(),
FlightCabinClass: $("#FlightCabinClass").val(),
PreferredDepartureTime: $("#PreferredDepartureTime").val(),
PreferredArrivalTime: $("#PreferredArrivalTime").val(),
}
],
};
$.ajax(
{
url: "/api/Flight/SearchFlight",
type: "Post",
data: sof,
success: function (data) {
alert(data);
}
});
});
});
</script>
Posted Properties values for Origin, Destination comes out to be null.
The textbox rendered on view page are something like this:
#Html.TextBoxFor(model => model.Segments.Origin)
Any hint please.
Remove the array [] for Segments. Use contentType and stringify in your $.ajax func. Use the generated id for the Origin. It might not be "Origin". So,pls change it accordingly.
<script>
$(document).ready(function () {
$("#btnPost").click(function () {
var sof = {
AdultCount: $("#AdultCount").val(),
JourneyType: $("#JourneyType :selected").text(),
PreferredAirlines: null,
Segments: {
Origin: $("#Origin").val(),
Destination: $("#Destination").val(),
FlightCabinClass: $("#FlightCabinClass").val(),
PreferredDepartureTime: $("#PreferredDepartureTime").val(),
PreferredArrivalTime: $("#PreferredArrivalTime").val(),
},
};
$.ajax(
{
url: "/api/Flight/SearchFlight",
type: "Post",
contentType: 'application/json',
data: JSON.stringify(sof),
success: function (data) {
alert(data);
}
});
});
});
</script>
Related
I have tried different methods that have been posted on this site, but nothing seems to work.
I want to create a clothing site (a personal project). The products on the site have their own class, that is built like this:
public class Product
{
public string ProductName { get; set; }
public string ProductPrice { get; set; }
public int Quantity { get; set; }
}
The shopping cart is another class that will contain a list of Product objects and this one is built like this:
public class ShoppingCart
{
[Key]
public int Id { get; set; }
List<Product> ProductList { get; set; }
public string ClientName { get; set; }
public string ClientAddress { get; set; }
public string ClientMail { get; set; }
}
I created an API Controller class and thought that would solve the problem. It looks like this:
[Route("api/Shopping")]
[ApiController]
public class ShoppingCartController : ControllerBase
{
[HttpPost]
public ShoppingCart Save([FromBody] ShoppingCart s)
{
return s;
}
}
In my JavaScript code I create my JSON object and try to post it like this:
var orderB = document.getElementById("orderB");
orderB.addEventListener("click", function () {
var inputName = document.getElementById("inputName").value;
var inputAddress = document.getElementById("inputAddress").value;
var inputMail = document.getElementById("inputMail").value;
var auxArray = [];
for (var i = 0; i < productsAux.length; i++) {
auxArray[i] = { "productName": productsAux[i].titlu, "productPrice": productsAux[i].pret, "quantity": localStorage.getItem(productsAux[i].titlu)};
}
var shoppingCart = {
productList: auxArray,
clientName: inputName,
clientAddress: inputAddress,
clientMail: inputMail
};
$.ajax({
type: "POST",
data: JSON.stringify(shoppingCart),
url: "api/shopping/save",
contentType: "application/json charset=utf-8",
}).done(function (res) {
alert(res);
});
After I push the order button on my page I expect to see the alert pop-up with the callback result which I suppose is the ShoppingCart object that is created using the JSON that I send.
For those coming on later, I would suggest checking that your types are correct on both ends. For instance, if your JS is posting a byte array and C# tries to convert it to an int, the whole object (not just that prop) will be null.
This has caught me many a time.
I opened the Network tab and I got this: I got a 404 (kind of
expected that) , the name of the method 'save' , a type of 'xhr' and a
size of 45B.
The 404 error obviously means the url/routing is wrong. Here to solve it ,you have two ways to achieve.
First way:
You can change url to "api/shopping" in ajax as follow:
$.ajax({
type: "POST",
data: JSON.stringify(shoppingCart),
url: "api/shopping",
contentType: "application/json charset=utf-8",
}).done(function (res) {
alert(res);
})
Second way:
You can change the path name
of Save action by Attribute routing with Http verb attributes as follow:
[Route("api/Shopping")]
[ApiController]
public class ShoppingCartController : ControllerBase
{
[HttpPost("Save")]
public ShoppingCart Save([FromBody] ShoppingCart s)
{
return s;
}
}
Update
According to your comment, in addition to the above updates, you also need to modify the routing settings as follows:
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
Debug result:
I need to convert a json file to match a viewmodel parameter for a WebAPI 2 post (language C#).
But when it hits the API controller, the param (data from body) is null.
My .json file to set up to match my model
{
"Data": {
"DataHeader": {
"MessageTrackingIdentifier": "18c64415-05cc-415e-9cf1-034bdc4dbdac",
"MessageName": "USERS"
},
"DataDetail": [
{
"CustomerCode": "0002888802",
"CustomerName": "SGG (Pty) Limited "
},
{
"CustomerCode": "0002034092",
"CustomerName": "AAG (Pty) Limited "
}
]
}
}
My model:
public class TUserModel
{
public TUserDataModel Data { get; set; }
}
public class TUserDataModel
{
public TDataHeader DataHeader { get; set; }
public List<TUserModelDataDetail> DataDetail { get; set; }
}
public class TUserModelDataDetail
{
public string CustomerCode { get; set; }
public string CustomerName { get; set; }
}
public class TDataHeader
{
public string MessageTrackingIdentifier { get; set; }
public string MessageName { get; set; }
}
My WebAPI 2 action
public IHttpActionResult PostUser([FromBody] TUserModel model)
Ajax postfunction:
function PostUserData(viewModel)
{
var model = JSON.stringify(viewModel);
$.ajax({
url: "http://localhost:60667/api/User",
type: "POST",
contentType: "application/json; charset=utf-8",
dataType: "json",
crossDomain: true,
data: model,
success: function (reply)
{
$('.js-call-UserApi').css("background", "green");
},
error: function (jqXHR, errorData)
{
alert('error: ' + JSON.stringify(jqXHR.responseText, errorData));
}
});
}
The js call of the file to the Ajax Post function: (filename it reads is 'UserFA.json')
var oXHR = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
function reportStatus()
{
if (oXHR.readyState == 4) // Request completed.
PostUserData(this.responseText); // All set. Now show the data.
}
oXHR.onreadystatechange = reportStatus;
oXHR.open("GET", "UserFA.json", true); // true = ASYNCHRONOUS REQUEST (DESIRABLE), false = SYNCHRONOUS REQUEST.
oXHR.send();
Edit: The file once read in and stringified and cleaned of formatting characters
"{"Data":
{"DataHeader": {"MessageTrackingIdentifier": "18c64415-05cc-415e-9cf1-034bdc4dbdac", "MessageName": "USERS"},
"DataDetail":
[
{ "CustomerCode": "0002888802 ", "CustomerName": "SGG (Pty) Limited "},
{ "CustomerCode": "0002034092 ", "CustomerName": "AAG (Pty) Limited "}
]
}
}"
Thanks
Your json and model don't quite match. The json has an object named "Data" which then contains "DataHeader" and "DataDetail" -- but in your model, these properties are all at the same level in your TUserModel object and Data is a string not an object. If you want to change the model to match the json, then you will need to change TUserModel to:
public class TUserModel
{
public TUserDataModel Data { get; set; }
}
And add an intermediate object, which I'm calling TUserDataModel:
public class TUserDataModel
{
public TDataHeader DataHeader { get; set; }
public List<TUserModelDataDetail> DataDetail { get; set; }
}
If you want to change the json and leave the model mostly the same, then remove the "Data" level, thus moving DataHeader and DataDetail up. You could then also remove the string "Data" property from your TUserModel class.
{
"DataHeader": {
...
},
"DataDetail": [
...
]
}
My JavascriptCode
//insert the employee and department record
this.insertEmployeeDepartment = function (Employee) {
var request = $http({
method: "post",
url: "/Employee/InsertEmployeeDepartment",
contentType: "application/json",
data: JSON.stringify(Employee)
});
return request;
}
EmployeesAPIController.cs
using System.Web.Http;
namespace EmployeeService
{
[RoutePrefix("Employee")]
public class EmployeesAPIController : ApiController
{
[HttpPost]
[Route("InsertEmployeeDepartment")]
public EmployeeDepartment InsertEmployeeAndDepartment([FromBody]EmployeeDepartment emp)
{
var xx = emp;
}
}
}
EmployeeDepartment.cs
using System.Collections.Generic;
namespace Test
{
public class EmployeeDepartment
{
public IEnumerable<Employee> Employees { get; set; }
public IEnumerable<Department> Departments { get; set; }
}
}
Models -
Employee.cs
public class Employee
{
public int EmployeeId { get; set; }
public string EmployeeName { get; set; }
public int Age { get; set; }
public int Salary { get; set; }
public int DepartmentId { get; set; }
}
Department.cs
public class Department
{
public int Deptid { get; set; }
public string Deptname { get; set; }
}
The array that I am passing from Javascript is as under
In the controller method, the value is coming as null?
What wrong I am making?
Given your Javascript Object array (and not sure if it is limited to just two entries), we can re-write your javascript post model to mimic your WebApi request model.
Something like (remeber limited to 2 objects in the javascript array).
this.insertEmployeeDepartment = function (Employee) {
//construct a new object to match the WebApi Object
var dto = {
Employees: [Employee[0]], //Employee[0] is the employee record
Departments: [Employee[1]] //Employee[1] is the department record
};
var request = $http({
method: "post",
url: "/Employee/InsertEmployeeDepartment",
contentType: "application/json",
data: JSON.stringify(dto)
});
return request;
}
Now if your JavaScript array is constructed differently per method you will have to format your new model data object differently.
Edit:
To make it match exactly as i see your WebApi DepartmentId property is not on the Employee[0] record we can copy it over manually. Such as.
this.insertEmployeeDepartment = function (Employee) {
//construct a new object to match the WebApi Object
Employee[0]['DepartmentId'] = Employee[1].Deptid;
var dto = {
Employees: [Employee[0]], //Employee[0] is the employee record
Departments: [Employee[1]] //Employee[1] is the department record
};
var request = $http({
method: "post",
url: "/Employee/InsertEmployeeDepartment",
contentType: "application/json",
data: JSON.stringify(dto)
});
return request;
}
Your javascript object is an array that essentially contains a object of each type. You need to use an object that contains an array of objects of each type.
So what you have is something like
[{Age:"23", EmployeeId:"67", EmployeeName:"TestEmpName", Salary:"6666"}, {Deptid:"34", Deptname:"New Dept"}]
What you need is something like
{Employees: [{Age:23, EmployeeId:67, EmployeeName:"TestEmpName", Salary:6666, DepartmentId:0 }],
Departments: [{Deptid:34, Deptname:"New Dept"}]}
How can I pass JsonResult object from javascript function in View to Controller Action without Ajax call - just javascript - window.location.href = url?
I get JsonResult object from Controller Action to javascript function via Ajax call. Then I want to pass this object back to other Controller Action but I get object with null reference properties.
My javascript function in View:
function order(model) {
$('#details-container').html("<h2>Loading Complete Frame Module. Please wait...</h2>");
$.p({
url: '#Url.Action("CompleteFrameBrandDetails", "PacCompleteFrame")',
data: { item: model },
success: function (xml) {
if (xml.Success) {
$.p({
url: '#Url.Action("GlassCompleteFrame", "PacModule")',
data: JSON.stringify({ b2bXml: xml.Data }),
success: function (model) {
var pacModuleModel = {
Mode: model.Data.Mode,
IframeUrl: model.Data.IframeUrl.toString(),
CustomerNumber: model.Data.CustomerNumber.toString(),
ReadOnly: model.Data.ReadOnly,
GlassXml: model.Data.GlassXml.toString(),
Price: parseFloat(model.Data.Price),
Comission: model.Data.Comission.toString(),
Permissions: null,
Language: model.Data.Language.toString()
};
// here are all values in model.Data correct
// but then I can't figure out how to pass it to Controller Action without Ajax call - just with javascript command
var url = '#Url.Action("GlassCompleteFrameView", "PacModule", "__view__")';
window.location.href = url.replace("__view__", model.Data); //pacModuleModel
}
});
} else {
$.alert({
message: 'error while trying to load xml details'
});
}
}
});
}
My Controller Action:
public ActionResult GlassCompleteFrameView(PacModuleModel model)
{
// here I get object module but
// model.CustomerNumber = null
// model.GlasXml = null
// model.Price = null
// ...
return View("Glass", model);
}
I have also Model like this for automatic Json binding but dont work:
public enum ModuleMode
{
ByProduct,
ByRecipe
}
public partial class PacModuleModel
{
private PacPermissionModel permissionModel;
public ModuleMode Mode { get; set; }
public string IframeUrl { get; set; }
public string CustomerNumber { get; set; }
public bool ReadOnly { get; set; }
public string GlassXml { get; set; }
public double? Price { get; set; }
public string Comission { get; set; }
public PacPermissionModel Permissions
{
get
{
if (permissionModel == null)
{
permissionModel = new PacPermissionModel();
}
return permissionModel;
}
}
public string Language { get; set; }
}
Try this in controller
public JsonResult GlassCompleteFrameView(PacModuleModel model)
{
// here I get object module but
// model.CustomerNumber = null
// model.GlasXml = null
// model.Price = null
// ...
return Json(model, JsonRequestBehavior.AllowGet);
}
The problem was in model. It was more than 45000 char long. Now I use Session variable to get model in GlassCompleteFrameView(PacModuleModel model) and works perfect.
public ActionResult GlassCompleteFrameView(PacModuleModel model)
{
model = Session["xml"] as PacModuleModel;
return View("Glass", model);
}
I am trying to create Product instance in Javascript and than to pass it to the server using [webmethod].
[WebMethod]
public static void SetProduct(Product product)
{
// i want a product instance
}
Following is Product class that i'm trying to create:
public class Product
{
public Type Type { get; set; }
public Foo Foo { get; set; }
public List<Bar> Bars { get; set; }
}
public class Type
{
public string ID { get; set; }
}
public class Foo
{
public string ID { get; set; }
public string Color { get; set; }
}
public class Bar
{
public string Name { get; set; }
}
I am being able to create Type and Foo but not List<Bar> in Javascript: (see my comments in the code for more details)
Javascript
function setProduct() {
var product = {};
product.Type = {};
product.Foo = {};
product.Type.ID = 'typeID';
product.Foo.ID = 'fooID';
product.Foo.Color = 'fooColor';
//here is my question how can create List<Bar> Bars and add it to product item???
$.ajax({
type: "POST",
url: "Default.aspx/SetProduct",
contentType: "application/json; charset=utf-8",
dataType: "json",
async: false,
data: "{product:" + JSON.stringify(product) + "}",
});
}
JavaScript doesn't know what a List<T> is. It only knows how to make arrays. So you'll have to construct an array of Bars and pass that in the JSON.
Fortunately, it's an easy fix:
product.Bars = [
{ Name: "bar 1" },
{ Name: "bar 2" },
{ Name: "bar 3" },
];
The above is probably all you need. I'm pretty sure ASP.NET will be smart enough to convert that Bar[] into a List<Bar> automagically, but just in case it isn't:
public class Product
{
public Type Type { get; set; }
public Foo Foo { get; set; }
public IEnumerable<Bar> Bars { get; set; }
}
Then if you still want List<T> functionality, just convert the array to a List in your WebMethod:
[WebMethod]
public static void SetProduct(Product product)
{
var list = product.Bars.ToList();
product.Bars = list;
return product;
}
Now you can still access those nice List<T> methods:
((List<Bar>)product).Add(new Bar() { Name = "bar 4" });
// create an array
product.Bars = [];
// add an element to the array
product.Bars.push({
Name: "Foo"
});
alternatively you can initialize the array with elements as well:
// create and initialize array
product.Bars = [{Name:"Foo"}, {Name:"Bar"}];
Use an array, and add the items to the array with array.push. Eg :
product.Bars = [];
product.Bars.push({ Name: "foo" });