How to invoke(not call directly) the Task<T>'s ContinueWith method? - c#

For some business reasons, I cannot call the service's method directly, so I wrote the code like this:
class TheService {
public Task<string> CallMe(string input) {
return Task.Run(() => {
return "the result of " + input;
});
}
}
//The calling code segment...
//Get the target method's info
MethodInfo mi = typeof(TheService).GetMethod("CallMe");
//Get the target method's return type, yes, it's a Task<string>
ParameterInfo pi = mi.ReturnParameter;
Type taskType = pi.ParameterType;
//Get the service instance.(I new it here for simple reason)
TheService svc = new TheService();
//Invoke the target method and get the Task<string>, however I got only an object (not Task<string>) because I invoke it, not call it directly
object task = mi.Invoke(svc, new[] {"test"});
//How can I make a ContinueWith call here?
//This isn't work! It throws a conversion exception.
//Note: Task<string> is just an example. I wound actually get Task<MyClassA> or Task<MyClassB> here. So, I cannot hard code the conversion. However, I know the Type of Task<T> here. My instinct tells me I should use Invoke again but I don't know how to do.
((Task<object>)task).ContinueWith(a=>{
Console.WriteLine("The result is " + a.Result);
});
My question is how to call the object's (It's actually a Task) ContinueWith method?
Or anything workaround?

You can use the base class Task:
((Task)task).ContinueWith(a=>{
Console.WriteLine("The result is " + ((dynamic)a).Result);
});
Inside the completion callback ((dynamic)a).Result will be of type dynamic here. You can cast it or interrogate it using reflection. You can use reflection in the first place instead of dynamic if you like that better.
Another idea:
static void Run<T>(Task<T> task) {
...
}
Run((dynamic)task);
This uses dynamic to match the generic type arguments so that the call works.

It is because you cast Task<string> to Task<object>.
((Task<string>)task).ContinueWith(a => {
Console.WriteLine("The result is " + a.Result);
});
Remember that types with different generic constraint are not interchangeable.
If situation is trick that the task return type is unknown, you can keep using reflection.
((Task)task).ContinueWith(t =>
{
var resultProperty = t.GetType().GetProperty("Result");
var resultObject = resultProperty.GetValue(t);
Console.WriteLine("The result is " + resultObject);
});

Related

Waiting for a result from a lambda function in C#

I'm working on a c# application and using AWS lambda functions in the backend. The lambda function is working correctly and i'm able to call it from the application. The part I'm having trouble with is getting the code to wait for the result from the lambda function to be returned before continuing. I've looked into using the async/await pattern but i'm getting compile errors because AmazonLambda.InvokeAsync returns null.
This is the code what is correctly invoking the function and prints out the response but I'd like to instead return the response to the calling method. I've also tried changing the return from void to string and adding a return to the callback function but I get this error: "Anonymous function converted to a void returning delegate cannot return a value"
Any help is appreciated.
public void Invoke() {
InvokeRequest invokeRequest = new InvokeRequest() {
FunctionName = FunctionName,
Payload = Payload
};
Client.InvokeAsync(invokeRequest, responseObject => {
if (responseObject.Exception == null) {
Debug.Log("LAMBDA SUCCESS: " + Encoding.ASCII.GetString(responseObject.Response.Payload.ToArray()));
} else {
Debug.Log("LAMBDA ERR: " + responseObject.Exception);
}
});
}
Try...
var result = await Client.InvokeAsync(...
or
var result = Client.InvokeAsync(...).Result;
Try
public async Task Invoke() {
InvokeRequest invokeRequest = new InvokeRequest() {
FunctionName = FunctionName,
Payload = Payload
};
await Client.InvokeAsync(invokeRequest, responseObject => {
if (responseObject.Exception == null) {
Debug.Log("LAMBDA SUCCESS: " + Encoding.ASCII.GetString(responseObject.Response.Payload.ToArray()));
} else {
Debug.Log("LAMBDA ERR: " + responseObject.Exception);
}
});
}
AmazonLambdaClient.InvokeAsync function have multiple overloads. The one which you are using accepts two parameters -
InvokeRequest request
AmazonServiceCallback
The second parameter is a callback, think of it as an event(just like a click event of a button). Which means it is called when an event has happened unlike async/await of C# which return values to caller.
This is an asynchronous operation using the standard naming convention for .NET 4.5 or higher. For .NET 3.5 the operation is implemented as a pair of methods using the standard naming convention of BeginInvoke and EndInvoke. For Unity the operation does not take CancellationToken as a parameter, and instead takes AmazonServiceCallback and AsyncOptions as additional parameters.
Here is the link to official documentation AmazonLambdaClient.InvokeAsync
To solve your problem -
public void Invoke()
{
InvokeRequest invokeRequest = new InvokeRequest
{
FunctionName = FunctionName,
Payload = Payload
};
Client.InvokeAsync(invokeRequest, responseObject =>
{
if (responseObject.Exception == null)
{
Debug.Log("LAMBDA SUCCESS: " + Encoding.ASCII.GetString(responseObject.Response.Payload.ToArray()));
// Call function on success and pass in the returned value
}
else
{
Debug.Log("LAMBDA ERR: " + responseObject.Exception);
// Call function on failure and pass exception data
}
});
}
In the above code you can explicitly call methods for success/failure and pass in corresponding parameters. So whatever code you were planning to write after getting result from your Invoke function, write that in success/failure methods instead.
You can also create a separate callback function and use it instead of writing everything in Invoke function.

Generic Extension Method for Dynamic Member Invocation

I am trying to build a generic extension method that can call a member function of a class dynamically and return a specified type. For some background, this is the general problem:
I am using Autorest to generate some client libraries for a swagger API. Because some GET routes within the API return different objects depending on the HTTP status code of the response, the method invocation returns object and the developer is responsible for casting the object themselves. I am trying to create a convenient wrapper for doing this cast in a generic way.
Here is an example of a typical function signature that would be wrapped up:
object IPet GetPets(string petName)
Note that this method might return a number of object types, depending on the HTTP status code. For instance, 200 might return a Dog object but 404 might return a Cat object.
This would be invoked through an Autorest generated client library like this:
AnimalApi animalClient = new AnimalApi(new Uri("http://myanimals.com"));
object pet = animalClient.Pet.GetPets("dog");
if(pet is Dog) {
Console.WriteLine("Dog!");
} else {
Console.WriteLine("Not Dog");
}
I would like to scoop up this manual casting functionality into something a bit more intuitive, here is what I am thinking:
AnimalApi animalClient = new AnimalApi(new Uri("http://myanimals.com"));
string petType = "Dog";
Dog pet = animalClient.Pet.CallMethod<IPet, Dog, string>( (api,type) => api.GetPets(type), petType);
In this scenario, any return other than objects of type 'Dog' would cause an exception to be thrown. Here is my attempt at implementation:
public static Tout CallMethod<Tin, Tout>(this Tin client, Expression<Action<Tin, Targ>> apiCall, params object[] args)
where Tout : class {
MethodCallExpression providedMethod = apiCall.Body as MethodCallExpression;
if(providedMethod == null) {
throw new ApplicationException("Invalid method call provded");
}
var method = providedMethod.Method;
object responseData;
try {
// Call object-returning function
responseData = method.Invoke(client, args);
} catch(Exception error) {
if(error.InnerException is HttpOperationException) {
// Unknown error occurred
var ex = error.InnerException as HttpOperationException;
object content = JsonConvert.DeserializeObject(ex.Response.Content);
throw new ServiceException(ex.Response.StatusCode + ": "
+ JsonConvert.SerializeObject(content));
} else {
throw error.InnerException;
}
}
// Return formatted object if successful
if(responseData is Tout) {
return responseData as Tout;
// Otherwise throw
} else {
// Deal with known error object responses
if(responseData is ErrorResponse) {
var error = responseData as ErrorResponse;
throw new ServiceException(error);
} else {
// Unknown error occurred
throw new ServiceException("Unknown response was received: "
+ JsonConvert.SerializeObject(responseData));
}
}
}
The problem I have here is of passing the function and arguments into the generic extension method. Without knowing the various possible numbers of arguments that might be required by the various API calls, how can I define Expression<Action<Tin, Targ>> generically? It seems to me like I would have to replicate this function with Expression<Action<T1, T2, T3>> and so on to accommodate varying length argumen lists.
I want an expressive way for people to interact with the API, such that it is easy to see what is happening. However, this mechanism should be robust to various API changes down the road. My current goal is to provide a way to encapsulate common object casting and error checking operations. Is there a better way to do this? For the moment I am working under the assumption that the server side swagger doc cannot change.

Generic type func-eval using ICorDebugEval

I'm making a managed .NET debugger using MDBG sample.
MDBG has no support for property getters evaluation, which I'm trying to add. Please, consider following class structure:
public abstract class Base<T>{
public string SomeProp {get;set;}
}
public class A : Base<int>{
}
At some point of time I'm creating an instance of A and stopping at a breakpoint to evaluate it's state.
In my debugger's watch window I introduce "this.SomeProp", that should perform a func-eval of get_SomeProp method on this object and return a null value for given case.
The first issue I've encountered was the fact, that get_SomeProp was defined on the base class, so I had to run through all TypeDefs/TypeRefs/TypeSpecs in the class hierarchy to find the function.
But after it was found, calling
ICorDebugEval.CallFunction(function.CorFunction, new[] {#object.CorValue});
resulted in: TypeLoadException: The generic type was used with the wrong number of generic arguments in assembly.
As I've realized it happens because non-generic function is defined in a generic class (Base), so when I'm evaluating it I should also indicate class's generic params.
This could be done using
ICorDebugEval2.CallParameterizedFunction(function.CorFunction,
genericArguments,
functionArguments);
The problem is that I have no idea how to extract types of class generic parameters, having only function that I want to evaluate and instance on which I want to evaluate it.
Here is some code I'm currently using:
private MDbgValue EvaluatePropertyGetter(MDbgFrame scope, MDbgValue #object, string propertyName) {
var propertyGetter = $"get_{propertyName}";
var function = ResolveFunctionName(
scope.Function.Module.CorModule.Name,
#object.TypeName,
propertyGetter,
scope.Thread.CorThread.AppDomain);
if (function == null) {
throw new MDbgValueException("Function '" + propertyGetter + "' not found.");
}
var eval = Threads.Active.CorThread.CreateEval();
var typeToken = function.CorFunction.Class.Token;
var type = function.Module.Importer.GetType(typeToken); //checked that type containing function is generic
if (type.IsGenericType) {
//------------->need to get class'es generic param types<------------
var genericType1 = this.ResolveType("System.Object"); // just a stub
eval.CallParameterizedFunction(function.CorFunction, new CorType[] {genericType1}, new[] {#object.CorValue});
}
else {
eval.CallFunction(function.CorFunction, new[] {#object.CorValue});
}
Go().WaitOne();
if (!(StopReason is EvalCompleteStopReason)) {
// we could have received also EvalExceptionStopReason but it's derived from EvalCompleteStopReason
Console.WriteLine("Func-eval not fully completed and debuggee has stopped");
Console.WriteLine("Result of funceval won't be printed when finished.");
}
else {
eval = (StopReason as EvalCompleteStopReason).Eval;
Debug.Assert(eval != null);
var cv = eval.Result;
if (cv != null) {
var mv = new MDbgValue(this, cv);
return mv;
}
}
return null;
}
Any suggestion/advice is greatly appreciated!
Regards,
Solution
Thanks to #Brian Reichle outstanding answer I came up with this solution:
if (type.IsGenericType) {
//getting Type's Generic parameters
var typeParams = GetGenericArgs(#object.CorValue.ExactType, function.CorFunction.Class.Token);
eval.CallParameterizedFunction(function.CorFunction, typeParams.ToArray(), new[] {#object.CorValue});
}
And the function itself:
private List<CorType> GetGenericArgs(CorType corType, int classTk) {
if (corType == null)
return null;
List<CorType> list = new List<CorType>();
var param =corType.TypeParameters;
var args = GetGenericArgs(corType.Base, classTk);
if (classTk == corType.Class.Token) {
list.AddRange(param.Cast<CorType>());
}
if (args != null) {
list.AddRange(args);}
return list;
}
You can use ICorDebugValue2::GetExactType on the value object representing an instance of A to get the ICorDebugType for type A, ICorDebugType::GetBase() to get its base class (Base<int>) and ICorDebugType::EnumerateTypeParameters on the base type to get it's type arguments.

C# Generics and using the non-generic version from typed method

I'm using the RestSharp library to access a REST API.
I want all the API requests to go through the same method, so I can add headers, handle errors and do other stuff in a central place.
So I made a method that accepts a generic Func<> and that solves most of my problems, but I don't know how to handle the case where I don't have a return type.
private T PerformApiCall<T>(RestRequest restRequest, Func<RestRequest, IRestResponse<T>> restMethod)
{
var response = restMethod.Invoke(restRequest);
//handle errors
....
return response.Data;
}
I call it like this:
var apples = PerformApiCall(new RestRequest('/api/apples'), req => Client.Execute<List<Apple>>(req));
But I came across a problem, a bunch of API calls don't have a return type because they don't return data. So I used Client.Execute(req) and I get the error saying the type arguments cannot be inferred, I tried to pass , but that failed because it couldn't convert the non-generic IRestResponse to the typed one.
Any ideas on how to tackle this in a nice way?
One thing you could try is to add an overload to your PerformApiCall function that takes a Func with a non-generic result type, and returns nothing:
// Notice the `Func` has `IRestResponse`, not `IRestResponse<T>`
public void PerformApiCall(RestRequest restRequest,
Func<RestRequest, IRestResponse> restMethod)
...
Then, depending on how complex your error checking/logic is, you could move it out to a separate method (which returns the response), and call it from both overloads of PerformApiCall:
private T PerformRequestWithChecks<T>(RestRequest restRequest,
Func<RestRequest, T> restMethod)
where T : IRestResponse
{
var response = restMethod.Invoke(restRequest);
// Handle errors...
return response;
}
// You can use it from both versions of `PerformApiCall` like so:
//
// // From non-generic version
// var response =
// PerformRequestWithChecks<IRestResponse>(restRequest, restMethod);
//
// // From generic version
// var response =
// PerformRequestWithChecks<IRestResponse<T>>(restRequest, restMethod);
// return response.Data;
You were getting a compiler error because it is sound to treat a subtype as if it was an instance of its supertype, but it is not sound to do it in the other direction (which is what was happening when you changed your calling code to just Client.Execute(req), returning a non-generic).
Here's an ideone paste illustrating this: http://ideone.com/T2mQfl

Passing a random method as a parameter?

Is there any way in C# to pass a random method as a parameter?
To explain my question:
I want to write a simple Logger-Tool that reports the entering and leaving of a method with the passed arguments an the class and method name:
The log file I'm aiming at:
ENTERING: ClassOfDoom::MethodOfDoom( arg1={1} [int], arg2={true} [bool] )
LEAVING: ClassOfDoom::MethodOfDoom RETURNING 1 [int]
The code I have in mind:
class ClassOfDoom {
// Remeber: MethodOfDoom is a _random_ method with _random_ arguments
public int MethodOfDoom(int arg1, bool arg2) {
Log.Entering(this, this.MethodOfDoom, arg1, arg2);
...
return Log.Returing(this, this.MethodOfDoom, 1);
}
}
Is there a way to achieve this? Or isn't C# as flexible as that?
Thanks in advance!
You can make your logging function take a MethodBase argument and use MethodBase.GetCurrentMethod to pass the current method info as an argument.
Then, in the logger, you could check its properties Name and DeclaringType to get the method information. Also, passing parameters is easy by declaring a params object[] args parameter in the logging function:
public static void Entering(object obj, MethodBase methodInfo,
params object[] args) {
Console.WriteLine("ENTERING {0}:{1}", methodInfo.DeclaringType.Name,
methodInfo.Name);
...
}
I'm not sure I entirely understand your question, but if you are trying to make a call to Log.Entering and Log.Returning inside an arbitrary (random) method and using the method's actual parameters, you should check out PostSharp. It will allow you to inject code in a method body and then do some work based on the reflected method information you get from the .NET framework (and the actual parameters passed to the method at runtime).
You could do it with Expression easily enough - it would look something like:
Log.Capture(() => this.MethodOfDoom(arg1, arg2));
Here's an example; I've been a bit lazy using Compile().DynamicInvoke() to read the arg-values - for real code I'd try to read it more directly:
using System;
using System.Diagnostics;
using System.Linq.Expressions;
class Program
{
DateTime MethodOfDoom(string s, int i)
{
return DateTime.Today;
}
public void RunTest()
{
int i =123;
Log.Capture(() => this.MethodOfDoom("abc", i));
}
static void Main()
{
new Program().RunTest();
}
}
static class Log
{
public static T Capture<T>(Expression<Func<T>> method)
{
MethodCallExpression mce = method.Body as MethodCallExpression;
if (mce == null) throw new InvalidOperationException(
"Method-call expected");
string name = mce.Method.Name;
try
{
int i = 0;
foreach(var param in mce.Method.GetParameters())
{
object argValue = Expression.Lambda(mce.Arguments[i++])
.Compile().DynamicInvoke();
Trace.WriteLine(param.Name + "=" + argValue, name);
}
Trace.WriteLine("ENTERING", name);
T result = method.Compile().Invoke();
Trace.WriteLine("EXITING: " + result, name);
return result;
}
catch (Exception ex)
{
Trace.WriteLine("EXCEPTION: " + ex, name);
throw;
}
}
}
If widely used in your code, this scenario is best implemented using Aspect Oriented Programming (AOP) techniques. There are different frameworks that can be used (such as Spring.NET AOP), which you can use in your .NET application. Here is a reference article that might help you get started:
http://www.developer.com/lang/article.php/10924_3795031_2
The referenced article gives you the logging enter/exit scenario as an example.
I have used PostSharp to do this very thing before.

Categories

Resources