Question

J'apprends à utiliser le CCR (runtime de concurrence et de coordination) avec un service Web asynchrone WCF.

Il s'agit du 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 renvoyer le nom du compte correspondant (le cas échéant)

J'ai écrit une fonction CCR qui devrait trouver le (s) compte (s) correspondant (s). (nécessite évidemment beaucoup de travail - ceci est juste une preuve de concept) Voici où je viens décollé.

Comment puis-je transmettre les résultats (port global?) ET plus important encore: comment connecter le CCR à l'appel de service WCF asynchrone 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(); 
    }
Était-ce utile?

La solution

OK, j'ai finalement réussi à me rendre quelque part avec tout cela!

Première étape: vous avez besoin d'une classe AsyncResult personnalisée

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, nous devons faire le lien avec les appels à la méthode Async 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;
            }
        }
    }

Ensuite, vous avez juste besoin de la méthode IEnumerator pour envoyer la réponse au port

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top