5

Here's my situation: I have a UserBadge object in ASP.NET, it contains 3 fields, being a User object, a Badge object and a boolean (isNotified) to check if the user has been notified of earning a badge. I'm having issues sending a specific UserBadge from this WebMethod():

[WebMethod()]
    public static UserBadge Notify()
    {
        var db = new achievDb();

        foreach (var uB in db.UserBadges)
        {
            if (System.Web.HttpContext.Current.User.Identity.Name == uB.User.UserName)
            {
                if (!uB.isNotified)
                {
                    return uB;
                }
            }
        }
        return null;
    }

to my $.ajax:

<script type="text/javascript">
            $(document).ready(function () {
                $.ajax({
                    type: "POST",
                    url: "../NotifCodeBehind.aspx/Notify",
                    data: "{}",
                    complete: function (result) {
                        if (result) {
                            $("#notify").jGrowl("You've unlocked a badge!", { header: 'Yay', close: function () {
                                $.ajax({
                                    type: "POST",
                                    url: "../NotifCodeBehind.aspx/Notified",
                                    data: "{}",
                                    success: function (ub) { DoCallback(JSON.stringify(ub)); },
                                    error: function () { DoCallback("NOPE!") }
                                });
                            }
                            })

                        };
                        function DoCallback(msg) {
                            alert(msg);
                        }
                    }
                })
            })
        </script>

and then back to another WebMethod() that sets the isNotified boolean to true once the notification is closed:

    [WebMethod()]
    public static void Notified(UserBadge ub)
    {
        var db = new achievDb();

            foreach (var userbadge in db.UserBadges)
            {
                if (userbadge.UserId == ub.UserId && userbadge.BadgeId == ub.UserId)
                {
                    userbadge.isNotified = true;
                    db.SaveChanges();
                }
        }
    }

The Problem: I have absolutely no idea how to actually pass the object to the ajax, and then back again... I've spent about 1,5 days browsing the internet about it, but now, I've decided to come for help. The more I read about it, the more it confuses me, and I'm an absolute newbie to jQuery/Ajax/JSON.

So if you could keep it as simple as possible, and nudge me in the right direction, it would be most appreciated!

EDIT: New JavaScript below, thought I had it, but I didn't.

EDIT2: This is now solved, I ended up using a controller instead of WebMethods.

Zachary Schuessler
  • 3,644
  • 2
  • 28
  • 43
mktwo
  • 63
  • 1
  • 6

3 Answers3

5

You want to work with JSON serialization. When you return the result to your ajax callback method, your web method can return result in form of XML, JSON or string. If you return a JSON, your complex object will be converted to a json object in a very straight forward manner.

Assuming your class structure

class UserBadge
{
    User UserProperty { get; set; }
    Badge BadgeProperty { get; set; }
    bool IsNotified { get; set; }
}

class User
{
    string Username { get; set; }
}

Your json object in javascript from the result callback function will look like

{ 
  UserProperty: { Username: "some username" },
  BadgeProperty: { /**********/ },
  IsNotified: true 
}

As you can see, your JSON structure is the same as your class object structure. So, calling result.UserProperty.Username in javascript is perfectly ok. Constructing the same object and passing it to another ajax web service will transform the JSON object to the managed class objects.

Edit: You can add the ScriptMethodAttribute to your WebMethod to specify JSON response.

[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public static UserBadge Notify()
{
}
Tomislav Markovski
  • 12,331
  • 7
  • 50
  • 72
  • I think I can follow so far, but I really don't get how JSON serialization works, I'm guessing I use `[Serializable]` for the class with the `WebMethod`s? – mktwo Jan 16 '12 at 14:32
  • Simply return the object and ASP.NET will convert it for you. Here's an example how to send JSON back to a web method. http://stackoverflow.com/questions/1527422/send-json-to-webmethod – Tomislav Markovski Jan 16 '12 at 14:40
  • See my Edit for `ScriptMethod` attribute to control response type. – Tomislav Markovski Jan 16 '12 at 14:43
1

Do you really want to pass the object to your web method ? Why not pass the ids ( UserId, badgeId etc ) and Build the object in your ajax server page using those Id's if needed. You can pass the Id as the query string values.

var userId=4 // read from some hidden items or somewhere
var badgeid=3 // read from somewhere
$.ajax({
        type: "POST",
        url: "../NotifCodeBehind.aspx/Notify?uid="+userId+"&bid="+badgeId,
        data: "{}",
        complete: function (result) {

       // rest of the code

EDIT : From the Comment, its clear that it is an ASP.NET MVC App

Since it is an ASP.NET MVC application, You can do model binding. You can serialize your form and send that to the controller action via jquery post.

If your page is having a "LogOnMOdel" and you want to do this binding for the UserBadge object as well, you need to create another ViewModel which has 2 properties , one is LogonModel and another is UserBadge. then pass that view model to your page.

Shyju
  • 214,206
  • 104
  • 411
  • 497
  • Well, that's the thing, I thought about that, but I'm not sure I can read those Ids from anywhere on that page. It's my _Layout.cshtml so I can't pass it a different model to be able to get to those Ids. – mktwo Jan 16 '12 at 14:20
  • Is this ASP.NET MVC ? Then you should be able to do Model Binding for ajax requests – Shyju Jan 16 '12 at 14:23
  • Yes, this is MVC3, but with 'Model Binding for ajax requests', do you mean I can bind a model NOT to the entire page, but to just the ajax bits? Because binding the needed model to the page is not really usable for me, because the page expects a `LogOnModel`. – mktwo Jan 16 '12 at 14:33
  • I've made a ViewModel, but how do I pass the LogOnModel to the page? – mktwo Jan 16 '12 at 15:02
  • Clarification: How do I pass the LogOnModel from the ViewModel to only the @Html.Partial("_LogonPartial")? I've tried to just make it @Html.Partial("_LogonPartial", Model.LogOnModel) but when I load up the page it says that the reference's not set to an instance of an object.. – mktwo Jan 16 '12 at 15:14
  • @Html.Partial("_LogonPartial", Model.LogOnModel) is the way to do that. I think your LogonModel Property is null. Initialize it please ( may be in the constructor or your new ViewModel) – Shyju Jan 16 '12 at 15:19
  • Okay, it's somewhat working, some pages load correctly, but others that are strongly typed or already had a model assigned, give me an error: `The model item passed into the dictionary is of type 'System.Collections.Generic.List1[achiev.li.Models.UserBadge]', but this dictionary requires a model item of type 'achiev.li.ViewModels.NotifyViewModel'.` – mktwo Jan 16 '12 at 15:30
  • Wherever you access those, instead of OldModelName.SomeProperty, use now like, NewViewModelName.OldModelName.SomePropery – Shyju Jan 16 '12 at 15:59
0

Well, finally figured it out with a little help from my brother and some good old fashioned exercise! I solved the issue by using a controller instead of a code-behind with WebMethods.

mktwo
  • 63
  • 1
  • 6