使用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>\r\n  <Recipe>\r\n    <ID>1</ID>\r\n    <Name>啤酒</Name>\r\n    <BranchNo>分店1</BranchNo>\r\n  </Recipe>\r\n  <Recipe>\r\n    <ID>2</ID>\r\n    <Name>紅酒</Name>\r\n    <BranchNo>分店1</BranchNo>\r\n  </Recipe>\r\n</NewDataSet>"

 

2、雖然String類型(XmlStr變量)可以作為參數直接傳給服務端了,但是由於字符串中包含:\r\n,以及/,因此傳輸的時候仍然會報錯。這里需要將這些特殊字符先替換掉,如:

String XmlStr = ds.GetXml().Replace("\r\n", "換行符").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("\r\n", "換行符").Replace("/", "~");
                return XmlStr;
            }
            catch (Exception ex)
            {
                return "";
            }
        }

 

3、服務端接收到XML格式的字符串之后,首先將被替換的特殊字符還原:

String xmlStr = xmlStr.Replace("換行符", "\r\n").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("換行符", "\r\n").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中添加一個元素,傳參時對這個新參數賦值,收到后再對新參數進行處理即可。接口函數及調用方法完全不用做任何改動。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM