How can I send complex JavaScript object to ASP.net WebMethod? - javascript

I'm trying send my client-side custom object (JavaScript) to ASP.net Web Method. I use jQuery Ajax command to perform this operation.
There a example of my object:
function Customer() {
this.Name = "";
this.Surname = "";
this.Addresses = new Array();
}
I load data with this method:
function buildCurrentCustomer() {
var currentCustomer = new Customer();
/** General Info **/
currentCustomer.Name = $("#Name").val();
currentCustomer.Surname = $("#Surname").val();
currentCustomer.Addresses = new Array();
currentCustomer.Addresses["HOME"] = $("#adHome").val();
currentCustomer.Addresses["OFFICE"] = $("#adOffice").val();
return currentCustomer;
}
And finally I send data with this code:
$.ajax({
type: "POST",
url: "../_layouts/CustomerManager/MasterPage.aspx/SetCustomer",
contentType: "application/json; charset=utf-8",
dataType: "json",
data: "{customer: " + JSON.stringify(currentCustomer) + "}",
cache: false,
success: function (result) {
},
error: function (ex) {
WriteToConsole(ex.responseText);
}
});
My server-side methods is like that:
[WebMethod]
public static bool SetCustomer(CustomerModel Customer)
{
//My code...
}
and my CustomerModel class is like that:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Common.Model.JavaScriptModel
{
public class CustomerModel
{
/** General Info **/
public string Name {get;set;}
public string Surname {get;set;}
public Dictionary<string, string> Addresses { get; set; }
}
}
The problem is that when I execute Ajax Call server-side method doesn't execute. If I change signature of server-side method in:
public static bool SetCustomer(List<CustomerModel> Customer)
SetCustomer method is executed but the List is empty.
Why have I this problem? Where can I find documentation about this functionality?
Thanks

first, if you use the data like this
data: "{customer: " + JSON.stringify(currentCustomer) + "}",
on the code behind, you need to take the same parameter customer and not Customer, so this
public static bool SetCustomer(CustomerModel Customer) { ... }
needs to be changed to
public static bool SetCustomer(CustomerModel customer) { ... }
second, your Customer object in the javascript is like this if translated to asp.net
string Name;
string Surname;
List<string> Addresses;
but your class in the code behind for Addresses is using
Dictionary<string, string>
thus causing your data from client side can't be parsed in the server side and return an error to the client side, so you need to change your Addresses class to
public List<string> Addresses { get; set; }
and lastly, your code inside buildCurrentCustomer for the Addresses is being set like this
currentCustomer.Addresses = new Array();
currentCustomer.Addresses["HOME"] = $("#adHome").val();
currentCustomer.Addresses["OFFICE"] = $("#adOffice").val();
this will never add a value to Addresses since it's type is an array, but you set the value to it as if it was an object, so if you want to stick to use an array, you need to change it to
currentCustomer.Addresses = new Array();
currentCustomer.Addresses.push($("#adHome").val());
currentCustomer.Addresses.push($("#adOffice").val());
*Note:
use this if you want to use the Addresses as an array, but if you need the Addresses to be an object that contains HOME and OFFICE, I'll Edit the answer
Edit:
perhaps you can use a javascript object like this
currentCustomer.Addresses = {};
currentCustomer.Addresses["Home"] = $("#adHome").val();
currentCustomer.Addresses["Office"] = $("#adOffice").val();
to make the equivalent for Dictionary<string,string> but if it didn't work you could change your Addresses to class too like this
public List<Address> Addresses { get; set; }
and add class Address
public class Address
{
public string Home {get;set;}
public string Office {get;set;}
}
I myself never used a Dictionary myself, so I don't know if it's the same

You can change your source code like this..
AJAX-
data: JSON.stringify({'customer':currentCustomer});
ASP.net Web Method-
[WebMethod]
public static bool SetCustomer(object customer)
{
CustomerModel CM = new CustomerModel();
_Serializer = new JavaScriptSerializer();
_StringBuilder = new StringBuilder();
_Serializer.Serialize(customer, _StringBuilder);
CM = _Serializer.Deserialize<CustomerModel>(_StringBuilder.ToString());
}
Note that you have to initialize _Serializer and the _StringBuilder properties at the top of the page as global variables...
public static JavaScriptSerializer _Serializer;
public static StringBuilder _StringBuilder;

Related

How to dynamically call an ActionResult in your API by using an Ajax-call?

I have coded in the StartUp.cs the following code for calling my API.
services.AddHttpClient("MyApi", c =>
{
#if DEBUG
c.BaseAddress = new Uri("https://localhost:12345");
#else
c.BaseAddress = new Uri("https://myApi.com");
#endif
But when I want to call the ActionResult by using an Ajax-call, he can't find the API.
alert(apiUrl);
$.ajax({
url: apiUrl + '/MyApiProcesses/GetSomething',
type: 'POST',
So I have written this variable in a js-file.
var apiUrl = 'https://localhost:12345';
//var apiUrl = 'https://myApi.com';
I want to know if it is possible to write it dynamically. If you declare it in the startup, you don't have to declare it twice?
If you need to use urls in ajax or httpclient, I usually do it this way, but it takes several steps to get a string from appsettings.
Create AppUrl section in appsettings.json
"AppUrl": {
"DevUrl": "http//..",
"ProductUrl": "http//..",
.... another urls if needed
},
2.Create class for this section
public class AppUrlSettings
{
public string DevUrl{ get; set; }
public string ProdUrl{ get; set; }
....another urls
}
configure settings in startup
var appUrlSection=Configuration.GetSection("AppUrl");
services.Configure<AppUrlSettings>(appUrlSection);
var urls = appUrlSection.Get<AppUrlSettings>();
services.AddHttpClient("MyApi", c =>
{
#if DEBUG
c.BaseAddress = new Uri(urls.DevUrl);
#else
c.BaseAddress = new Uri(urls.ProdUrl;
#endif
});
now you can use them like this
public class MyController:Controller
{
private readonly IOptions<AppUrlSettings> _appUrls;
public MyController (IOptions<AppUrlSettings> appUrls)
{
_appUrls = appUrls;
}
public IActionResult MyAction()
{
var model= new Model
{
DevUrl=_appUrls.Value.DevUrl;
...
}
}
}
you can then use urls as hidden fields.
or you can get urls from model in javascript directly:
var devUrl = #Html.Raw(Json.Encode(#Model.DevUrl));
.....
Or if you need the urls in many places, it can make sense to create a special service that you can inject directly in the views you need

Print model data without saving

if (saleDetails.length) {
var htmlData;
var paymentStatus = 0;
if ($('#PaymentStatus option:selected').val() != 0) {
paymentStatus = $('#PaymentStatus option:selected').text()
}
var SaleAmount = parseFloat(total + vat).toFixed(2);
var data = {
'AccountID': $('#hdnAccountID').val(),
'QuoteID': $('#hdnQuoteID').val(),
'BranchID': $('#BranchID option:selected').val(),
'PONO': $('#PONO').val(),
'PaymentStatus': $('#PaymentStatus').val(),
'SalesDate': $('#SaleDate').val(),
'PaymentStatus': paymentStatus,
'PaymentTypeID': $('#PaymentType option:selected').val(),
'VAT': vat,
'TotalAmount': invoiceAmount,
'DiscountAmount': $('#discInput').val(),
'AmountPaid': $('#amountPaid').val(),
'SaleDetails': saleDetails
};
var json = JSON.stringify({ 'model': data });
public ActionResult printOrder(Models.DTO.Sales model)
{
return PartialView(model);
//return View(model);
}
I am working on POS , In sales client requirement is that we should give him an option of print , so that if client click on Print button we should open a new tab and show invoice , so client can take out print and if customer pay him then client will save SalesOrder.
The problem I am facing is that I am unable to open new tab from controller . And if I am trying to do this from java script I am unable to pass model to view from java script.
So please help me in this issue as I am not too much expert in MVC.
You can use Html.ActionLink to open the page in new tab from your Razor page as below.
#Html.ActionLink("Print", "Action", new { controller="PrintOrder" }, new { target="_blank" })
Html.ActionLink however does not allow you to pass complex objects. You can use trick as mentioned in this stackoverflow answer to pass your model. From the post:
MODEL: Make static Serialize and Deserialize methods in the class like
public class XYZ {
// Some Fields
public string X { get; set; }
public string Y { get; set; }
public string X { get; set; }
// This will convert the passed XYZ object to JSON string
public static string Serialize(XYZ xyz)
{
var serializer = new JavaScriptSerializer();
return serializer.Serialize(xyz);
}
// This will convert the passed JSON string back to XYZ object
public static XYZ Deserialize(string data)
{
var serializer = new JavaScriptSerializer();
return serializer.Deserialize<XYZ>(data);
}
}
VIEW: Now convert your complex object to JSON string before passing it in
Action View <%= Html.ActionLink(Model.x, "SomeAction", new { modelString = XYZ.Serialize(Model) })%>
CONTROLLER: Get the
object as string in Action method and convert it back to object before
using public ActionResult SomeAction(string modelString) { XYX xyz = XYX.Deserialize(modelString); }

How to send two Array objects using http in AngularJS?

How to receive two parameters as an array in http action(List abc, List) xyz.
after that attempt I use a model class. lik
public class ItemAndChecque
{
public List<SaleItem> saleitem { get; set; }
public List<itemChecqe> itemchecq { get; set; }
}
public IHttpActionResult TowArrayValue(List<ItemAndChecque> abc)
I did many attempt to solve it but not... Some one can send me any Solution.
Your arrays need to be grouped in one object array:
var Indata = {saleitem: $scope.saleitem,itemchecq: $scope.itemchecq}
$http({
url: "someAPI",
method: "POST",
data: Indata
});
Add ItemAndChecque as model class to your backend.
Then you can receive it in your API Controller like this:
public void Post(ItemAndChecque request)
{
var productRepository = new ProductRepository();
var newProduct = productRepository.Save(request.product);
}
Here request contains 2 props with values of saleitem and itemchecq
Edit: based on the comment of #Icycool

SPRING --- How to submit an array of object to controller

As title,
i using angularjs to submit
my spring controller:
#RequestParam(value = "hashtag[]") hashtag[] o
above are work for array parameter but not an array object
my js script:
$http({
method: 'POST',
url: url,
data: $.param({
hashtag : [{label:"success",value:"ok"},{label:"success",value:"ok"},{label:"success",value:"ok"}],
}),
headers: { 'Content-Type': 'application/x-www-form-urlencoded' } });
i observe from chrome, the form data is
hashtag[0][label]:success
hashtag[0][value]:10
hashtag[1][label]:success
hashtag[2][value]:10
hashtag[3][label]:success
hashtag[3][value]:10
But the Spring show me
org.springframework.web.bind.MissingServletRequestParameterException: Required hashtag[] parameter 'id[]' is not present
Previously i was able to receive an array of parameters, but not an object. so can someone enlighten me?
Try #RequestParam(value = "hashtag") hashtag[] o
Given that you have a class named hashtag havinf label and value attributes.
Try Using #ModelAttribute
Create a new Java class HashtagList like given below
public class HashTagList {
private List<HashTag> hashTag;
public List<HashTag> getHashTag() {
return hashTag;
}
public void setHashTag(List<HashTag> hashTag) {
this.hashTag = hashTag;
}
}
and in your controller method
#ModelAttribute("hashtag") HashTagList hashTagList
Is the java class name hashtag or HashTag ?
Because it is a POST request you can use #RequestBody annotation and create a DTO class to map the data you are sending or maybe even use your domain object.
For example, why not create reusable POJO class that can hold key->value pairs like:
#JsonPropertyOrder({"label", "value"})
public final class Pair<K,V> implements Map.Entry<K,V>, Serializable {
private final K key;
private final V value;
#JsonCreator
public Pair(#JsonProperty("label")K key, #JsonProperty("value")V value) {
this.key = key;
this.value = value;
}
// ... rest of the implementation
}
Note: I have assumed here you are using Jackson mapper, hence the JSON annotations.
Next step is to get the class that will hold the data structure you are sending from your client:
public class HashTags implements Serializable {
List<Pair<String, String>> hashtag = new ArrayList<>();
// ... rest of the implementation
}
Then in your controller you will have to do something like:
#RequestBody HashTags entity

Pass List<int> from Javascript to AJAX-Enabled WCF in ASP.Net page

I am calling a WCF method from an ASP.Net page, but I am getting format exception when WCF tries to deserialize the recordIds parameter received from JavaScript.
The first parameter passed to the WCF method needs to be of List type. Is there something wrong I have done in using JSON.stringify?
Javascript Code to call WCF
function Update() {
var myarray1 = new Array();
myarray1[0] = 1;
myarray1[1] = 11;
myarray1[2] = 14;
WCFService1.AJAXEnabledService.BatchUpdateRecords(
JSON.stringify({recordIDs: myarray1}) , "ddsd", "gggg",
updateGrid, OnError);
}
WCF method being called by above JavaScript
[OperationContract]
public bool BatchUpdateRecords(List<int> recordIds, string columnNameToUpdate, string columnValue)
{
DataTable tierIDsTable = new DataTable("RecordIds");
tierIDsTable.Columns.Add(new DataColumn("Integer", typeof(Int32)));
tierIDsTable.PrimaryKey = new DataColumn[] { tierIDsTable.Columns["TierId"] };
foreach (int recordId in recordIds)
{
tierIDsTable.Rows.Add(recordId);
}
return true;
}
Not 100% sure, but have you tried this?
WCFService1.AJAXEnabledService.BatchUpdateRecords(
myarray1,
"ddsd",
"gggg",
updateGrid, OnError);
The issue (without knowing the error that you are receiving) is most likely that you are trying to pass in multiple parameters types. WCF does not usually support and expects an object instead. Create a response class with your parameters and use that instead.
public class ResponseObject
{
public List<int> recordIds { get; set; }
public string columnNameToUpdate { get; set; }
public string columnValue { get; set; }
}
Use this object as your parameter
public bool BatchUpdateRecords(ResponseObject responseObject)
{...

Categories