How do I create and return a continuation Task using reflection or by any other means if I only have access the Task?
I need a way to let an exception in the continuation travel back to the original caller. As far as I know this can only be done by returning the continuation task instead of the original task. The problem comes in that I don't know the result type of the Task so can't create a proper continuation Task.
Edit: I cannot change signature types. I have many interfaces that return Task< TResult > objects and can't expect the client to get Task< Object > results. These interfaces are WCF contracts. I want to do some extra validation logic after the "core" logic method is done and throw an exception if needed. This exception must travel back to client but it does not travel back currently because I'm not returning the continuation task yet. Also I don't know the type beforehand because I'm applying a postsharp aspect and using the OnExit() override, this gives me access to a return value that I know is a Task but it can be any number of Task objects of which TResult is only known at runtime.
using System;
using System.Threading.Tasks;
namespace TaskContinueWith
{
internal class Program
{
private static void Main(string[] args)
{
try
{
Task<string> myTask = Interceptor();
myTask.Wait();
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
Console.ReadLine();
}
private static Task<string> Interceptor()
{
Task<string> task = CoreLogic(); //Ignore
Task unknownReturnType = task; //This is what I have access to. A Task object which can be one of numerous Task<TResult> types only known at runtime.
Task continuation = unknownReturnType.ContinueWith(
t =>
{
if(someCondition)
{
throw new Exception("Error");
}
return t.Result; //This obviously does not work since we don't know the result.
});
return continuation;
}
private static async Task<string> CoreLogic()
{
return "test";
}
}
}
Another way to express the problem.
- I can only change what is inside DoExtraValidation().
- I cannot change the signature of DoExtraValidation() to use generics.
How do I change DoExtraValidation to make it work for any Task< TResult > return type?
using System;
using System.Threading.Tasks;
namespace TaskContinueWith
{
interface IServiceContract
{
Task<string> DoWork();
}
public class Servce : IServiceContract
{
public Task<string> DoWork()
{
var task = Task.FromResult("Hello");
return (Task<string>) DoExtraValidation(task);
}
private static Task DoExtraValidation(Task task)
{
Task returnTask = null;
if (task.GetType() == typeof(Task<string>))
{
var knownType = task as Task<string>;
returnTask = task.ContinueWith(
t =>
{
if(new Random().Next(100) > 50)
{
throw new Exception("Error");
}
return knownType.Result;
});
}
return returnTask;
}
}
internal class Program
{
private static void Main(string[] args)
{
try
{
IServiceContract myService = new Servce();
Task<string> myTask = myService.DoWork();
myTask.Wait();
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
Console.ReadLine();
}
}
}
Task<string>since that is what yourInterceptor()method returns. Is it always aTask<string>? If so, then a cast will work. If not, then you could return Task<object> and then the client code would need to figure out (somehow) what it was getting back. But my question would be--why don't you know the type that is being returned? It would be better to give a better description of what you're trying to do--there might be better solutions. - Matt Smith