Question

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 = ...;
    }
}
Was it helpful?

Solution

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
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top