There's a couple ways to go about this. You've already identified one of them ("Chained WCF Calls"). The other does indeed involve TPL techniques, and finesse.
Chained WCF Calls.
With this approach, just remember the most expensive part of WCF interactions is the (de-)serialization of payload / parameters. In terms of latency, your client will pay that price twice because you've "chained" your endpoints together. The "oneway" call configuration still requires that the client "wait" until all parameters have deserialized correctly and the call "looks good." This is because oneway calls still have the ability to raise a SOAP exception back to the caller indicating illegal parameters, or crashed WCF behaviors, etc. Only the latency of the "endpoint work" (the part you program) will be "saved" by using this technique.
With this approach, you must also consider that your oneway routine must be configured with most or all the same behaviors as your original endpoint. This is particularly true for the exception handling aspect. You said:
There is a stateful object that is stored in the OperationContext that maintains information about the process. If, for instance, there is an exception, it will save all of the relevant process information as a package.
It sounds like you would want to strip all or most of the behaviors from the original entry point, and instead have them decorate your internal oneway routine.
TPL Finesse
Note: this next approach likely solves only half your problem...
because it does not address the WCF exception-handing scenario
you called out.
In general, because it is [ThreadStatic] you are correct to be concerned about OperationContext not flowing between threads and TPL routines. However, according to MSDN, the OperationContext.Current property is public. Using closures, you should be able manually assign the OperationContext from the WCF request thread onto a new OperationContext.Current of a new Task.
In this case, you could allow the primary WCF request thread to return...and yet the new Task could run with the same OperationContext reference. If an exception is thrown on the new Task, it certainly will not be handled by a custom WCF behavior, since the primary WCF request thread would presumably have already exited-and-returned long ago, and thus it already "passed through" all the (exception handling) behavior layers.
In short, the only thing this buys you is if a WCF behavior had stamped a transaction ID into the OperationContext, then that transaction ID would manually flow onto the new Task...allowing a down-stream routine to pick it up.
If you were to follow this approach then:
- Try to ensure there is still a callback waiting for the background Task...its purpose is to catch any exception, log it if necessary, and swallow. You don't want independent Task in your WCF app having exceptions that are unhandled. Remember, you will have no help from WCF behaviors in this case.
- Be sure that the Task has a fairly confined latency...such as 400 to 800ms. You don't want a Task to run for 5 minutes. Presumably your WCF app is IIS hosted, and IIS can reload or unload your WCF AppDomain without warning...because it has no idea that you've created a new Task that is still doing work. As long as the latency is constrained, I doubt you will run into issues with IIS shutting down your WCF app "too soon."
Finally, if your situation is more complex than this, be aware of custom TaskScheduler instances.