Wait for an Async method to finish from a separate method

Using PostSharp to wrap a WCF Service call with AOP Logging with the OnEntry and OnExit methods for OnMethodBoundaryAspect.

Process: OnEntry() is called, a DateTime signaling the start of the call is stored in a property and an Asynchronous Task is started before the method ends while that Task continues on.

This Task formats some information on service call for logging and can take some time. These values are stored as properties in this class for logging.

OnExit() is called, another DateTime signaling the end of the call is stored. At this point I need to make sure the Task started in the OnEntry() method is complete and all the properties are ready to be logged to the database.

The question is how can I make sure the Task started in OnEntry() is complete for use in OnExit()? I have considered setting up a boolean, while(false) {Thread.Sleep(100);} then finish off when true, but that doesn't feel right for some reason.

Below is the code I currently have set up for this.

class LogMethodCallAttribute : OnMethodBoundaryAspect
{
    Int32 userId;
    String methodCall;
    String ip;
    DateTime entryTime;
    DateTime exitTime;

    /// Performs tasks on a Method before its execution.
    public override void OnEntry(MethodExecutionArgs args)
    {
        // Set OnEntry Time
        entryTime = DateTime.Now;

        if (ConfigurationManager.AppSettings["AOPLoggingEnabled"] == "1")
        {
            MessageProperties prop = OperationContext.Current.IncomingMessageProperties;
            // Queue the logging to run on the ThreadPool so the service can finish the request.
            Task.Factory.StartNew(() => SetUpLog(args, prop));            
        }
    }

    public override void OnExit(MethodExecutionArgs args)
    {
        // Set OnExit Time
        exitTime = DateTime.Now;

        // Need to make sure the Task running SetUpLog is complete and all props set.

        // Log the details of this method call.
        Logs.LogWebServiceCall(userId, methodName, ip, entryTime, exitTime);
    }

    // Format details for logging.
    private void SetUpLog(MethodExecutionArgs args, MessageProperties prop)
    {
        // Retrieve all the required data and do any formatting.
        userId = ...;
        methodCall = ...;
        ip = ...;
    }
}

Answers


EDIT: Okay, I think I misunderstood you.

Basically, you need to remember the Task that you've started, and then you can just call Wait() to wait until it's finished:

class LogMethodCallAttribute : OnMethodBoundaryAspect
{
    Task task;
    ... as before ...

    public override void OnEntry(MethodExecutionArgs args)
    {
        ...
        task = Task.Factory.StartNew(...);
    }

    public override void OnExit(MethodExecutionArgs args)
    {
        exitTime = DateTime.Now;
        // Wait for the task to have completed...
        task.Wait();
        // Now you can use the fields
    }
}

Personally I would actually not just set the fields in the task though - I'd make the task a Task<T> for some T which contains the logging parameters. Then you can make the only field in your attribute the task, and have:

var loggingParameters = task.Result;
... use the logging parameters

Need Your Help

Adding elements to top of Listview

android android-listview

I'm working on a app which features are below :

Carrierwave, MiniMagick - NoMethodError: undefined method `size' for nil:NilClass

ruby-on-rails ruby ruby-on-rails-3 carrierwave minimagick

On staging, I'm facing the following error on uploading and resizing an image through carrierwave and minimagick. On local everything works fine.