參考網址: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了。