I'm calling a third-party API which has a method that looks like this:
myServiceClient.Discover(key, OnCompletionCallback);
public bool OnCompletionCallback(string response)
{
// my code
}
My challenge is, I have to call Discover because it does some work under-the-covers that I need. At the same time, I have to wait for Discover to complete before running my custom code. To further complicate matters, I can't just put my code in the OnCompletionCallback handler because I need to call the code above from a Func delegate. In short, I want to do this:
Func<SystemTask> myFunction = async () =>
{
await myServiceClient.Discover(key);
// my code
}
However, I can't do this because the third-party API uses a callback approach instead of an async/await approach.
Is there some way to make the callback approach work in an async / await world?
If I understand you correctly you can do something like this
public Task<bool> MyAsyncFunction()
{
var tcs = new TaskCompletionSource<bool>();
myServiceClient.Discover("somekey", s => {
//........
var res = true;
tcs.TrySetResult(res);
return res;
});
return tcs.Task;
}
Now you can await MyAsyncFunction
Related
Is there a way to get the result of a Task.Run function like this
private Task<bool> UpdteSth(double bla)
=> Task.Run(() =>
{
try
{
UpdateOneAsync(doStuff);
}
catch (Exception exception)
{
sentryClient.CaptureException(exception);
return false;
}
return true;
});
from a caller method like this
public async Task<Entity> Get()
{
UpdateSth(double bla);
}
without having to await UpdateSth so Get can freely do whatever it needs without having to wait to UpdateSth result? I still need to get the result of UpdateSth() to do some logging business but other than that Get should not wait for UpdateSth to be done to continue its job.
Clearly, await and Task.FromResult() still make my Get() to wait for the result or UpdateSth to be done so I cannot used those.
I'm not getting the issue here. If you want to fire-and-forget you just call UpdateSth(bla);. What am I missing here?
Here's an example of what that looks like:
public Task<Entity> Get() =>
Task.Run(() =>
{
double bla = 4.2;
UpdateSth(bla);
return new Entity();
});
This is a trivial example. I feel that there is a more stringent requirement that hasn't been explained in the question.
I'm using the Gcm Network Manager to schedule tasks, in one of those tasks I need to perform an HTTP request. Until now it was written with HttpWebRequest so nothing was async.
Now I would like to reuse code that is written with HttpClient and is async.
The problem that arrises is that I cannot make the OnRunTask() async as it needs to return an int:
e.g.
public override int OnRunTask(TaskParams #params)
{
var result = await performSync();
if(result)
{
return GcmNetworkManager.ResultSuccess;
}
return GcmNetworkManager.ResultReschedule;
}
What could I do to be able to reuse async code here ?
You can use Task.Run inside your OnRunTask method like this :
Task.Run( async () =>
{
// Do your stuff here
await asyncTask();
});
You will no need to have OnRunTask async with this technique
Hope it helps
Edit
If you need the return value to match the framework / library signature, you can also use .Result
E.g.
var result = asyncTask().Result;
...
I am using a network API which works with callbacks. So basically, I have a bunch of method calls that I need to use in this 3rd party library which look like this:
void SendNetworkRequest(string requestType, Action<Response> callback)
I find the code getting a little bit wacky because all of my methods which depend on network resources from this 3rd party API also need to implement callbacks themselves. For example, in my main scene I may want to get the players information and my code would look something like this:
void InitMainScene()
{
_networkHelper.SendNetworkRequest("GetPlayersInfo",OnPlayerInfoResponse);
}
void OnPlayerInfoResponse(Response response)
{
_playerInfo = response.Info;
}
I have recently gotten into RX and am using it abundently in my code. I have read read some about async/await. I have experimented quite a bit, especially with RX, and tried working with Observable.FromAsync() but could not get it to work..
What am I missing here? How can I write code which is cleaner and doesn't require the callback using RX or async/await? The following is the psuedocode which I'm looking for:
void InitMainScene()
{
_playerInfo = Overservable.DoMagicThing<Response>( () => {
_networkHelper.SendNetworkRequest("GetPlayersInfo",(r) =>{return r;}); });
}
Here's how to do it with Rx. I swapped out Response for string just so I could compile and test, but trivial to swap back.:
public IObservable<string> SendNetworkRequestObservable(string requestType)
{
return Observable.Create<string>(observer =>
{
SendNetworkRequest(requestType, s => observer.OnNext(s));
observer.OnCompleted();
return Disposable.Empty;
});
}
// Define other methods and classes here
public void SendNetworkRequest(string requestType, Action<string> callback)
{
callback(requestType); // implementation for testing purposes
}
I am not sure about RX. However, you can convert callback-based SendNetworkRequest to an awaitable task like this:
void SendNetworkRequest(string requestType, Action<Response> callback)
{
// This code by third party, this is here just for testing
if (callback != null)
{
var result = new Response();
callback(result);
}
}
Task<Response> SendNetworkRequestAsync(string requestType)
{
return Task.Run(() =>
{
var t = new TaskCompletionSource<Response>();
SendNetworkRequest(requestType, s => t.TrySetResult(s));
return t.Task;
});
}
Now you can consume SendNetworkRequestAsync with async/await more naturally
Here's my take on doing this with Rx.
Inside the NetworkHelper class add this method:
public IObservable<Response> SendNetworkRequestObservable(string requestType)
{
return
Observable
.Create<Response>(observer =>
{
Action<Response> callback = null;
var callbackQuery =
Observable
.FromEvent<Response>(h => callback += h, h => callback -= h)
.Take(1);
var subscription = callbackQuery.Subscribe(observer);
this.SendNetworkRequest(requestType, callback);
return subscription;
});
}
This creates an observable that internally uses Observable.FromEvent(...).Take(1) to create an observable based on expecting a single call to the Action<Response> callback passed to the SendNetworkRequest method.
The only issue with this is that the call occurs on the current thread right to completion. If you want this code to run on a background thread, but return the result to the current thread, then you can do this:
public IObservable<Response> SendNetworkRequestObservable(string requestType)
{
return
Observable
.Start(() =>
Observable
.Create<Response>(observer =>
{
Action<Response> callback = null;
var callbackQuery =
Observable
.FromEvent<Response>(h => callback += h, h => callback -= h)
.Take(1);
var subscription = callbackQuery.Subscribe(observer);
this.SendNetworkRequest(requestType, callback);
return subscription;
}))
.Merge();
}
Either way you'd call it like this:
var _playerInfo =
_networkHelper
.SendNetworkRequestObservable("GetPlayersInfo")
.Wait();
Just a side-note: your DoMagicThing is a synchronous call. In Rx that's a .Wait() call, but it's better to just use a normal .Subscribe when you can.
As per the comment, you could do this with async:
async void InitMainScene()
{
_playerInfo = await _networkHelper.SendNetworkRequestObservable("GetPlayersInfo");
}
So I have a function that has a long wait time during its computation. I have a endpoint that needs to call this function, however it does not care about the completion of the function.
public HttpResponseMessage endPoint
{
Repository repo= new Repository();
// I want repo.computeLongFunction(); to be called, however this endpoint
// can return a http status code "ok" even if the long function hasn't completed.
repo.computeLongFunction();
return Request.CreateReponse(HttpStatusCode.Ok);
}
// If I make the function async would that work?
public class Repository
{
public void compluteLongFunction()
{
}
}
Use the Task Parallel Library (TPL) to spin off a new thread.
Task.Run(() => new Repository().computeLongFunction());
return Request.CreateReponse(HttpStatusCode.Ok);
It doesn't look like computeLongFunction() returns anything, so try this:
Thread longThread = new Thread(() => new Repository().computeLongFunction());
longThread.Start();
return Request.CreateResponse(HttpStatusCode.Ok);
Declare the thread so that you will still be able to control its life-cycle.
I am trying to call a REST service using RESTSharp and continuing execution immediately as I just need a task started but need to continue execution immediately so I am trying to use ExecuteAsync instead of Execute.
My code should look like this now
IRestResponse<ExpandoObject> restResponse = client.ExecuteAsync<ExpandoObject>(restRequest, response =>
{
callback(response.Content);
});
However, I have no idea how to implement the callback function and all samples don't show it. I assume it is like this but it does not compile.
private IRestResponse<ExpandoObject> callback(string content)
{
return null;
}
Any ideas?
There are a few ways to implement what you're trying to do, but the it looks like your
callback has wrong method signature...to get something "basic" running, the following should work
(I added wait simply for testing):
EventWaitHandle resetEvent = new AutoResetEvent(false);
client.ExecuteAsync(request, response =>
{
callback(response.Content);
resetEvent.Set();
return;
});
resetEvent.WaitOne();
}
private static void callback(string content)
{
System.Console.WriteLine(content);
}