2009-01-30 101 views
2

我正在學習如何將CCR(併發和協調運行時)與異步WCF Web服務結合使用。在異步WCF服務中使用CCR

這是測試WCF服務:

public class Service : IService 
    { 
     private Accounts.Manager accountManager = new Accounts.Manager(); 
     public IAsyncResult BeginGetAccount(int id, AsyncCallback callback, object state) 
     { 
      //How Do I Call the CCR Function without blocking a Thread? 
      throw new NotImplementedException(); 
     } 

     public string EndGetAccount(IAsyncResult result) 
     { 
      //How Do I Finish the Call and Pass back the Result? 
      throw new NotImplementedException(); 
     } 
    } 

這將需要一個ID號,並返回匹配的帳戶名(如果有的話)

我已經寫了CCR功能應該找到匹配的帳戶(s) (顯然需要大量的工作 - 這只是概念驗證) 這裏是我去的地方。

如何傳回結果(全局端口?) 更重要的是:如何在不阻塞線程的情況下將CCR插入WCF異步服務調用?

public IEnumerator<ITask> GetAccount(int id) 
    { 
     SqlDataReader reader = null; 
     SqlConnection connection = new SqlConnection(@"Data Source=.\SQLEXPRESS;Initial Catalog=BizData;Integrated Security=True;Async=True;"); 
     string query = "SELECT * FROM Account WHERE AccountID = @AccountID"; 
     SqlCommand command = new SqlCommand(query, connection); 
     SqlParameter accountID = new SqlParameter("AccountID", id); 
     command.Parameters.Add(accountID); 

     connection.Open(); 
     yield return Arbiter.Choice(SQLAdapter.GetReader(command), 
      delegate(SqlDataReader r) { reader = r; }, 
      delegate(Exception e) { Console.Write("Failed to get SQL data"); }); 

     if (reader == null) yield break;  

     while (reader.Read())  
     { 
      Account account = new Account { ID = Convert.ToInt32(reader["AccountID"]), 
       Name = reader["Account"].ToString(), 
       ParkingNo = Convert.ToInt32(reader["ParkingNo"]), 
       Password = reader["Password"].ToString() }; 
      //Post account? 
     } 
     connection.Close(); 
    } 

回答

1

好的,我終於得到了所有這一切!

第一項:您需要一個定製的AsyncResult類

class AsyncResult : IAsyncResult , IDisposable 
    { 
     object _state; 
     ManualResetEvent _waitHandle = new ManualResetEvent(false); 
     bool _isCompleted; 

     #region IAsyncResult Members 
     public object AsyncState 
     { 
      get { return _state; } 
     } 

     public System.Threading.WaitHandle AsyncWaitHandle 
     { 
      get { return _waitHandle; } 
     } 

     public bool CompletedSynchronously 
     { 
      get { return false; } 
     } 

     public bool IsCompleted 
     { 
      get { return _isCompleted; } 
     } 
     #endregion 

     Exception _exception; 
     internal Exception Exception 
     { 
      get { return _exception; } 
     } 

     Accounts.Account _result; 
     internal Accounts.Account Result 
     { 
      get { return _result; } 
     } 

     internal AsyncResult(PortSet<Accounts.Account, Exception> port, DispatcherQueue queue, AsyncCallback callback, object state) 
     { 
      _state = state; 

      Arbiter.Activate(queue, 
       Arbiter.Choice(port, 
        r => 
        { 
         _result = r; 
         Complete(callback); 
        }, 
        e => 
        { 
         _exception = e; 
         Complete(callback); 
        } 
       ) 
      ); 
     } 

     private void Complete(AsyncCallback callback) 
     { 
      _isCompleted = true; 
      _waitHandle.Set(); 

      if (callback != null) 
      { 
       ThreadPool.QueueUserWorkItem(s => callback(this)); 
      } 
     } 

     private bool disposedValue = false; 

     public void Dispose() 
     { 
      if (!this.disposedValue) 
      { 
       _waitHandle.Close(); 
       _waitHandle = null; 
       _state = null; 
      } 
      this.disposedValue = true; 
     } 
    } 

好了,那麼我們就需要使用異步WCF方法來把這些在呼叫:

public class Service : IService 
    { 
     private Dispatcher dispatcher; 
     private DispatcherQueue dq; 

     public Service() 
     { 
      dispatcher = new Dispatcher(); 
      dq = new DispatcherQueue("CCR DispatcherQueue", dispatcher); 
     } 

     public IAsyncResult BeginGetAccount(int id, AsyncCallback callback, object state) 
     { 
      PortSet<Accounts.Account, Exception> port = new PortSet<Accounts.Account, Exception>(); 
      Accounts.Manager manager = new Accounts.Manager(); 
      manager.GetAccountData(dq, port, id); 

      AsyncResult result = new AsyncResult(port, dq, callback, state); 
      return result; 
     } 

     public string EndGetAccount(IAsyncResult result) 
     { 
      { 
       var AccountName = string.Empty; 
       if ((result != null)) 
       { 
        using (Common.AsyncResult asyncResult = result as Common.AsyncResult) 
        { 

         if (asyncResult == null) 
         { 
          throw new NullReferenceException("IAsynchResult Parameter is Null"); 
         } 

         asyncResult.AsyncWaitHandle.WaitOne(); 
         if (asyncResult.Result != null) 
         { 
          AccountName = asyncResult.Result.Name; 
         } 
        } 
       } 
       return AccountName; 
      } 
     } 
    } 

然後你只需要IEnumerator的方法發佈回答端口