none
Integrating the CCR into a Asynchronous WCF Web Service (Not Client side!)

    Pregunta

  • Hello all,

    I hope you can help me out here.  I'm designing a 'Proof of concept' CCR Project for work.
    I have created a WCF Service that can take advantage of the CCR. 

    The WCF Service will feature Asynchronous web methods such as:

    public class Service : IService
    {
        public IAsyncResult BeginGetAccount(int id, AsyncCallback callback, object state)
        {
            //Kick Off CCR Enabled method - And Don't block thread!
        }

        public string EndGetAccount(IAsyncResult result)
        {
            //Return Account Result
        }
    }

    I have already written a method for Asynchronously getting the Account from a SQL Database.
    It has the following signature: 

    public IEnumerator<ITask> GetAccount(int id, Port<Account> resultPort)

    Any Accounts found will be posted to the resultPort (only one is expected)
    Here is where I come unstuck...

    How do I stitch together the WCF service call and the IEnumerator?


    Learning one small step at a time
    martes, 03 de febrero de 2009 10:31

Respuestas

  • You need to provide a custom implementation for IAsyncResult. This is boilerplate code that you only have to write once. Here is an example. I assumes that the result port is of type PortSet<int, Exception>. You can easily change this to your Account type.

     

    1         class AsyncResult : IAsyncResult  
    2         {  
    3             object _state;  
    4             ManualResetEvent _waitHandle = new ManualResetEvent(false);  
    5             bool _isCompleted;
    6
    7             #region IAsyncResult Members  
    8             public object AsyncState  
    9             {  
    10                 get { return _state; }  
    11             }  
    12  
    13             public System.Threading.WaitHandle AsyncWaitHandle  
    14             {  
    15                 get { return _waitHandle; }  
    16             }  
    17  
    18             public bool CompletedSynchronously  
    19             {  
    20                 get { return false; }  
    21             }  
    22  
    23             public bool IsCompleted  
    24             {  
    25                 get { return _isCompleted; }  
    26             }
    27             #endregion  
    28  
    29             Exception _exception;  
    30             internal Exception Exception  
    31             {  
    32                 get { return _exception; }  
    33             }  
    34  
    35             int _result;  
    36             internal int Result  
    37             {  
    38                 get { return _result; }  
    39             }  
    40  
    41             internal AsyncResult(PortSet<int, Exception> port, DispatcherQueue queue, AsyncCallback callback, object state)  
    42             {  
    43                 _state = state;  
    44  
    45                 Arbiter.Activate(queue,  
    46                     Arbiter.Choice(port,  
    47                         r =>   
    48                         {   
    49                             _result = r;  
    50                             Complete(callback);  
    51                         },   
    52                         e =>  
    53                         {  
    54                             _exception = e;  
    55                             Complete(callback);  
    56                         }  
    57                     )  
    58                 );          
    59             }  
    60  
    61             private void Complete(AsyncCallback callback)  
    62             {  
    63                 _isCompleted = true;  
    64                 _waitHandle.Set();  
    65  
    66                 if (callback != null)  
    67                 {  
    68                     ThreadPool.QueueUserWorkItem(s => callback(this));  
    69                 }  
    70             }  
    71         } 

    In the BeginGetAccount method you have to

    • enqueue the iterative task in a DispatcherQueue
    • create and return an instance of AsyncResult (with the result port, dispatcher queue, callback and state as parameters)

    In the EndGetAccound method you have to

    • cast the result to AsyncResult
    • retrieve the Result and return it (or throw an exception)

    Hope this helps,

    Andreas

    • Marcado como respuesta Mavstar martes, 03 de febrero de 2009 22:34
    martes, 03 de febrero de 2009 18:36

Todas las respuestas

  • You need to provide a custom implementation for IAsyncResult. This is boilerplate code that you only have to write once. Here is an example. I assumes that the result port is of type PortSet<int, Exception>. You can easily change this to your Account type.

     

    1         class AsyncResult : IAsyncResult  
    2         {  
    3             object _state;  
    4             ManualResetEvent _waitHandle = new ManualResetEvent(false);  
    5             bool _isCompleted;
    6
    7             #region IAsyncResult Members  
    8             public object AsyncState  
    9             {  
    10                 get { return _state; }  
    11             }  
    12  
    13             public System.Threading.WaitHandle AsyncWaitHandle  
    14             {  
    15                 get { return _waitHandle; }  
    16             }  
    17  
    18             public bool CompletedSynchronously  
    19             {  
    20                 get { return false; }  
    21             }  
    22  
    23             public bool IsCompleted  
    24             {  
    25                 get { return _isCompleted; }  
    26             }
    27             #endregion  
    28  
    29             Exception _exception;  
    30             internal Exception Exception  
    31             {  
    32                 get { return _exception; }  
    33             }  
    34  
    35             int _result;  
    36             internal int Result  
    37             {  
    38                 get { return _result; }  
    39             }  
    40  
    41             internal AsyncResult(PortSet<int, Exception> port, DispatcherQueue queue, AsyncCallback callback, object state)  
    42             {  
    43                 _state = state;  
    44  
    45                 Arbiter.Activate(queue,  
    46                     Arbiter.Choice(port,  
    47                         r =>   
    48                         {   
    49                             _result = r;  
    50                             Complete(callback);  
    51                         },   
    52                         e =>  
    53                         {  
    54                             _exception = e;  
    55                             Complete(callback);  
    56                         }  
    57                     )  
    58                 );          
    59             }  
    60  
    61             private void Complete(AsyncCallback callback)  
    62             {  
    63                 _isCompleted = true;  
    64                 _waitHandle.Set();  
    65  
    66                 if (callback != null)  
    67                 {  
    68                     ThreadPool.QueueUserWorkItem(s => callback(this));  
    69                 }  
    70             }  
    71         } 

    In the BeginGetAccount method you have to

    • enqueue the iterative task in a DispatcherQueue
    • create and return an instance of AsyncResult (with the result port, dispatcher queue, callback and state as parameters)

    In the EndGetAccound method you have to

    • cast the result to AsyncResult
    • retrieve the Result and return it (or throw an exception)

    Hope this helps,

    Andreas

    • Marcado como respuesta Mavstar martes, 03 de febrero de 2009 22:34
    martes, 03 de febrero de 2009 18:36
  • Thanks Andreas!

    I still have a lot to learn in this space, but hey that's a Good thing :)
    Last night I was just about ready to give up on trying to integrate the Async WCF and CCR.

    Thanks again!

    Mav.
    Learning one small step at a time
    martes, 03 de febrero de 2009 22:36
  • Hello

    I was looking at your sample code

    any reason why you queue up the callback execution in the threadpool queue instead of executing it directly in a CCR thread?

    seem to me that "Complete" will be executed internally as any other task?

    Thanks

    Nicolas
    lunes, 11 de mayo de 2009 1:18
  • Most async operations use the system threadpool for executing the callback. So this was mainly chosen to be consistent. Also, it isolates the CCR worker thread from badly written client code that executes long running operations in the callback. While these could still potentially exhaust the threadpool, well written CCR components will not affected. This is important if you implement you health monitoring in CCR.

    lunes, 11 de mayo de 2009 5:48