天天看點

WEB API傳回的字元串清單

參考網址:https://www.cnblogs.com/yuanmo/p/10045467.html

開發工具:vs2015

語言:C# ASP.NET 5

第一次弄asp.net mvc,太難了,一堆問題

我的程式結構:web api->mvc5背景,即mvc5背景通路web api,擷取到資料之後,顯示到前端的頁面上

web api接口代碼如下:

public List<string> GetLocalDirs()
{
    List<string> retList = GetGoodDirs();
    if (retList.Count() == 0)
        retList.Add("-1:搜尋目錄失敗");
    return retList;
}
           

這個接口傳回的是一個字元串清單,如果沒有搜尋到目錄,就一條資料:-1:搜尋目錄失敗。在請求它的mvc5背景代碼參考網上的内容,也很簡單:

public ActionResult SearchDir()
{
    WebClient webClient = new WebClient();
    string remoteDirList = webClient.DownloadString(strRemoteUrl);
    DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(List<string>));
    MemoryStream ms = new MemoryStream(Encoding.Default.GetBytes(remoteDirList));
    List<string> listTmp = (List<string>)ser.ReadObject(ms);
    
    DirFindViewModel model = new DirFindViewModel();
    model.dirList = listTmp;
    return PartialView(model);
}
           

這個action是由js在頁面後面請求。收到web api的傳回内容後,反序列化為List<string>結構。通過調試發現,如果傳回的字元串不帶中文,即隻有普通的英文符号(比如字母、數字等),就沒有問題,如果有中文,就失敗。後加了個try:

public ActionResult SearchDir()
{
    string remoteDirList = "";
    try
    {
        WebClient webClient = new WebClient();
        remoteDirList = webClient.DownloadString(strRemoteUrl);
        DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(List<string>));
        MemoryStream ms = new MemoryStream(Encoding.Default.GetBytes(remoteDirList));
        List<string> listTmp = (List<string>)ser.ReadObject(ms);
    
        DirFindViewModel model = new DirFindViewModel();
        model.dirList = listTmp;
        return PartialView(model);
    }
    catch(Exception e)
    {
        model.strDesc = e.Message;
        return PartialView(model);
    }
}
           

通過catch,發現是反序列化時失敗,說什麼格式不正确,同時發現 remoteDirList 的中文内容是亂碼,這應該是編碼的問題了,于是去網上找相關的說明,修改後的代碼如下:

public ActionResult SearchDir()
{
    string remoteDirList = "";
    try
    {
        WebClient webClient = new WebClient();
        remoteDirList = webClient.DownloadString(strRemoteUrl);

        // 轉換編碼為unicode
        byte[] utf8Bytes = Encoding.Default.GetBytes(remoteDirList);
        byte[] defBytes = Encoding.Convert(Encoding.UTF8, Encoding.Default, utf8Bytes);
        remoteDirList = Encoding.Default.GetString(defBytes);


        DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(List<string>));
        MemoryStream ms = new MemoryStream(Encoding.Default.GetBytes(remoteDirList));
        List<string> listTmp = (List<string>)ser.ReadObject(ms);
    
        DirFindViewModel model = new DirFindViewModel();
        model.dirList = listTmp;
        return PartialView(model);
    }
    catch(Exception e)
    {
        model.strDesc = e.Message;
        return PartialView(model);
    }
}
           

再跟蹤仍然失敗,仔細看轉換之後的字元串,發現前面的大部分是正常的,隻有最後一個字會被轉成??,即兩個問号。反複捉摸,問了同僚,參考網上的,既然web api傳回List<string>在接收端是個字元串,那我直接改為傳回字元串,修改後如下:

public string GetLocalDirs()
{
    List<string> retList = GetGoodDirs();
    if (retList.Count() == 0)
        retList.Add("-1:搜尋目錄失敗");

    string retStr = Newtonsoft.Json.JsonConvert.SerializeObject(retList);
    return retStr;
}
           

改過之後,發現還是不行,原本正常的字元串,這次多出了轉義符,比如修改之前傳回的是:

["-1:搜尋目錄失??"],修改之後,傳回的變成了:

"[\"-1:搜尋目錄失敗\"]"

注意,這是實際的内容,如果是在調試模式下,在變量清單中顯示的内容就是 “\"[\\\"-1:搜尋目錄失敗\\\"]\"”,(兩邊的雙引号是工具顯示字元串的),這個就有點不可思議了,我在web api的接口中,把傳回的retStr寫入到檔案中,檢視它确實沒錯,并不存在黑底符。沒辦法,我就摒棄了庫函數,直接自己實作,代碼也很簡單:

public string GetLocalDirs()
{
    List<string> retList = GetGoodDirs();
    if (retList.Count() == 0)
        retList.Add("-1:搜尋目錄失敗");

    string retStr = "[";
    int txtIndex = 0;
    foreach(string itemText in retList)
    {
        if (txtIndex > 0)
            retStr += ",";
        retStr += "\"" + itemText + "\"";
        txtIndex++;
   }
   retStr += "]";

    return retStr;
}
           

這改過之後,仍然把傳回的内容寫入檔案,檢視和之前沒啥差別,依然有轉義符,沒辦法了,既然傳輸會帶上轉義符,那就在接收端把它去掉,修改代碼如下:

public ActionResult SearchDir()
{
    string remoteDirList = "";
    try
    {
        WebClient webClient = new WebClient();
        remoteDirList = webClient.DownloadString(strRemoteUrl);

        // 轉換編碼為unicode
        byte[] utf8Bytes = Encoding.Default.GetBytes(remoteDirList);
        byte[] defBytes = Encoding.Convert(Encoding.UTF8, Encoding.Default, utf8Bytes);
        remoteDirList = Encoding.Default.GetString(defBytes);
        remoteDirList = remoteDirList.Replace("\\", "");        // 加了這三行
        remoteDirList = remoteDirList.Replace("\"[", "[");
        remoteDirList = remoteDirList.Replace("]\"", "]");

        DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(List<string>));
        MemoryStream ms = new MemoryStream(Encoding.Default.GetBytes(remoteDirList));
        List<string> listTmp = (List<string>)ser.ReadObject(ms);
    
        DirFindViewModel model = new DirFindViewModel();
        model.dirList = listTmp;
        return PartialView(model);
    }
    catch(Exception e)
    {
        model.strDesc = e.Message;
        return PartialView(model);
    }
}
           

再測試,轉義符已經被成功清除掉了,現在還是有編碼的問題,再仔細考慮,這個編碼我點有混亂,在catch的提示資訊中,有出現“utf8”的字樣,那看來還是編碼的問題導緻的,對于http傳輸,不大可能丢失位元組,就算丢,也不可能是每次都丢,并且丢的是中間的内容。再仔細檢視編碼的轉換部分,把滑鼠放在 Encoding.Default 的Default 上,提示是ANSI 代碼頁的編碼,但是string提示又是unicode,加上catch提示中的utf8字樣,難道是反序列化的編碼不對?對它的編碼進行修改,不再使用Default編碼,修改後代碼如下:

public ActionResult SearchDir()
{
    string remoteDirList = "";
    try
    {
        WebClient webClient = new WebClient();
        remoteDirList = webClient.DownloadString(strRemoteUrl);

        // 轉換編碼為unicode
        byte[] utf8Bytes = Encoding.Default.GetBytes(remoteDirList);
        byte[] defBytes = Encoding.Convert(Encoding.UTF8, Encoding.Default, utf8Bytes);
        remoteDirList = Encoding.Default.GetString(defBytes);
        remoteDirList = remoteDirList.Replace("\\", "");
        remoteDirList = remoteDirList.Replace("\"[", "[");
        remoteDirList = remoteDirList.Replace("]\"", "]");

        DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(List<string>));
        MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(remoteDirList));    // 改了編碼
        List<string> listTmp = (List<string>)ser.ReadObject(ms);
    
        DirFindViewModel model = new DirFindViewModel();
        model.dirList = listTmp;
        return PartialView(model);
    }
    catch(Exception e)
    {
        model.strDesc = e.Message;
        return PartialView(model);
    }
}
           

注,這裡隻是修改了 MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(remoteDirList)); 一行中的編碼,由Default改成了Unicode。然後再測試,一切ok,所有的中文也都能正常顯示了,反序列化也不再被catch了。