1

I have just come back to this requirement again as I was pulled away from it to do more important requirements at the time.

I have asked a similar question here and the answer has helped. However, in that question, I was passing test data and saving it to the database. I'm unable to figure out how to save the actual widget information however. The link helped me with passing the json successfully.

I receive this message when trying to save the data. enter image description here

jQuery

    function updateWidgetData() {
        var items = [];
        $('.column').each(function () {
            var columnId = $(this).attr('id');
            $('.dragbox', this).each(function (i) {
                var collapsed = 0;
                if ($(this).find('.dragbox-content').css('display') == "none")
                    collapsed = 1;
                //Create Item object for current panel  
                var item = {
                    id: $(this).attr('id'),
                    collapsed: collapsed,
                    order: i,
                    column: columnId
                };
                //Push item object into items array  
                items.push(item);
            });
        });
        //Assign items array to sortorder JSON variable  
        var sortorder = { items: items };

        $.ajax({
            url: "/Handlers/SaveWidgets.ashx",
            type: "POST",
            contentType: "application/json; charset=uft-8",
            dataType: "json",
            data: JSON.stringify(sortorder),
            success: function (response) {
                alert("Passed json");
            },
            error: function (error) {
                alert("Failed passing json.");
            }
        });

Handler

   public void ProcessRequest(HttpContext context)
    {
        String json = String.Empty;
        // you have sent JSON to the server
        // read it into a string via the input stream
        using (StreamReader rd = new StreamReader(context.Request.InputStream))
        {
            json = rd.ReadToEnd();
        }

        // create an instance of YourDataModel from the
        // json sent to this handler
        SaveWidgetsDAL data = null;
        DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(SaveWidgetsDAL));
        using (MemoryStream ms = new MemoryStream())
        {
            byte[] utf8Bytes = Encoding.UTF8.GetBytes(json);
            ms.Write(utf8Bytes, 0, utf8Bytes.Length);
            ms.Position = 0;
            data = serializer.ReadObject(ms) as SaveWidgetsDAL;
        }
        // update the DB and
        // send back a JSON response
        int rowsUpdated = 0;

        foreach (var item in data.wdata)
        {
            using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["dboCao"].ConnectionString))
            {
                conn.Open();

                using (SqlCommand cmd = new SqlCommand("UPDATE tWidgetControl SET SortNo = @SortNo, ColumnId = @ColumnId, Collapsed = @Collapsed "
                    + "WHERE UserId = @UserId AND WidgetId = @WidgetId;", conn))
                {
                    cmd.Parameters.AddWithValue("@SortNo", item.SortNo);
                    cmd.Parameters.AddWithValue("@ColumnId", item.ColumnId);
                    cmd.Parameters.AddWithValue("@Collapsed", item.Collapsed);
                    cmd.Parameters.AddWithValue("@UserId", "2");
                    cmd.Parameters.AddWithValue("@WidgetId", item.WidgetId);
                    rowsUpdated = cmd.ExecuteNonQuery();
                }
                conn.Close();
            }
        }

        context.Response.ContentType = "application/json";
        context.Response.Write("{ \"rows_updated\": " + rowsUpdated + " }");
    }

    public bool IsReusable
    {
        get
        {
            return false;
        }
    }

Widgets Data Class

public class SaveWidgetsDAL
{
    public List<Widgets> wdata { get; set; }

    public SaveWidgetsDAL() { }

    public class Widgets
    {
        [DataMember]
        public string SortNo { get; set; }

        [DataMember]
        public string ColumnId { get; set; }

        [DataMember]
        public string Collapsed { get; set; }

        [DataMember]
        public string Title { get; set; }

        [DataMember]
        public string UserId { get; set; }

        [DataMember]
        public string WidgetId { get; set; }
    }
}

I would imagine that I would need to save the json into a list and then insert/update each widget information into the database. However, I receive the error above when I try this. I'm clearly missing something, but I am not sure what it is. This error occurs in my handler, but the list in the SaveWidgetsDAL is empty, causing the NullReference. I am not sure what I am missing or sure where to go from here. Any help is greatly appreciated!

EDIT 1:

I have changed my database around a bit along with my SaveWidgetsDAL.

SaveWidgetsDAL

[DataContract]
public class SaveWidgetsDAL
{
    [DataMember(Name = "items")]
    public List<Widgets> wdata { get; set; }

    public SaveWidgetsDAL() { }

    public class Widgets
    {
        [DataMember(Name = "order")]
        public string SortNo { get; set; }

        [DataMember(Name = "column")]
        public string ColumnId { get; set; }

        [DataMember(Name = "collapsed")]
        public string Collapsed { get; set; }

        [DataMember(Name = "id")]
        public string Title { get; set; }
    }
}

Handler (just the foreach)

foreach (var item in data.wdata)
{
    using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["dboCao"].ConnectionString))
    {
        conn.Open();

        using (SqlCommand cmd = new SqlCommand("UPDATE tWidgetTest SET Title = @Title, SortNo = @SortNo, ColumnId = @ColumnId, Collapsed = @Collapsed "
                    + "WHERE UserId = @UserId AND Title = @Title;", conn))
         {
             cmd.Parameters.AddWithValue("@Title", item.Title);
             cmd.Parameters.AddWithValue("@SortNo", item.SortNo);
             cmd.Parameters.AddWithValue("@ColumnId", item.ColumnId);
             cmd.Parameters.AddWithValue("@Collapsed", item.Collapsed);
             cmd.Parameters.AddWithValue("@UserId", "2");
             rowsUpdated = cmd.ExecuteNonQuery();
          }
         conn.Close();
     }
 }

However, I now get this error when inserting into the database. enter image description here

I'm able to see that my foreach count is 11, but the Collapsed, SortNo, ColumnId, Title are all null for each item.

Community
  • 1
  • 1
Humpy
  • 2,004
  • 2
  • 22
  • 45
  • Did you verify the JQuery is passing the data? – snowYetis Dec 15 '14 at 17:45
  • I believe that it is. When I used the Test data, it was able to be passed. What's the best way to verify that it is passing the data? – Humpy Dec 15 '14 at 17:51
  • Use fiddler. Inspect your AJAX request when it is sent. It should have your JSON data inside of it. – snowYetis Dec 15 '14 at 17:54
  • ah, I don't think I'll be able to. The function UpdateWidget() executes on the drop of the widget and is suppose to get the ID of the
    of the widgets.
    – Humpy Dec 15 '14 at 18:18
  • try console.log(response.innerHtml) or something like that. That will show you your AJAX data in a browser's DevTools - Console tab. – snowYetis Dec 15 '14 at 19:40

1 Answers1

1

The problem seems to be that the data member names specified in your c# data contract do not match the JSON property names in the JSON you are generating. Your JavaScript code generates JSON that looks like

{"items":[{"id":"1","collapsed":"False","order":"1","column":"1"}]}

But these property names are not the property names in your c# classes, and you have not overridden those names. Try something like the following instead:

[DataContract]
public class SaveWidgetsDAL
{
    [DataMember(Name="items")]
    public List<Widgets> wdata { get; set; }

    public SaveWidgetsDAL() { }

    [DataContract]
    public class Widgets
    {
        // I was able to figure out which JSON properties to which to map these properties.
        [DataMember(Name = "column")]
        public string ColumnId { get; set; }

        [DataMember(Name = "collapsed")]
        public string Collapsed { get; set; }


        // However it is unclear how to map these to your JSON.  
        [DataMember(Name = "sortno")]
        public string SortNo { get; set; }

        [DataMember(Name = "title")]
        public string Title { get; set; }

        [DataMember(Name = "userid")]
        public string UserId { get; set; }

        [DataMember(Name = "widgetid")]
        public string WidgetId { get; set; }
    }
}

I was able to deduce the correct c# data member names for collapsed: collapsed and column: columnId, however I could not figure out how to map the rest since they don't seem to match up 1-1. You will need to further fix the data member names to make them match exactly.

Update2

In your updated question, you omitted the [DataContract] attribute on the nested Widgets class:

    // [DataContract] missing
    public class Widgets
    {

You need to make sure both the outer and nested classes have this attribute.

Update

This is the part of your code that creates your JSON:

            var collapsed = 0;
            if ($(this).find('.dragbox-content').css('display') == "none")
                collapsed = 1;
            //Create Item object for current panel  
            var item = {
                id: $(this).attr('id'),
                collapsed: collapsed,
                order: i,
                column: columnId
            };
            //Push item object into items array  
            items.push(item);

        var json = JSON.stringify(sortorder);

Thus each object item in your items array contains just these four named properties:

  • id
  • collapsed
  • order
  • column

The property names you use in your var item = { id: value1, collapsed: value2, ...}; statement are the names that JSON.stringify() writes into the json string. The data member names specified in your c# code must match these names exactly in order to deserialize them with DataContractJsonSerializer. Thus the following c# classes will deserialize those four named properties:

[DataContract]
public class SaveWidgetsDAL
{
    [DataMember(Name = "items")]
    public List<Widgets> wdata { get; set; }

    public SaveWidgetsDAL() { }

    [DataContract]
    public class Widgets
    {
        // I was able to figure out which JSON properties to which to map these properties.
        [DataMember(Name = "id")]
        public string Id { get; set; }

        [DataMember(Name = "collapsed")]
        public string Collapsed { get; set; }

        [DataMember(Name = "order")]
        public string Order { get; set; }

        [DataMember(Name = "column")]
        public string ColumnId { get; set; }
    }
}

If you need to transfer additional properties, you need to add them in your var item statement, then add properties with the identical data member name in your Widgets class. To confirm you have correctly matched the names, you can either debug your ProcessRequest() method with Visual Studio and manually examine your json string, or debug log your json string via:

    System.Diagnostics.Debug.WriteLine(json);

That will allow you to see the JSON and ensure that your data member names match your JSON property names.

dbc
  • 104,963
  • 20
  • 228
  • 340
  • This has definitely helped. Within my foreach loop now, I'm able to see the count from data.wdata, which shows 11 (I have 11 widgets, so this is promising) but when I expand collapsed, sortno, columnId and title are all null, for all of them. I will update my question with what I have currently. – Humpy Dec 15 '14 at 21:11
  • @Humpy - you omitted one of the `[DataContract]` attributes. – dbc Dec 15 '14 at 22:44
  • 1
    ah, I'm a noob. Good catch again. Now I just need to clean up the column names (FeaturedContent_Column1) and widget id's... Thanks for all the help! – Humpy Dec 16 '14 at 13:35
  • I have another question for you. Since you knew how to do this successfully, do you know how to call the data that is saved back to persist the widgets per user? I was able to save each widget with the correct UserId, now I'm back at this dashboard and trying to get it to persist. I created a bounty on [this new question](http://stackoverflow.com/questions/27513832/call-back-jquery-widget-information-from-database-and-display-widgets-in-proper) I asked as well. – Humpy Dec 22 '14 at 18:01