非同步AsyncController + 網頁截圖 實作教學
有時候在Server端處理一些比較耗時的工作,例如讀寫檔案,呼叫外部的服務等..
不僅僅讓使用者Hold在那邊,同時也占了一個Thread,當Thread到達上限後,之後進入的使用者
就只能排在佇列中,當佇列也額滿時,就會回覆503給使用者了。(買五月天演唱會的票時常會遇到)
之前的部落格有去呼叫網頁截圖的API,剛好可以用來練習這樣的情境:
網路上有很多提供類似擷取網頁圖片的服務,使用上只要在網址上加上參數即可,很簡單。
因此只要利用HttpWebRequest這個類別去送出一個request,然後將回應的圖片存起來即可。
C#
public class HomeController : AsyncController
{
[AsyncTimeout(10000)]
public void LoadImageAsync(string url)
{
string name = Guid.NewGuid().ToString(); //設定一個檔名
string path = Server.MapPath("~/File/links/"); //存放路徑
AsyncManager.OutstandingOperations.Increment(1); //計數器加 1
AsyncManager.Parameters["Status"] = true; //預設一個參數叫Status,值為true
WebRequest httpRequest =
HttpWebRequest.Create(@"http://mozshot.nemui.org/shot/large?" + url);
//建立一個Request
//以下是參考的服務網址
//http://capture.heartrails.com/256x256/shadow/delay=5?指定的url 較快
//http://mozshot.nemui.org/shot/large?指定的url 較慢
httpRequest.BeginGetResponse((ar) =>
{
WebResponse response = httpRequest.EndGetResponse(ar);
//下面這一段是判斷抓到的是不是正確的圖片
//因為服務有時候圖抓得不是那麼快
if (false)//這邊需看不同的服務回傳的結果作判斷
{
AsyncManager.Parameters["Message"] = "抓取失敗,請稍後再試一次。";
AsyncManager.OutstandingOperations.Decrement();
//當失敗的時候,計數器減1,也就是歸零,就會觸發LoadImageCompleted
}
else
{
using (Stream dataStream = response.GetResponseStream())
{
//如果是抓到正確的response,將stream轉為圖片
using (System.Drawing.Image image = System.Drawing.Bitmap.FromStream(dataStream))
{
try
{
//存檔
image.Save(path + name + ".png");
//設定另外一個參數Message,存放訊息
AsyncManager.Parameters["Message"] = "抓取成功";
}
catch (Exception ex)
{
//發生錯誤時,將Status參數設為false
AsyncManager.Parameters["Status"] = false;
}
finally
{
//不管有沒有發生例外,都將計數器減1
AsyncManager.OutstandingOperations.Decrement();
}
}
}
}
}, null);
}
public ActionResult LoadImageCompleted(bool Status, string Message)
{
//回應結果,這邊寫這樣有點蠢,但因為我自己的網站是用ajax去呼叫的
//所以結果會直接alert出來
if (Status)
{
return Content(Message);
}
return Content("0");
}
}
Html
<script src="http://code.jquery.com/jquery-1.7.1.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(function () {
$('#url').change(function () {
//注意這邊呼叫的路徑!!不用加Async
$.post('<%=Url.Action("LoadImage") %>', { url: $('#url').val() },
function (data, status) {
if (data == '0') {
alert("取樣失敗!");
} else {
alert(data);
}
});
});
});
</script>
輸入網址:<input id="url" type="text" /><br /><br />
另外上面那一段判斷response正不正確,每個服務回應的都不太一樣,在試的時候只要
偵個錯,看一下response有什麼不一樣,就可以做出判斷了。
參考資料: