events v.s. async methods using TaskCompletionSource - c#

I am currently implementing an application protocol library relying on TCP/IP for transport (long lasting connection).
I am trying to achieve a nice asynchronous implementation relying on TAP pattern using C#5 async/await constructs, mainly to put into practice the concepts I have only seen in theory up until now.
The client can connect to a remote server and send requests to it.
client receives response from the server as well as requests (full duplex mode).
From the point of view of the client code, the asynchronous call to my library to send a request to the server and receive the associated response is as simple as :
var rsp = await session.SendRequestAsync(req);
From inside my protocol library, I am just buliding the request, converting it to bytes (to be sent on the network stream) and I call WriteAsync on the stream and I then await on a Task created just before sending the request, making use of a TaskCompletionSource object, which is basically waiting for the associated response to be received (and setting the result on the tcs), and then return the response to the client caller.
This part seems fine.
Now the "problem" concerns the part where server is sending requests to the client. There are different type of requests that the server can send to the client.
My protocol library is using an asynchronous loop to listen to the underlying stream (receiving incoming responses or requests from the server).
This loop is reading responses/requests asynchronously on the stream, then in case of a request from the server, it raises an event corresponding to the request type (such as ReceivedRequestTypeA). The client code can subscribe to these events to be notified when a specific request type is received from the server. The event args of these contains all the parameters associated with the request as well as a response object, to be set by the client, which will be asynchronously sent on the stream by library once event handler code is completed.
The code for the asynchronous listen loop is as follow. Please do not mind the while true, not very pretty (cancelation pattern should be used instead), but this is not the point !
private async Task ListenAsync()
{
while(true)
{
Request req = await ReadRequestAsync();
await OnReceivedRequest(req);
}
}
So the loop is calling the asynchronous method ReadRequestAsync which is just reading some bytes asynchronously in the stream until a complete request or response is available.
Then it forwards the request to the asynchronous method OnReceivedRequest which code can be seen below :
private async Task OnReceivedRequest(Request req)
{
var eventArgs = new ReceivedRequestEventArgs { Req = req };
if (req is RequestTypeA)
{ ReceivedRequestTypeA(this, eventArgs); }
[... Other request types ...]
await SendResponseAsync(eventArgs.Resp);
}
This asynchronous method raise the appropriate request type event.
The client code is subscribed to this event, so its appropriate event handler method is called ... the client code does whatever it needs with the request and then construct a response and set it in the EventArgs object -end of event handler method-. The code resumes in OnReceivedRequest in the library, and the response is sent asynchronously (calling WriteAsync on the underlying stream).
I don't think this is a good approach, as it can completely block the asynchronous loop in the library if the event handler code on client side is doing a lengthy blocking operation (bye bye fully asynchronous protocol library, you are now becoming somehow synchronous due to client code). The same would happened if I was using an asynchronous task based delegate for events and awaiting on it.
I was thinking that instead of using events, I could have an asynchronous method GetRequestTypeAAsync() which would be implemented using TaskCompletionSource object in library, and the tcs result being set with the request in OnReceivedRequest. And on client code side, instead of subscribing to ReceivedRequestTypeA event, the code would rather consist of a loop arround GetRequestTypeAAsync(). Still as the client code must somehow provide a response to the library to be sent to server, I don't know how this could work ...
My brain is completely fuzzy right now and can't really think clear. Any suggestion for a nice design will be greatly appreciated.
Thanks !

I'm also working on async/await TCP/IP sockets, and I strongly recommend you take a look at TPL Dataflow. It's pretty easy to make async-friendly endpoints using two BufferBlocks (one for reads and one for writes).
In my system, the TCP/IP socket wrapper exposes a simple ISourceBlock<ArraySegment<byte>> representing the raw reads. This is then linked to a TransformManyBlock which performs message framing, and from there it can be linked to a TransformBlock which parses the bytes into actual message instances.
This approach works best if you have a RequestType base class from which all your other message types inherit. Then you can have a single receiving task that just (asynchronously) receives RequestType message instances from the end of the dataflow pipeline.

Related

Is there a way to wait for the execution of a consumer in MassTransit?

In MassTransit if you want to await the execution of a consumer so that you can get the response there is IRequestClient<TCommand> which has a method GetResponse<TResponse>(Command). Is that the only way you can await the execution of a consumer in MassTransit?
What I want to be able to say is after publishing did the consumer execute successfully or did it error out if it errored out I want to be able to notify interested parties that the command errored out.
It is the easiest way, yes. If you have a method that needs to publish/send a message and wait (via await, in this case) for a consumer to consume the message, using the request client creates a unique RequestId and specifies the response address so that the consumer can notify the requestor via a response.
If you're really more interested in knowing if there was an exception consuming the message, you can create a separate consumer that consumes Fault<TCommand>. If the consumer throws an exception, MassTransit will publish a fault message of this type which can then be consumed to deal with the exception.
Note that if the request client is used, faults are only sent back to the response address and are not published.
Beyond those basic capabilities, sagas may also be used to orchestrate the original message, faults, etc. if so required.

Calling async methods from a WCF service

I want to call asynchronous methods from a WCF service, something like:
[ServiceContract]
interface IService
{
[OperationContract]
int SomeMethod(int data);
}
int SomeMethod(int data)
{
var query = ... build LINQ query;
var response = await query.ToListAsync();
return response.Length;
}
I don't want to add async to the IService interface or SomeMethod method. Using asynchronous methods is an internal issue that shouldn't be reflected in the interface.
How can I do that?
CLARIFICATION:
My problem here is using await in a non-async method. I don't want the service contract to change (the client doesn't necessarily know what async is), and I don't want to split the method into BeginSomeMethod and EndSomeMethod. I want one method that uses await internally.
Whether the server is using sync or async code does not matter for the client. Client and server are separated by a well-specified wire-protocol (often SOAP). SOAP has no notion of asynchronous completion.
You can have a sync server and an async client, or vice versa. The client cannot even detect whether the server is sync or async. This is an implementation detail. The server could be a wrist watch running Linux and you still couldn't tell.
The style of IO you use is an implementation detail and does not influence the bytes that go over the network.
So pick what you like. The client can still use async IO to access the server.
I'm not sure why this is such a surprise to people. In other contexts this seems very intuitive: You can have a asynchronous TCP server and a synchronous client. I can say new WebClient().DownloadString(url) and download a string synchronously from a web-server that is implemented in an asynchronous way. I cannot even tell what server software is running.
Use Fiddler to look at what goes over the wire when you make a WCF call. There is no notion of synchronous or asynchronous calls.
Under the hood, when you invoke a service asynchronously, the WCF client library using TCP sockets in an asynchronous way. When you invoke synchronously, TCP sockets are being used with blocking calls. That's the entire difference.
WCF generated clients can be made to have asynchronous methods in addition to the synchronous methods. Select the "Generate asynchronous operations" option in the UI. Now you have both versions. Both fully functional.
Here's how you can convince yourself of this with an experiment: Write a sync server, and call it both sync and async from the same .NET client. Now write a 2nd server asynchronously (in any style you like) and use the exact same client code to call it.
Task and IAsyncResult are not serializable over SOAP anyway so it cannot possibly be the case that a Task is transmitted to the client.

How to create Async ActionResult to create async-await pattern for following polling logic?

I have a loop that actually waits for some process for completion of a Job and returns result.
I have MyRestClient.FetchResult(id) and MyRestClient.FetchResultAsync(id) both available to me, which fetches result from some remote service and returns boolean value if it is complete.
public class StatusController: ActionController {
public ActionResult Poll(long id){
return new PollingResult(()=>{
return MyRestClient.FetchResult(id) == SomethingSuccessful;
});
}
}
public class PollingResult : ActionResult{
private Func<bool> PollResult;
public PollingResult(Func<bool> pollResult){
this.PollResult = pollResult;
}
public override void ExecuteResult(ControllerContext context)
{
Response = context.HttpContext.Response;
Request = context.HttpContext.Request;
// poll every 5 Seconds, for 5 minutes
for(int i=0;i<60;i++){
if(!Request.IsClientConnected){
return;
}
Thread.Sleep(5000);
if(PollResult()){
Response.WriteLine("Success");
return;
}
// This is a comet, so we need to
// send a response, so that browser does not disconnect
Response.WriteLine("Waiting");
Response.Flush();
}
Response.WriteLine("Timeout");
}
}
Now I am just wondering if there is anyway to use Async Await to improve this logic because this thread is just waiting for every 5 seconds for 5 minutes.
Update
Async Task pattern usually finishes all work before sending result back to client, please note, if I do not send intermediate responses back to client in 5 seconds, client will disconnect.
Reason for Client Side Long Poll
Our web server is on high speed internet, where else clients are on low end connection, making multiple connections from client to our server and then relaying further to third party api is little extra overhead on client end.
This is called Comet technology, instead of making multiple calls in duration of 5 seconds, keeping a connection open for little longer is less resource consuming.
And of course, if client is disconnected, client will reconnect and once again wait. Multiple HTTP connections every 5 seconds drains battery life quicker compared to single polling request
First, I should point out that SignalR was designed to replace manual long-polling. I recommend that you use it first, if possible. It will upgrade to WebSockets if both sides support it, which is more efficient than long polling.
There is no "async ActionResult" supported in MVC, but you can do something similar via a trick:
public async Task<ActionResult> Poll()
{
while (!IsCompleted)
{
await Task.Delay(TimeSpan.FromSeconds(5));
PartialView("PleaseWait").ExecuteResult(ControllerContext);
Response.Flush();
}
return PartialView("Done");
}
However, flushing partial results goes completely against the spirit and design of MVC. MVC = Model, View, Controller, you know. Where the Controller constructs the Model and passes it to the View. In this case you have the Controller is directly flushing parts of the View.
WebAPI has a more natural and less hackish solution: a PushStreamContent type, with an example.
MVC was definitely not designed for this. WebAPI supports it but not as a mainstream option. SignalR is the appropriate technology to use, if your clients can use it.
Use Task.Delay instead of Thread.Sleep
await Task.Delay(5000);
Sleep tells the operating system to put your thread to sleep, and remove it from scheduling for at least 5 seconds. As follows, the thread will do nothing for 5 secs - that's one less thread you can use to process incoming requests.
await Task.Delay creates a timer, which will tick after 5 seconds. The thing is, this timer doesn't use a thread itself - it simply tells the operating system to signal a ThreadPool thread when 5 seconds have passed.
Meanwhile, your thread will be free to answer other requests.
update
For your specific scenario, it seems there's a gotcha.
Normally, you'd change the surrounding method's signature to return a Task/Task<T> instead of void. But ASP.NET MVC doesn't support an asynchronous ActionResult (see here).
It seems your options are to either:
move the async code to the controller (or to another class with an async-compatible interface)
Use a WebAPI controller, which seems to be a good fit for your scenario.
I have a video encoding in process with third party cloud api, however
my web client (chrome/ie/ff) need to poll result of encoding. If I
simply pass on result for every 5 seconds, web client will need to
make multiple HTTP calls one after another
I think the approach when you're trying to poll the result of the video encoding operation within the boundaries of a single HTTP request (i.e., within your ASP.NET MVC controller method) is wrong.
While you're doing the polling, the client browser is still waiting for your HTTP response. This way, the client-side HTTP request may simple get timed out. It is also a not-so-user-friendly behavior, the user is not getting any progress notifications, and cannot request the cancellation.
I've recently answer a related question about long-running server side operation. IMO, the best way of dealing with it is to outsource it to a WCF service and use AJAX polling. I also answered another related question on how to do the asynchronous long-polling in a WCF service.

Cancel async web service calls

I need to be able to cancel async calls made to my webservice. One solution I have is to use manage my own threads, and use synchronous methods from the SOAP client. This works fine and it needs some more fine grained thread management.
If I used any of these two patterns provided from adding a web service reference, say:
var Client = new ASL_WS.SvcSoapClient()
IAsyncResult result = Client.BeginAuthenticateUser(Email, Password, new AsyncCallback(AuthCompleted));
or
var Client = new ASL_WS.SvcSoapClient()
Client.AuthenticateUserCompleted += AuthCompleted;
Client.AuthenticateUserAsync(Email, Passsword);
do any of these two patterns give me a way of cancelling the request? One use case could be: a user logs in, but wants to cancel before the authenticate call completes.
Of course, I could implement this differently by modifying the asyncState passed to these calls, and setting it to disable UI update, but it's not what I'm looking for.
Could I just just cancel all outstanding operations. Does Client.Abort() cancel such operations. What if there are many async requests, are all cancelled? Are there any other API methods that can do this?
Yes, you can use Abort method but keep below notes in mind. You can also use CancelAsync.
Abort notes: http://msdn.microsoft.com/en-us/library/aa480512.aspx
When you call the Abort method, any outstanding requests will still complete, but they will complete with a fault. This means that if you are using callbacks, your callback function will still be called for each outstanding request . When the EndInvoke method is called, or in our case, the wrapper function EndDelayedResponse, then a fault will be generated indicating that the underlying connection has been closed.
CancelAsync example: http://www.codeproject.com/KB/cpp/wsasync.aspx

How to set Async Page Directive Dynamically so Async Methods work

I am writing some Utility code to send off emails Async.
var mailClient = new SmtpClient(smtpHost);
mailClient.SendCompleted += new SendCompletedEventHandler(mailClient_SendCompleted);
using (var mailMessage = new MailMessage())
{
if (!((System.Web.UI.Page)HttpContext.Current.CurrentHandler).IsAsync)
{
// set to Async????
}
mailClient.SendAsync(mailMessage, new { EmailID });
}
But I get errors because my Pages don't have Async="true" in the page directives.
here is the standard error that you get:
"Asynchronous operations are not allowed in this context. Page starting an
asynchronous operation has to have the Async attribute set to true and an
asynchronous operation can only be started on a page prior to
PreRenderComplete event."
I read this: (last paragraph )
http://msdn.microsoft.com/en-us/magazine/cc163725.aspx
A final point to keep in mind as you
build asynchronous pages is that you
should not launch asynchronous
operations that borrow from the same
thread pool that ASP.NET uses. For
example, calling
ThreadPool.QueueUserWorkItem at a
page's asynchronous point is
counterproductive because that method
draws from the thread pool, resulting
in a net gain of zero threads for
processing requests. By contrast,
calling asynchronous methods built
into the Framework, methods such as
HttpWebRequest.BeginGetResponse and
SqlCommand.BeginExecuteReader, is
generally considered to be safe
because those methods tend to use
completion ports to implement
asynchronous behavior.
Questions:
1) How can I update the page to be Async in my c# code?
2) If I can't what is the down side with forcing all my pages to be Async=true?
3) Is there an even better way to thread my task without being "counterproductive"?
How many different pages do you need to send mail from?
Also, what error did you get when you tried to send async? Please edit your question to contain the entire exception.
Consider creating a single (async) page to send email from. You can call that page by using Server.Transfer, and have it redirect back to your desired page when done.
Finally, if you're sending so many emails that you lose performance when sending mail synchronously, then perhaps you should create a Windows Service to send the actual email. Your ASP.NET page would queue a request to this service (through MSMQ, or WCF) to have the service send the email.

Categories