WebAPI Threading - c#

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.

Related

How to start an async method without await its completion?

Sometimes I need to start an async job which works very slow. I don't care if that job success and I need to continue working on my current thread.
Like sometimes I need to send an Email or SMS which works very slow. I need to respond to the web client as soon as possible so I don't want to await it.
I have googled this question and some articles suggest me to write like this:
// This method has to be async
public async Task<Response> SomeHTTPAction()
{
// Some logic...
// ...
// Send an Email but don't care if it successfully sent.
Task.Run(() => _emailService.SendEmailAsync());
return MyRespond();
}
Or like this:
// This method has to be async
public async Task<Response> SomeHTTPAction()
{
// Some logic...
// ...
// Send an Email but don't care if it successfully sent.
Task.Factory.StartNew(() => _emailService.SendEmailAsync());
return MyRespond();
}
There will be a warning says: before the call is completed. Consider applying the 'await' operator to the result of the call.
So what if I really awaited it? What is the best practice in C# to 'fire and forget', just call an async method without waiting for its completion?
A standalone discard is the best way to avoid this warning.
_ = Task.Run(() => _emailService.SendEmailAsync());
Discards are dummy variables and can be used to ignore the Task object returned by an asynchronous operation.
https://learn.microsoft.com/en-us/dotnet/csharp/discards#a-standalone-discard
If you truly just want to fire and forget. Simply don't call use await.
// It is a good idea to add CancellationTokens
var asyncProcedure = SomeHTTPAction(cancellationToken).ConfigureAwait(false);
// Or If not simply do:
var asyncProcedure = SomeHTTPAction().ConfigureAwait(false);
If you want to use the result output later its gets trickier. But if it is truly fire and forget the above should work
A Cancellation token allows interrupts and canceling procedures. If you are using Cancellation token you will need to use it everywhere from the retrieval straight through to the calling method (Turtles all the way down).
I used ConfigureAwait(false) to prevent deadlocks. Here for more information
EDIT
See the second answer that uses 'Task.Factory.StartNew' I gave this answer some time ago. At the time I didn't realise that the way I did it at the time doesn't ensure completion.
If you need to use async in your function you can also use a discard variable and don't use await. This is also usefull if you have multiple async function calls but you don't need to wait for all of them.
public async function(){
var tmp = await asyncfunction();
...
_ = _httpClient.PutAsync(url, content);
...
}
As Amadan told in the comment that, you need to remove async from your function. then it will stop giving you the warning.
// This method has to be async
public Response SomeHTTPAction()
{
// Some logic...
// ...
// Send an Email but don't care if it successfully sent.
Task.Factory.StartNew(() => _emailService.SendEmailAsync());
return MyRespond();
}
and Task.Factory.StartNew(() => _emailService.SendEmailAsync()); will indeed work on a new thread.
It all depends on what your Async method accepts. Normally it will accept a "special" class that also holds an event. You can subscribe your callback method to that event and pass it along with the method. When it's finished, your callback method will be called.
An example of this (for sockets) would be:
public void CreateSocket()
{
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
SocketAsyncEventArgs sockAsync = new SocketAsyncEventArgs();
sockAsync.Completed += SockAsync_Completed;
s.ConnectAsync(sockAsync);
}
private void SockAsync_Completed(object sender, SocketAsyncEventArgs e)
{
//Do stuff with your callback object.
}
It all depends on what the method you are trying to call can accept. I would look at the documentation for more help on that specifically.
I am curious why this hasn't been suggested.
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
//what ever code here...e.g.
DoSomething();
UpdateSomething();
}).Start();
It just fires off a separate thread.

Awaiting a Callback method

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

Relating Task exception to a Task<T> response

I have just started working with tasks. We have a system setup that uses requests/responses. The service running the tasks accepts a master request that has a list of request objects and returns a master response that has a list of response objects. So it looks something like this
var MasterRequest = new MasterRequest;
MasterRequest.Requests.Add(new BlueRequest);
MasterRequest.Requests.Add(new RedRequest);
MasterRequest.Requests.Add(new YellowRequest);
The request implements a simple IRequest interface and each color is a concrete class. The service has concrete classes (request processors) set up to be able to process each request separately and simultaneously according to a concrete request object. Each concrete class on the service has a GetTask method with a signature like this:
Task<IResponse> GetTask(IRequest);
{
// some setup stuff
return Task.Factory.StartNew<IResponse>(() =>
{
// do task stuff
return response; // implements IResponse
});
}
My service takes the passed in MasterRequest and builds a list of tasks by calling the GetTask call listed above on the concrete request processors. I then use a Parallel.ForEach on the list to process the tasks.
// this is what is returned from the service.
// it has a List<IResponse> on it to hold the resposnes
MasterResposne resposne = new MasterResponse();
List<Task<IResponse>> tasks = new List<Task<IResponse>>();
foreach(IRequest req in MasterRequest.Requests)
{
// factory to get the proper request processor
RequestProcessor p = rp.GetProcessor(req);
tasks.add(p.GetTask(req));
}
Parallel.ForEach(tasks, t =>
{
t.Wait();
// check for faulted and cancelled
// this is where I need help
response.Responses.Add(t.Result);
}
This all works great. But if the task throws an exception I don't know how to tie it back to the specific concrete request that triggered it. I need to know so I can pass back a properly built response to the caller.
My first thought was to subclass Task but that brings up it's own set of issues that I don't want to deal with.
I read this SO article and it seems like I want to do something like this
Is this ok to derive from TPL Task to return more details from method?
I think Reed's second example is my solution but I still cannot see how to run the tasks simultaneously and be able to tie exceptions to the request so I can return a properly built list of responses.
Thanks in advance.
So I was able to use Reed's solution from the link I supplied. My service code to process the requests turned into this
// this is what is returned from the service.
// it has a List<IResponse> on it to hold the resposnes
MasterResposne resposne = new MasterResponse();
List<ExecutionResult> tasks = new List<ExecutionResult>();
foreach(IRequest req in MasterRequest.Requests)
{
// factory to get the proper request processor
RequestProcessor p = rp.GetProcessor(req);
tasks.add(p.GetResult(req));
}
Parallel.ForEach(tasks, t =>
{
t.task.Wait();
response.Responses.Add(t.Result);
}
Where ExecutionResult is defined like so
class ExecutionResult
{
public IResult Result;
public Task<IResponse> task;
}
That gives me access to a pre-built response object so I can pass it back to the caller.
EDIT:
So I reviewed my Parallel.ForEach and was able to redo my code and use await Task.WhenAll as suggested. New code looks more like this:
// this is what is returned from the service.
// it has a List<IResponse> on it to hold the resposnes
MasterResposne resposne = new MasterResponse();
List<ExecutionResult> tasks = new List<ExecutionResult>();
List<ExecutionResult> executionResults = new List<ExecutionResult>();
foreach(IRequest req in MasterRequest.Requests)
{
// factory to get the proper request processor
RequestProcessor p = rp.GetProcessor(req);
ExecutionResult er = engine.GetResult(req);
executionResults.Add(er);
tasks.Add(er.Task);
}
await Task.WhenAll<IResponse>(tasks);
foreach (ExecutionResult r in executionResults)
{
if (r.Task.IsCompleted)
{
response.AddResponse(r.Task.Result);
}
else
{
r.Response.Status = false;
AggregateException flat = r.Task.Exception.Flatten();
foreach (Exception e in flat.InnerExceptions)
{
Log.ErrorFormat("Reqest [{0}] threw [{1}]", r.Response.RequestId, e);
r.Response.StatusReason.AppendLine(e.Message);
}
}
}
This allows me to tie my request information to my task and get the response back that I need to return to my caller.
Thanks for the guidance.
I then use a Parallel.ForEach on the list to process the tasks.
This is actually pretty bad. It's throwing a ton of threads into the mix just to block on the tasks completing.
But if the task throws an exception I don't know how to tie it back to the specific concrete request that triggered it. I need to know so I can pass back a properly built response to the caller.
Whenever you have a "process tasks after they complete" kind of problem, usually the best solution is a higher-level asynchronous operation:
private async Task<IResponse> ProcessAsync(IRequest request)
{
try
{
return await engine.GetResult(request);
}
catch (Exception ex)
{
IResponse result = /* create error response */;
return result;
}
}
This allows a much simpler main function:
MasterResposne resposne = new MasterResponse();
var tasks = MasterRequest.Requests.Select(req => ProcessAsync(req));
response.AddRange(await Task.WhenAll(tasks));

Async/Await in foreach with HTTPClient

I have a webservice that loads up some plugins (dlls) and calls their Process method. One of the plugins takes a list of members and ensures that they are all included in a MailChimp list.
Here is the code that adds the users to the MailChimp group.
private async Task AddMCUsers(List<Member> _memberList)
{
using (var http = new HttpClient())
{
var creds = Convert.ToBase64String(Encoding.ASCII.GetBytes("user:password");
http.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", creds);
string memberURI = string.Format(#"{0}lists/{1}/members", _baseURI, _memberGroupId);
var jss = new JavaScriptSerializer();
foreach (var user in _memberlist)
{
var _addStatus = "";
try
{
var content = jss.Serialize(new MCPost()
{
email_address = user.Email,
status = "subscribed",
merge_fields = new MCMergeFields()
{
FNAME = user.Firstname,
LNAME = user.Lastname
}
});
using(var result = await http.PostAsync(memberURI, new StringContent(content,Encoding.UTF8, "application/json")))
{
var resultText = await result.Content.ReadAsStringAsync();
if(result.IsSuccessStatusCode)
{
_addStatus = "Success";
var _returnedUser = jss.Deserialize<MCMember>(resultText);
//Store new user's id
user.ServiceId = _returnedUser.id;
}
else
{
_addStatus = "Fail";
}
}
}
catch {
_addStatus = "Error";
}
LogEvent("Add User - " + _addStatus, string.Format("Id: {0} - {1} {2} (Account: {3}) : {4}", user.Id, user.Firstname, user.Lastname, user.AccountId, user.Email));
}
}
}
In normal procedural code, this wouldn't be a problem. However, the only Post method available on the httpClient was PostAsync. Being fairly new to the async/await stuff, I'm not sure the ramifications on the rest of my code ... particularly as it relates to my attempt to reuse the httpClient instead of instantiating a new one for each http call.
I'm not sure what happens with await when its wrapped in a foreach like I have. Will I run into issues with reusing the httpClient to make repeated calls when running asynchronously?
My other question is, what is actually going to be returned. IOW, my understanding is that await returns a Task. However, here, I'm looping through the list and making multiple calls to await PostAsync. My method returns a Task. But which task gets returned? If my calling method needs to wait for completion before moving on, what does its call look like?
private void Process()
{
//Get List
var task = AddMCUsers(list);
task.Wait();
//Subsequent processing
}
I've read that you should use Async all the way. Does this mean my calling method should look more like this?
public async Task Process()
{
//Get list
...
await AddMCUsers(list);
//Other processing
}
Thanks to whatever help you can offer on this.
In normal procedural code, this wouldn't be a problem.
The whole point of async/await is to write asynchronous code in a way that looks practically identical to "normal" synchronous code.
Being fairly new to the async/await stuff, I'm not sure the ramifications on the rest of my code ... particularly as it relates to my attempt to reuse the httpClient instead of instantiating a new one for each http call.
HttpClient was intended to be reused; in fact, it can be used for any number of calls simultaneously.
I'm not sure what happens with await when its wrapped in a foreach like I have.
One way to think of it is that await "pauses" the method until its operation completes. When the operation completes, then the method continues executing. I have an async intro that goes into more detail.
Will I run into issues with reusing the httpClient to make repeated calls when running asynchronously?
No, that's fine.
IOW, my understanding is that await returns a Task.
await takes a Task. It "unwraps" that task and returns the result of the task (if any). If the task completed with an exception, then await raises that exception.
My method returns a Task. But which task gets returned?
The Task returned from an async method is created by the async state machine. You don't have to worry about it. See my intro for more details.
If my calling method needs to wait for completion before moving on, what does its call look like? ... I've read that you should use Async all the way. Does this mean my calling method should look more like this?
Yes, it should look like your second snippet:
public async Task ProcessAsync()
{
//Get list
...
await AddMCUsers(list);
//Other processing
}
The only thing I changed was the Async suffix, which is recommended by the Task-based Asynchronous Pattern.
in your code you should be fine with reusing the HttpClient. What async / await is allow the code to release the execution thread to prevent locking a cpu thread while waiting for the web response. It also releases control back to the caller. When releasing code back to the caller it means that if your Process function does not await your AddMCUsers, Process could finish before AddMCUsers (useful in fire and forget situations to not await a method).
What async/await do not do is affect the logical flow of an individual method. When you await an async web call the execution is paused and then resumed at the same point once the web call returns. There is also thread context tracking and the code resumes in the same context (ie. UI thread or background thread depending on the parent) by default, but this can be changed if needed.
At some point in your code you may want to have a method that blocks until your async code competes and that is where you will want your Task.Wait() call to block execution. If all you use is awaits then it is possible for your program to end before your task competes. See the code example below.
class Program
{
static void Main(string[] args)
{
Task waitForMe = Task.Run(() => waitAsync());
}
static async Task waitAsync()
{
await Task.Delay(5000);
}
}
in the sample with out a Task.Wait call to block the Main method the program will end before the 5 second wait is complete. Having a main method of the following will cause the program to wait for 5 seconds before exiting:
static void Main(string[] args)
{
Task waitForMe = Task.Run(() => waitAsync());
waitForMe.Wait();
}

How to implement call to call ExecuteAsync using RestSharp

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);
}

Categories

Resources