2009-01-30 5 views
2

Je suis d'apprendre à utiliser le CCR (Concurrency et coordination Runtime) en liaison avec un service Web asynchrone WCF.Utilisation du CCR avec Asynchronous service WCF

C'est le service de test 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(); 
     } 
    } 

Il faudra un numéro d'identification et retourner le nom du compte de contrepartie (le cas échéant)

J'ai écrit une fonction de CCR qui doit trouver le compte correspondant (s) (de toute évidence, il faut beaucoup de travail - c'est juste preuve de concept) Voici où je suis décollé. Comment puis-je repasser les résultats (port global?) ET plus important encore: Comment connecter le CCR à l'appel de service asynchrone WCF sans bloquer un thread?

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(); 
    } 

Répondre

1

OK, j'ai finalement obtenu quelque part avec tout cela!

Première place: Vous avez besoin d'une coutume AsyncResult classe

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; 
     } 
    } 

Ok, alors nous devons attacher ce avec la Async WCF Appels de méthode:

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; 
      } 
     } 
    } 

Ensuite, il vous suffit de la méthode IEnumerator pour poster la réponse au port

Questions connexes