tags:

views:

877

answers:

2

Guys, I can't seem to get the object serialization working correctly clientside for my app? When I used the getJSON() method inside jQuery with a response mime type of text/json (serialized using JSON.Net library), it was working fine, but as soon as I moved it across to an ajax() request (so I could post my code in webmethods on my page) its fallen apart. Any ideas would be greatly appreciated.

Edit: I'm using framework 2.0, not 3.5

My javascript looks like this:

 function companySearch(txt) 
 {
     $("#<%= divCompanyResult.ClientID %>").hide();
        $("#<%= divCompanyResult.ClientID %>").html("");

        var strCompanySearch = $("#<%= tbCompanySearch.ClientID %>").val();

        $.ajax
        ({
            type: "POST",
            url: "Home.aspx/GetCompanies", 
            contentType: "application/json; charset=utf-8", 
            datatype: "json",
            data: "{name: '" + strCompanySearch + "'} ", 
            success: companySearchSuccess,
            error: onError
        });

        return (true);
 }

 function companySearchSuccess(response)
 {
        $.each(response, 
            function(i, company) 
            {
                $("#<%= divCompanyResult.ClientID %>").prepend(company.Name + "<br />");
            });

        $("#<%= divCompanyResult.ClientID %>").slideDown(1000);
 }

And my .ASPX page (nb. its a page, not a webservice), looks like this:

    [WebMethod]
    public static Company[] GetCompanies(string name)
    {
        Company[] companies = Company.FindCompanies(name);

        return companies;
    }

And the object its returning:

[ActiveRecord]
public class Company : ActiveRecordBase<Company>
{
    private int iD;
    private string name;
    private string accountNo;
    private string streetAddr1;
    private string streetAddr2;
    private string streetSuburb;
    private string streetCity;
    private string postAddr1;
    private string postAddr2;
    private string postSuburb;
    private string postState;
    private string postPC;
    private string accountType;
    private string accountSubType;
    private string areaRep;
    private string status;
    private string overview;
    private string bpcsId;
    private string modifiedBy;
    private DateTime modifiedDate;
    private IList<Contact> contacts;

    [PrimaryKey]
    public int ID { get { return this.iD; } set { this.iD = value; } }
    [Property]
    public string Name { get { return this.name; } set { this.name = value; } }
    [Property]
    public string AccountNo { get { return this.accountNo; } set { this.accountNo = value; } }
    [Property]
    public string StreetAddr1 { get { return this.streetAddr1; } set { this.streetAddr1 = value; } }
    [Property]
    public string StreetAddr2 { get { return this.streetAddr2; } set { this.streetAddr2 = value; } }
    [Property]
    public string StreetSuburb { get { return this.streetSuburb; } set { this.streetSuburb = value; } }
    [Property]
    public string StreetState { get { return this.streetCity; } set { this.streetCity = value; } }
    [Property]
    public string StreetPC { get { return this.streetCity; } set { this.streetCity = value; } }
    [Property]
    public string PostAddr1 { get { return this.postAddr1; } set { this.postAddr1 = value; } }
    [Property]
    public string PostAddr2 { get { return this.postAddr2; } set { this.postAddr2 = value; } }
    [Property]
    public string PostSuburb { get { return this.postSuburb; } set { this.postSuburb = value; } }
    [Property]
    public string PostState { get { return this.postState; } set { this.postState = value; } }
    [Property]
    public string PostPC { get { return this.postPC; } set { this.postPC = value; } }
    [Property]
    public string AccountType { get { return this.accountType; } set { this.accountType = value; } }
    [Property]
    public string AccountSubType { get { return this.accountSubType; } set { this.accountSubType = value; } }
    [Property]
    public string AreaRep { get { return this.areaRep; } set { this.areaRep = value; } }
    [Property]
    public string Status { get { return this.status; } set { this.status = value; } }
    [Property]
    public string Overview { get { return this.overview; } set { this.overview = value; } }
    [Property]
    public string BPCSId { get { return this.bpcsId; } set { this.bpcsId = value; } }
    [Property]
    public string ModifiedBy { get { return this.modifiedBy; } set { this.modifiedBy = value; } }
    [Property]
    public DateTime ModifiedDate { get { return this.modifiedDate; } set { this.modifiedDate = value; } }

    // Inverse ensures is read-only ie. Contact controls the relationship
    // Castle will usually infer relationship, but we explicitly set just to be on the safe side
    [HasMany(Inverse=true, Table="Contact", ColumnKey="CompanyId")] 
    [ScriptIgnore]
    public IList<Contact> Contacts { get { return this.contacts; } set { this.contacts = value; } }

    protected Company() { }

    public Company(string Name, string StreetAddr1)
    {
        this.Name = Name;
        this.StreetAddr1 = StreetAddr1;

        ModifiedBy = "Test";
        ModifiedDate = DateTime.Now;
    }

    public static Company[] FindCompanies(string name)
    {
        return FindAll(Expression.InsensitiveLike("Name", "%" + name + "%"));
    } 
}
+1  A: 

Microsoft's WebMethods encode the return data inside of an object named 'd'. So, you need to change your code to look like this:

function companySearchSuccess(response)
{
  // Get encoded data
  response = response.d; // you could rename this, or just change the variable reference

}

This is done to prevent a special kind of javascript exploit. You can see more details here and here.

Travis
Ah, the dreaded "d". Very questionable security "feature" if you ask me... anyway, "response = response.d || response;" would be more appropriate, as earlier versions of ASP.NET don't use the "d" wrapper.
Tsvetomir Tsonev
Unfortunately I'm using framework 2.0, so this isn't the solution. I have checked the response with Firebug and the string isn't wrapped into a "d" object...
jacko
@Tsvetomir: good addition. But yeah, that 'feature' makes webmethods pretty incompatible with other frameworks, which can be a real pain.
Travis
+2  A: 

Turns out I had overlooked the camel casing for the dataType property on my ajax request

Old:

    $.ajax
    ({
        type: "POST",
        url: "Home.aspx/GetCompanies", 
        contentType: "application/json; charset=utf-8", 
        datatype: "json",
        data: "{name: '" + strCompanySearch + "'} ", 
        success: companySearchSuccess,
        error: onError
    });

Solution

    $.ajax
    ({
        type: "POST",
        url: "Home.aspx/GetCompanies", 
        contentType: "application/json; charset=utf-8", 
        dataType: "json",
        data: "{name: '" + strCompanySearch + "'} ", 
        success: companySearchSuccess,
        error: onError
    });

Hope this helps others avoid the hours of searching google, tutorials and blogs that I suffered... Doh!

jacko
Heh, I just spent 30 mins tearing my hair out trying to work out why my script couldn't read my object.....and it was exactly this mistake! :( Bloomin' case sensitive languages.
Nick