【问题标题】:Pass widget data using json and saving to database使用 json 传递小部件数据并保存到数据库
【发布时间】:2014-12-16 07:00:07
【问题描述】:

我刚刚再次回到这个要求,因为当时我被拉出来去做更重要的要求。

我问了一个类似的问题here,答案很有帮助。但是,在那个问题中,我传递了测试数据并将其保存到数据库中。但是,我无法弄清楚如何保存实际的小部件信息。该链接帮助我成功传递了 json。

我在尝试保存数据时收到此消息。

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.");
            }
        });

处理程序

   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;
        }
    }

小部件数据类

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; }
    }
}

我想我需要将 json 保存到一个列表中,然后将每个小部件信息插入/更新到数据库中。但是,当我尝试这个时,我收到了上面的错误。我显然错过了一些东西,但我不确定它是什么。此错误发生在我的处理程序中,但 SaveWidgetsDAL 中的列表为空,导致 NullReference。我不确定我错过了什么或不确定从这里去哪里。非常感谢任何帮助!

编辑 1:

我已经改变了我的数据库以及我的 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; }
    }
}

处理程序(只是 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();
     }
 }

但是,我现在在插入数据库时​​收到此错误。

我可以看到我的 foreach 计数为 11,但 Collapsed、SortNo、ColumnId、Title 对于每个项目都是空的。

【问题讨论】:

  • 您是否验证了 JQuery 正在传递数据?
  • 我相信是的。当我使用测试数据时,它能够通过。验证它是否正在传递数据的最佳方法是什么?
  • 使用提琴手。发送时检查您的 AJAX 请求。它应该包含您的 JSON 数据。
  • 啊,我想我做不到。函数 UpdateWidget() 在小部件的放置上执行,并假设获取小部件的
    的 ID。
  • 试试 console.log(response.innerHtml) 或类似的东西。这将在浏览器的 DevTools - Console 选项卡中显示您的 AJAX 数据。

标签: c# jquery asp.net sql-server json


【解决方案1】:

问题似乎是您的 c# 数据合同中指定的 data member names 与您生成的 JSON 中的 JSON 属性名称不匹配。您的 JavaScript 代码生成的 JSON 看起来像

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

但是这些属性名称不是您的 c# 类中的属性名称,并且您没有覆盖这些名称。请尝试以下方法:

[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; }
    }
}

我能够推断出 collapsed: collapsedcolumn: columnId 的正确 c# 数据成员名称,但是我无法弄清楚如何映射其余部分,因为它们似乎不匹配 1-1。您需要进一步修复 data member names 以使它们完全匹配。

更新2

在您更新的问题中,您省略了嵌套 Widgets 类上的 [DataContract] 属性:

    // [DataContract] missing
    public class Widgets
    {

您需要确保外部类和嵌套类都具有此属性。

更新

这是创建 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);

因此,items 数组中的每个 object item 仅包含这四个命名属性:

  • id
  • collapsed
  • order
  • column

您在var item = { id: value1, collapsed: value2, ...}; 语句中使用的属性名称是JSON.stringify() 写入json 字符串的名称。在您的 c# 代码中指定的数据成员名称​​必须与这些名称完全匹配,以便使用 DataContractJsonSerializer 反序列化它们。因此,以下 c# 类将反序列化这四个命名属性:

[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; }
    }
}

如果您需要传输其他属性,则需要在您的var item 语句中添加它们,然后在您的Widgets 类中添加具有相同数据成员名称的属性。要确认您已正确匹配名称,您可以使用 Visual Studio 调试您的 ProcessRequest() 方法并手动检查您的 json 字符串,或通过以下方式检查您的 debug log json 字符串:

    System.Diagnostics.Debug.WriteLine(json);

这将允许您查看 JSON 并确保您的数据成员名称与您的 JSON 属性名称匹配。

【讨论】:

  • 这绝对有帮助。现在在我的 foreach 循环中,我可以看到 data.wdata 的计数,它显示 11(我有 11 个小部件,所以这是有希望的)但是当我展开折叠时,sortno、columnId 和 title 全部为空其中。我会用我目前的情况更新我的问题。
  • @Humpy - 您省略了 [DataContract] 属性之一。
  • 啊,我是菜鸟。又是一次好收获。现在我只需要清理列名 (FeaturedContent_Column1) 和小部件 ID...感谢所有帮助!
  • 我还有一个问题要问你。既然您知道如何成功地做到这一点,您是否知道如何调用保存的数据来持久化每个用户的小部件?我能够使用正确的 UserId 保存每个小部件,现在我回到了这个仪表板并试图让它持续存在。我在this new question 上创建了一个赏金,我也问过。
猜你喜欢
相关资源
最近更新 更多
热门标签