• 使用WCF传输DataTable:DataTable和Xml格式的字符串相互转换(C#)


    背景:项目中要用到客户端向服务端传数据,使用WCF,绑定webHttpBinding,做了一个小例子。

    业务逻辑简介:客户端在a表中添加了几条数据,从SQL Server数据库直接取出新添加的数据(DataTable格式的数据),传递给服务端,服务端有着和客户端相同的数据库结构,将收到的数据也同样添加到自己的a表中。除了添加数据,还有可能进行修改、删除等,并且有几十张表都会依次进行上述操作。客户端的任何变动都需要传给服务端,服务端做相同的变动。

    由于客户端是从SQL直接取出的DataTable格式的数据,传递给服务端时,DataTable无法作为参数类型,运行会报错(这里是指使用在[WebInvoke]方法中时)。因此想到将DataTable转换成String类型再进行传输。为了保证服务端在收到字符串后能够再成功转换成DataTable,使用了XML格式的String。查阅了很多资料,网上很多例子都是先生成XML格式的文件,再把文件序列化后进行传输,感觉很麻烦。最终找到了一个解决方案,大致步骤如下:

    1、在客户端将取到的DataTable数据加入一个DataSet中,DataSet有一个GetXml方法,可以直接转换成XML格式的字符串。

    DataSet ds = new DataSet();
    ds.Tables.Add(dtData);
    
    //将数据转换为xml格式
    String XmlStr = ds.GetXml();

    其中dtData就是获取到的DataTable格式的数据,内容如下:ID     Name      BranchNo

                                                                                 1       啤酒        分店1

                                                                                 2       红酒        分店1

    转换成的XML字符串的内容为:

    <NewDataSet>
      <Recipe>
        <ID>1</ID>
        <Name>啤酒</Name>
        <BranchNo>分店1</BranchNo>
      </Recipe>
      <Recipe>
        <ID>2</ID>
        <Name>红酒</Name>
        <BranchNo>分店1</BranchNo>
      </Recipe>
    </NewDataSet>

    表示为String类型后,XmlStr变量的内容为:"<NewDataSet>   <Recipe>     <ID>1</ID>     <Name>啤酒</Name>     <BranchNo>分店1</BranchNo>   </Recipe>   <Recipe>     <ID>2</ID>     <Name>红酒</Name>     <BranchNo>分店1</BranchNo>   </Recipe> </NewDataSet>"

    2、虽然String类型(XmlStr变量)可以作为参数直接传给服务端了,但是由于字符串中包含: ,以及/,因此传输的时候仍然会报错。这里需要将这些特殊字符先替换掉,如:

    String XmlStr = ds.GetXml().Replace("
    ", "换行符").Replace("/", "~");

    然后再进行传输就可以了。

    因此,将DataTable转换成XML格式字符串的完整方法为:

            /// <summary>
            /// 将DataTable转换成XML格式的字符串
             /// </summary>
            /// <param name="dtData">DataTable</param>
            /// <returns>返回:XML格式的字符串</returns>
            public String DataTableToXmlStr(DataTable dtData)
            {
                try
                {
                    DataSet ds = new DataSet();
                    ds.Tables.Add(dtData);
    
                    //将数据转换为xml格式
                       String XmlStr = ds.GetXml().Replace("
    ", "换行符").Replace("/", "~");
                    return XmlStr;
                }
                catch (Exception ex)
                {
                    return "";
                }
            }

    3、服务端接收到XML格式的字符串之后,首先将被替换的特殊字符还原:

    String xmlStr = xmlStr.Replace("换行符", "
    ").Replace("~", "/");

    4、最后将XML格式的字符串再还原为DataTable格式的数据,以便对数据库进行操作。需要添加对System.Xml的引用。

    将XML格式的字符串转化为DataTable的完整方法如下所示:

             /// <summary>
            /// 将XML格式的字符串转化为DataTable
            /// </summary>
            /// <param name="xmlStr">XML格式的字符串</param>
            /// <returns>返回:DataTable</returns>
            public DataTable XmlStrToData(String xmlStr)
            {
                XmlTextReader reader = null;
                try
                {
                    xmlStr = xmlStr.Replace("换行符", "
    ").Replace("~", "/");
                    DataSet xmlds = new DataSet();
                    StringReader stream = new StringReader(xmlStr);
                    reader = new XmlTextReader(stream);
                    xmlds.ReadXml(reader);
    
                    if (reader != null)
                    {
                        reader.Close();
                    }
    
                    return xmlds.Tables[0]; 
                }
                catch (Exception ex)
                {
                    if (reader != null)
                    {
                        reader.Close();
                    }
                    return null;
                }
            }

     5、我的例子中,服务端的接口函数如下:

            /// <summary>
            /// 分店向总店上传酒水数据
             /// </summary>
            /// <param name="recipeXml"></param>
            /// <returns></returns>
            [OperationContract(Name = "BranchRecipeXml")]
            [WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Xml, ResponseFormat = WebMessageFormat.Xml, UriTemplate = "BranchRecipeXml/{recipeXml}", BodyStyle = WebMessageBodyStyle.Bare)]
            String BranchRecipe(String recipeXml);


    客户端通过调用这个方法,将DataTable格式的数据转换为XML格式的字符串,通过recipeXml参数传递给服务端,并接收返回值(String类型,表示操作是否成功)。

    PS:客户端和服务端的具体例子就不直接给出了,不是本文要表达的重点。

    补充:还有一种比较简单的实现方式,是刚刚才试验出来的:

    1、客户端,将DataTable格式的数据(dt)写入Stream:

                                            System.IO.MemoryStream xmlStream = new System.IO.MemoryStream();
    dt.WriteXml(xmlStream, XmlWriteMode.WriteSchema); xmlStream.Position
    = 0;

    2、将Stream作为参数传递给服务端,服务端接口如下:

            /// <summary>
            /// 分店向总店上传酒水数据
             /// </summary>
            /// <param name="recipeStr"></param>
            /// <returns></returns>
            [OperationContract(Name = "BranchRecipeStr")]
            [WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Xml, ResponseFormat = WebMessageFormat.Xml, UriTemplate = "BranchRecipeStr", BodyStyle = WebMessageBodyStyle.Bare)]
            String BranchRecipeStr(Stream recipeStr);

    3、服务端接收到Stream后,再转换成DataTable:

                DataTable dt = new DataTable();
                dt.ReadXml(recipeStr);

    这里recipeStr就是客户端传过来的Stream recipeStr。

    11.21补充:

    刚刚又试验出一种更好的方法。。。是在做的过程中无意间想到的,试了一下,居然可以—_—

    因为[WebInvoke]方法的参数可以是类的。。。那把表结构做成类的形式太麻烦了的话,是不是可以把表作为这个类中的一个元素呢?

    (1)做一个Model:

    public class MainBranchModel
        {
            public DataTable dtData = new DataTable();
        }

    (2)服务端接口,将这个Model作为参数类型:

            /// <summary>
            /// 分店向总店上传酒水数据
             /// </summary>
            /// <param name="recipeStr"></param>
            /// <returns></returns>
            [OperationContract(Name = "BranchRecipeModel")]
            [WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Xml, ResponseFormat = WebMessageFormat.Xml, UriTemplate = "BranchRecipeModel", BodyStyle = WebMessageBodyStyle.Bare)]
            String BranchRecipeStr(MainBranchModel recipeStr);

    (3)客户端上传数据:

    MainBranchModel recipeStr = new MainBranchModel();
    recipeStr.dtData = dt.Copy();//dt就是客户端获取到的数据
    
    //调用服务端函数:向总店发送数据
    //将recipeStr作为参数传过去,服务端接收到后就可以直接用了。。。

    用Model作为参数的好处,是当参数个数发生变化后,不需要修改接口函数。如在Model中添加一个元素,传参时对这个新参数赋值,收到后再对新参数进行处理即可。接口函数及调用方法完全不用做任何改动。

  • 相关阅读:
    【原】webpack--loaders,主要解释为什么需要loaders和注意事项
    【原】通过npm script运行webpack的原理
    原生js深拷贝函数
    git add 添加错文件的撤销方法
    item2 快捷键
    sudo su 和sudo -s的区别
    nvm常用命令
    【雅思】【口语】Describe a product you bought and felt happy
    【雅思】【口语】Help others
    【雅思】【口语】
  • 原文地址:https://www.cnblogs.com/xuxiaona/p/3425774.html
Copyright © 2020-2023  润新知