5

For this question, I'm using ASP.NET Web Forms in C#, a web service and jQuery. I read this post about using an array to pass in a bunch of parameters to a web method using jQuery AJAX. I'm wondering if it's possible to do the same thing without using indices. The problem with indices is that order matters and making an update is a hassle since it involves updating the client-script and web method's arguments. I'm currently using named arguments, but this is very tedious. My largest web method has 20 arguments! Yuck! I'm looking for a shortcut here without having to care about order. Is this possible?

var obj = {};

// Iterate through each table row and add the editor field data to an object.
$('.addressRow').each(function ()
{
    var row = $(this);
    var addressField = row.find('.addressField');
    var attr = addressField.attr('addressFieldName');
    var val = addressField.val()
    obj[attr] = val;
});

$.ajax(
{
    type: 'POST',
    url: '/WebServices/AddressService.asmx/SaveAddress',
    data: JSON.stringify(obj),
    contentType: 'application/json; charset=utf-8',
    dataType: 'json',
    success: function (response)
    {
        alert('address saved');
    },
    error: function (response)
    {
        alert('error');
    }
});



[WebMethod]
public void SaveAddress(string streetAddress1, string streetAddress2, string apartmentNumber, string city, strng state, string zipCode, string country)
{
    // save address...
}

UPDATE:

Thanks to all who answered. Using your answers and some other Stack questions, I was finally able to piece together a working demo. I'm pasting my proof of concept code here so anyone stuck with the same problem can see how it's done.

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Web Service Demo</title>
    <style type="text/css">
        * { font-family: "Segoe UI"; font-size: 12px; color: #444444; }
        #result1 { padding: 10px 0px; }
    </style>
    <script type="text/javascript" src="Scripts/jquery.js"></script>
    <script type="text/javascript">
        $(document).ready(function ()
        {
            $('button').click(function ()
            {
                // NOTE: When using JavaScript objects, the properties MUST match the C# properties EXACTLY (casing and seplling).
                // I.e. in employee.FirstName, FirstName maps EXACTLY to the FirstName in the C# Employee object.

                // Create a employee object using the assigning to properties method.
                var employee1 = {};
                employee1.ID = 5416;
                employee1.FirstName = 'Fred';
                employee1.LastName = 'Baker';
                employee1.BirthDate = '07/18/1982';
                employee1.StreetAddress = '947 River Street';
                employee1.City = 'Somnerville';
                employee1.State = 'AR';
                employee1.ZipCode = '41370';

                // A property has the ability to be a list or complex type. In this example, employee1 uses a list of access codes and employee2 does not.
                employee1.AccessCodes = new Array();
                employee1.AccessCodes[0] = 512;
                employee1.AccessCodes[1] = 887;

                // Create a employee object using the associative array method.
                var employee2 =
                {
                    ID: 3316,
                    FirstName: 'Jason',
                    LastName: 'Masters',
                    BirthDate: '11/19/1980',
                    StreetAddress: '11 South Crane Avenue',
                    City: 'New York',
                    State: 'NY',
                    ZipCode: '01147'

                    // employee2 does no use any access codes. AccessCodes in the C# web method is a list and by excluding it from the JavaScript
                    // object, the C# code defaults the list to the null.
                };

                // In order to pass a complex JavaScript object to a web method as a complex type, the JavaScript object needs to be JSONified.
                // The name of the argument in the C# web method MUST be included here in single quotes EXACTLY (casing and spelling) the same way
                // the argument is specified in the C# code. In this example, the web method is "public string GetEmployeeData(Employee employee)". The
                // complex argument is 'employee'. IT IS VITALLY IMPORTANT that, when using the JSON.stringify() function, the name of the web method
                // argument is included here exactly the same way as specified in the C# code. I know I'm being redundant by repeating myself, but
                // it took me hours to figure out how to do this and the error message from doing this improperly is completely useless!

                var data1 = JSON.stringify({ 'employee': employee1 }); // 'employee' is the web method argument and employee1 is the JavaScript object from above.
                var data2 = JSON.stringify({ 'employee': employee2 }); // 'employee' is the web method argument and employee2 is the JavaScript object from above.

                // Send employee1 to the web method.
                $.ajax(
                {
                    type: 'POST',
                    url: '/WebServices/WebService1.asmx/GetEmployeeData',
                    data: data1,
                    contentType: 'application/json; charset=utf-8',
                    dataType: 'json',
                    success: function (response)
                    {
                        $('#result1').html(response.d);
                    },
                    error: function (response)
                    {
                        $('#result1').html('web service call failure\n' + response.responseText);
                    }
                });

                // Send employee2 to the web method.
                $.ajax(
                {
                    type: 'POST',
                    url: '/WebServices/WebService1.asmx/GetEmployeeData',
                    data: data2,
                    contentType: 'application/json; charset=utf-8',
                    dataType: 'json',
                    success: function (response)
                    {
                        $('#result2').html(response.d);
                    },
                    error: function (response)
                    {
                        $('#result2').html('web service call failure\n' + response.responseText);
                    }
                });
            });
        });
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <p>This demo shows how to pass a complex JSON object to a web method and get a reponse back from the web method.</p>
        <p>1) It creates two JavaScript objects.</p>
        <p>2) The JavaScript objects are JSONified and sent to the web method.</p>
        <p>3) The web method receives the complex objects and uses them to create response text.</p>
        <p>4) When the callback function fires, it displays the text returned from the web service.</p>
        <button type="button">Call Web Service</button>
        <div id="result1"></div>
        <div id="result2"></div>            
    </div>
    </form>
</body>
</html>

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ToolboxItem(false)]
[ScriptService]
public class WebService1 : WebService
{
    [WebMethod]
    public string GetEmployeeData(Employee employee)
    {
        var output = string.Format("Employee #{0}: {1} {2} lives at {3} in {4}, {5} with a zip code of {6} and was born on {7}.", employee.ID, employee.FirstName, employee.LastName, employee.StreetAddress, employee.City, employee.State, employee.ZipCode, employee.BirthDate.ToShortDateString());

        if (employee.AccessCodes != null)
        {
            output += string.Format(" Employee #{0} has access codes: ", employee.ID);

            foreach (var accessCode in employee.AccessCodes)
            {
                output += accessCode + " , ";
            }

            output = output.Substring(0, output.Length - 2);
        }
        else
        {
            output += string.Format(" Employee #{0} does not have any has access codes.", employee.ID);
        }

        return output; 
    }
}

public class Employee
{
    public int ID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime BirthDate { get; set; }
    public string StreetAddress { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string ZipCode { get; set; }
    public List<int> AccessCodes  {get;set;}
}
Community
  • 1
  • 1
Halcyon
  • 13,619
  • 17
  • 64
  • 91
  • 2
    If you just want to shorten the method signature, you can switch to using a custom type you define on the server. You can then create a matching JS object you can pass to the server. This won't decrease the work of having to maintain the object on the client and server, since you still have to update the object on the client and server. – Zachary Feb 09 '12 at 23:51

2 Answers2

2

NOTE: this example will not fully keep you from doing work, but you should only have to change a few places if something changes. Change the c# class and change the save method (and the layout perhaps).

Create an "address" class in c# with all the elements, create an array of addresses, then handle that list of addresses (single parameter) in the web method. My example is somewhat construed but should give you a starting place. I have not tested this fully but it should be close.

[WebMethod] 
public void SaveAddress(List<Address> Addresses) { 
// save em here
}

public class Address
{
    public Address()
    {
        streetAddress1 = streetAddress2 = apartmentNumber = city = state = zipCode = country = String.Empty;
    }
    public String streetAddress1 { get; set; }
    public String streetAddress2 { get; set; }
    public String apartmentNumber { get; set; }
    public String city { get; set; }
    public String state { get; set; }
    public String zipCode { get; set; }
    public String country { get; set; }
}

With this layout:

<div id='Address'>
    <input class='streetAddress1' type='text'>
    <input class='streetAddress2' type='text'>
    <input class='apartmentNumber' type='text'>
    <input class='city' type='text'>
    <input class='state' type='text'>
    <input class='zipCode' type='text'>
    <input class='country' type='text'>
</div>
<div id='Address'>
    <input class='streetAddress1' type='text'>
    <input class='streetAddress2' type='text'>
    <input class='apartmentNumber' type='text'>
    <input class='city' type='text'>
    <input class='state' type='text'>
    <input class='zipCode' type='text'>
    <input class='country' type='text'>
</div>
<button id='savedata'>SaveData</button>

Here is some client code to save:

function AddressRow(currentAddressRow) {
    this.streetAddress1 = currentAddressRow.find('.streetAddress1').val();
    this.streetAddress2 = currentAddressRow.find('.streetAddress2').val();
    this.apartmentNumber = currentAddressRow.find('.apartmentNumber').val();
    this.city = currentAddressRow.find('.city').val();
    this.state = currentAddressRow.find('.state').val();
    this.zipCode = currentAddressRow.find('.zipCode').val();
    this.country = currentAddressRow.find('.country').val();
}

function AddressRowSet() {
    var addressRows = [];
    var allAddressRows = $('.Address');
    var thisRow = null;
    var currentRowCount = allAddressRows.length;
    var i = 0;
    for (i = 0; i < currentRowCount; i++) {
        thisRow = allAddressRows.eq(i);
        addressRows.push(new AddressRow(thisRow));
    }
    this.AddressRows = addressRows;
}

function SaveCurrentAddresses() {
    var AddressRecords = new AddressRowSet();
    var AddressesData = {
        Addresses: AddressRecords.AddressRows
    };
    SaveAddressData(JSON.stringify(AddressesData));
}

function SaveAddressData(Addresses) {
    $.ajax({
        type: 'POST',
        data: Addresses,
        contentType: 'application/json',
        url: '/WebServices/AddressService.asmx/SaveAddress',
        dataType: 'json',
        success: function(response) {
            alert('address saved');
        },
        error: function(response) {
            alert('error');
        }
    });
}
$('#savedata').click(function() {
    SaveCurrentAddresses();
});
Mark Schultheiss
  • 28,892
  • 9
  • 63
  • 88
1

You don't need to use arrays - arrays are specifically for storing a list of related data - i.e. a list of countries or cars etc.

Use an anonymous json blob to define your parameters:

var obj = {
    param1: 'stringval1',
    param2: 100, // int value,
    param3: {
        childobjparam1: 'this is a child object in json',
        childobjparam2: true // boolean value
    }
};

Then you can just pass in the json object as follows:

$.ajax(
{
    type: 'POST',
    url: '/WebServices/AddressService.asmx/SaveAddress',
    data: obj,
    contentType: 'application/json; charset=utf-8',
    dataType: 'json',
    success: function (response)
    {
        alert('address saved');
    },
    error: function (response)
    {
        alert('error');
    }
});

JSON is lovely :)

Spikeh
  • 3,326
  • 2
  • 21
  • 49