2009-04-05

Web Service非同步練習

在撰寫程式時我會盡量避開多執行緒問題
前陣子因為程式需求,比較常用.Net的BackgroundWorker
這次在練習撰寫Web Server時遇到一個課題

若是今天Client端程式去呼叫Web Service
而Service卻需要較長時間運算,才能回傳結果回來
那在Client端的UI會整個hold在那
這是我們開發程式的人最不想看到的樣子
(除非使用者很有耐心的等待!
不然你可以想像到,隔著螢幕後有個人一直幹樵敲鍵盤)

在微軟出的MCTS:Distributed Application Development Training Kit這本書的Chapter 7裡有大致提到使用非同步的方式。

接下來我也只是根據練習,實做下去
首先我先定義一個Delegate

public delegate string DelegateHelloWorld(string Name);

接下來使用BeginInvoke來實作
localhost.Service locService=new WinClinetPolling.localhost.Service();
 
DelegateHelloWorld myDelegate = new DelegateHelloWorld(locService.HelloWorld);
 
 
IAsyncResult result=myDelegate.BeginInvoke(textBox1.Text,null,myDelegate);
 
 
label1.Text="程式處理中,請稍候。。。";
 
 
while(!result.IsCompleted)
 
{
 
    label1.Text+="。";
    
    Application.DoEvents();
    Thread.Sleep(1000);
 
}
 
label1.Text="完成"+myDelegate.EndInvoke(result);     


其中locServer是我建立的Web Server
提供一個帶參數Method名稱為HelloWorld
這個Method中,我執行了一段程式碼
Thread.Sleep(10000);
也就是說當我呼叫這個Method時
會延遲十秒鐘後,才會回傳值

利用Delegate的BeginInvoke方式
來進行Asynchronously

其實也可以直接使用Web Service提供的
Asnyc方式,直接呼叫HelloWorldAsync
當建立了新的Web Method後,會自動提供另一個Asnyc
原本我的Method-HelloWorld
會再提供一個Asnyc的HelloWorldAsync

proxy.HelloWorldAsync(textBox2.Text, null);
 
label2.Text = "開始處理。。。請稍候!";

之後我們在去訂閱這個Method的Completed事件

proxy.HelloWorldCompleted += new WinClinetPolling.localhost.HelloWorldCompletedEventHandler(proxy_HelloWorldCompleted);

在Completed事件中

private void proxy_HelloWorldCompleted(object sender, WinClinetPolling.localhost.HelloWorldCompletedEventArgs e)
{
 if (e.Cancelled)
 {
  label2.Text = "取消了。。。";
 }
 else if (e.Error != null)
 {
  throw e.Error;
 }
 else
 {
  label2.Text = e.Result;
 }
}

先簡單記錄下來。。。

Universal Time 轉換成 Local Time

最近在撈取資料庫資料時,遇到一個問題
在這些資料中,有一些關於Date的資料
但這些時間全部存的都是Universal Time
當我直接撈回Local端來呈現報表時,會遇到時間錯亂的狀況

接下來的程式部份,是參考公司裡林大哥的程式

public static string[] SPFDateFormats = new string[] { "yyyy/MM/dd-HH:mm:ss", "yyyy/MM/dd-HH:mm:ss:fff", "yyyy/MM/dd" };    

public static DateTime ToUniversalTime(string pstrServerDate)
 
{
 
    DateTimeFormatInfo provider = new DateTimeFormatInfo();
    provider.DateSeparator = "/";
    provider.TimeSeparator = ":";
    try
    {
    
    return DateTime.ParseExact(pstrServerDate, SPFDateFormats, provider, DateTimeStyles.None);
    }
    catch (Exception exception)
    {                
    
    return DateTime.ParseExact("9999/12/31-23:59:59:999", SPFDateFormats, provider, 
    
    DateTimeStyles.None);
    }
 
}

這樣轉出來就會是Local Time。
先大概記錄下來。。或許以後還會使用到

參考資料:
1.DateTimeStyles
2.DateTime.ParseExact
3.DateTimeFormatInfo