Can I get rid of this horrible blocking code? - c#

I need some help, In a web api service call, I need to call a function in a dll that executes asynchronously, and then gives the response in a call back function. Now normally this would be good , but now with a web api the idea is to execute the command and then return the response.
Below is my current code which works, but I think its terrible code, its everything you don't want to do. Especially on a web server when this code is going to run for every request.
[HttpGet]
public HttpResponseMessage Off(string id)
{
APNLink.Link link = LinkProvider.getDeviceLink(id, User.Identity.Name);
if (link.LinkConnectionStatus == APNLink.ConnectionStatus.Connected)
{
link.RelayCommand(APNLink.RelayNumber.Relay1, APNLink.RelayCommand.OFF, test);
BlockForResponse();
var msg = Request.CreateResponse(HttpStatusCode.OK);
return msg;
}
else
{
if (link.Connect())
{
var status = link.LinkConnectionStatus;
int timeout = 0;
while (status != APNLink.ConnectionStatus.Connected)
{
Thread.Sleep(500);
status = link.LinkConnectionStatus;
if (status == APNLink.ConnectionStatus.Connected)
{
break;
}
if (timeout++ > 16)
{
var msg1 = Request.CreateResponse(HttpStatusCode.RequestTimeout);
return msg1;
}
}
link.RelayCommand(APNLink.RelayNumber.Relay1, APNLink.RelayCommand.OFF, test);
BlockForResponse();
var msg = Request.CreateResponse(HttpStatusCode.OK);
return msg;
}
else
{
var msg2 = Request.CreateResponse(HttpStatusCode.BadRequest);
return msg2;
}
}
}
bool flag = false;
public void test(bool var)
{
flag = true;
}
private static bool BlockForResponse()
{
int count = 0;
while (!flag)
{
Thread.Sleep(500);
if (count > 10)
{
//timeout
return false;
}
}
return true;
}
now the thing is I have to block when waiting for the dll, Connection to be connected, only then can I execute the command. once I have executed the command. I then have to block again for the response.
Another aspect is, Can I actually block on an asp.net thread? Surely each request is not handled on its own thread?
Is there any way I can make this code neater and most importantly more efficient?

Answering the question:
In a web api service call, I need to call a function in a dll that
executes asynchronously, and then gives the response in a call back
function.
IMO, the best way of doing this is to make your controller method asynchronous and use TaskCompletionSource to wrap the callback of your DLL. Some good additional reads:
Using Asynchronous Methods in ASP.NET MVC 4.
The Nature of TaskCompletionSource<TResult>.
The code may look something like this:
[HttpGet]
public async Task<HttpResponseMessage> Off(string id)
{
APNLink.Link link = LinkProvider.getDeviceLink(id, User.Identity.Name);
if (link.LinkConnectionStatus == APNLink.ConnectionStatus.Connected)
{
var tcs = new TaskCompletionSource<object>();
CallbackType test = delegate {
tcs.SetResult(null);
};
link.RelayCommand(
APNLink.RelayNumber.Relay1,
APNLink.RelayCommand.OFF,
test);
// BlockForResponse();
await tcs.Task; // non-blocking
var msg = Request.CreateResponse(HttpStatusCode.OK);
return msg;
}
// ...
}

Related

Await for Task in C# not returing

I am having an issue with the below code. In Debug it runs to the }); part after return true but never returns to the calling method. The below methods should connect to a zebra printer, send the ZLP code print and check the status after to ensure printing was successful. Then return true or false (will add exception handling after) and if true commit to the database the values printed.
private Boolean printLabel(string productName, double productWeight, String customerLabelType, String scaleNumber, String packageDate, String lotNumber, String barCode)
{
string s = dao.getCustomerLabel(customerLabelType);
s = s.Replace("<<<product_weight>>>", productWeight.ToString());
s = s.Replace("<<<product type>>>>", productName);
s = s.Replace("<<<barcode>>>", barCode);
s = s.Replace("<<<Packed Date:>>>", packageDate);
s = s.Replace("<<<Lot Number:>>>", lotNumber);
// RawPrinterHelper.SendStringToPrinter("ZDesigner GX420d", s);
string ipAddress = dao.getPrinterIp(scaleNumber);
try
{
return PrintOneLabelTask(ipAddress, s).Result;
}
catch (Exception ex)
{
}
return false;
}
private async Task<Boolean> PrintOneLabelTask(string theIpAddress, String ZPL_STRING)
{
await Task.Run(() =>
{
// Instantiate connection for ZPL TCP port at given address
Connection thePrinterConn = new TcpConnection(theIpAddress, TcpConnection.DEFAULT_ZPL_TCP_PORT);
ZebraPrinter printer = PrintHelper.Connect(thePrinterConn, PrinterLanguage.ZPL);
PrintHelper.SetPageLanguage(printer);
if (PrintHelper.CheckStatus(printer))
{
PrintHelper.Print(printer, ZPL_STRING);
if (PrintHelper.CheckStatusAfter(printer))
{
Console.WriteLine($"Label Printed");
}
}
printer = PrintHelper.Disconnect(printer);
Console.WriteLine("Done Printing");
return true;
});
return false;
}
When you return from a lambda expression, you are exiting the lambda expression and returning control to PrintOneLabelTask. You are not returning from PrintOneLabelTask at all. So in your code, the PrintOneLabelTask method will always return false.
You need to capture the result and return that instead.
private async Task<Boolean> PrintOneLabelTask(string theIpAddress, String ZPL_STRING)
{
bool result = false;
await Task.Run(() =>
{
// Instantiate connection for ZPL TCP port at given address
Connection thePrinterConn = new TcpConnection(theIpAddress, TcpConnection.DEFAULT_ZPL_TCP_PORT);
ZebraPrinter printer = PrintHelper.Connect(thePrinterConn, PrinterLanguage.ZPL);
PrintHelper.SetPageLanguage(printer);
if (PrintHelper.CheckStatus(printer))
{
PrintHelper.Print(printer, ZPL_STRING);
if (PrintHelper.CheckStatusAfter(printer))
{
Console.WriteLine($"Label Printed");
}
}
printer = PrintHelper.Disconnect(printer);
Console.WriteLine("Done Printing");
result = true;
});
return result;
}
Note: There are probably some other problems in your code... e.g., I don't see any possible scenario where the method will return false.
You seem to be experiencing a deadlock caused by the SynchronizationContext of your framework.
When you access Result of the Task<bool> returned from PrintOneLabelTask, you are blocking the current thread until that task is completed.
The Task<bool> is returned as soon as you hit await Task.Run(() =>: Task.Run returns another Task that will complete once the provided delegate has run to completion on the ThreadPool.
However, if your SynchronizationContext schedules continuations back onto the calling thread, it will attempt to resume PrintOneLabelTask on a thread that is already being blocked by Result.
There is your deadlock.
The solution
PrintOneLabelTask isn't really asynchronous at all; it is a synchronous method that is being run on the ThreadPool.
This isn't a problem as such, but it can lead to unmaintainable code with issues like the one you are currently experiencing.
The method should be written as the synchronous operation it is:
private void PrintOneLabel(string theIpAddress, string ZPL_STRING)
{
// Instantiate connection for ZPL TCP port at given address
Connection thePrinterConn = new TcpConnection(theIpAddress, TcpConnection.DEFAULT_ZPL_TCP_PORT);
ZebraPrinter printer = PrintHelper.Connect(thePrinterConn, PrinterLanguage.ZPL);
PrintHelper.SetPageLanguage(printer);
if (PrintHelper.CheckStatus(printer))
{
PrintHelper.Print(printer, ZPL_STRING);
if (PrintHelper.CheckStatusAfter(printer))
{
Console.WriteLine($"Label Printed");
}
}
printer = PrintHelper.Disconnect(printer);
Console.WriteLine("Done Printing");
}
(The method should also be void rather than bool because there is no situation where false could be returned).
Then call the method synchronously:
try
{
PrintOneLabel(ipAddress, s);
return true;
}
catch (Exception ex)
{
}
return false;
If you are building an app that has a UI thread, and this now causes your UI to freeze, then decide to offload to the ThreadPool at the highest level possible (usually an event handler):
public async void YourEventHandler(object sender, EventArgs e)
{
//...
bool result = await Task.Run(() => printLabel(//...
//...
}

How to run angular code synchronously like I would in c#

I am trying to recreate a C# app with Angular, but I am struggling to get the code to run synchronously as it would in c#.
Here is an example:
private void doChecks()
{
if (isInvoiced())
return;
Console.WriteLine("Done");
}
private bool isInvoiced()
{
var invID = Server.GetInvoice(mAccID);
if (invID <= 0)
return false;
else
return someOtherFunction(invID);
}
When I try implementing this in Angular I am not sure how to accomplish the same flow without resorting to async await methods.
async doChecks() {
const doAllChecks = await this.service.DoChecks(this.mAcc).toPromise();
if (await this.isInvoiced()) {
return;
}
Console.log("Done");
}
async isInvoiced() {
const invID = await this.service.GetInvoice(this.mAcc).toPromise();
if (invID <= 0)
return false;
else {
const data = await someOtherFunction(invID); // now this function is also going to have to be async to I can await inside of that for its http request to finish.
return data;
}
}
Is there a way to accomplish this in a simpler way ?
You could run it one after the other inside "then statement". Nested Promises. If you are using Angular 2 and above, you can try nesting your logic in subscribers instead of promises.
this.MyPromise1().then(result => {
this.MyPromise2().then(result2 => {
this.MyPromise3().then(result3 => {
and so on..
})
})
});

Mixing async-await with fire-and-forget approach

I'm writing a websocket server using .NET's HttpListener class.
Essentially, I've got a HandleListener() function which wait for clients to connect and yield each client to HandleClient(WebSocket client). So I currently have:
private async void HandleListener()
{
try
{
while (listener != null && listener.IsListening)
{
HttpListenerContext listenerContext = await listener.GetContextAsync();
WebSocketContext webSocketContext = await listenerContext.AcceptWebSocketAsync(subProtocol: null);
WebSocket webSocket = webSocketContext.WebSocket;
clients.Add(webSocket);
await HandleClient(webSocket);
}
}
catch (HttpListenerException) { } // Got here probably because StopWSServer() was called
}
private async Task HandleClient(WebSocket client) { ... }
Problem is, I can't seem to process more then one client. It looks like the execution of HandleListener() halts as long as the first client is connected.
I tried removing the await from the call to HandleClient(), but I get the "because this call is not awaited..." error. I can make HandleClient() a async void method, but this is not an event handler.
BTW, the reason that HandleClient() is async Task is because it's doing, all over in a loop until the listener is dead:
recieveResult = await client.ReceiveAsync(recievedBuffer, CancellationToken.None);
From what I understand, a fire-and-forget approach is bad overall, and I can't seem to achieve it with async-await implementation. But HandleClient() is a fire-and-forget method, and I don't see any other way of achieving what I need.
EDIT: Added current implementation of HandleClient():
private async Task HandleClient(WebSocket client)
{
try
{
ArraySegment<byte> recievedBuffer = new ArraySegment<byte>(new byte[BUFFER_SIZE]);
while (listener != null && listener.IsListening && client.State == WebSocketState.Open)
{
WebSocketReceiveResult recieveResult;
using (var ms = new MemoryStream())
{
do
{
recieveResult = await client.ReceiveAsync(recievedBuffer, CancellationToken.None);
ms.Write(recievedBuffer.Array, recievedBuffer.Offset, recieveResult.Count);
}
while (!recieveResult.EndOfMessage);
switch (recieveResult.MessageType)
{
case WebSocketMessageType.Close:
RemoveClient(client, WebSocketCloseStatus.NormalClosure, string.Empty);
break;
case WebSocketMessageType.Binary:
RemoveClient(client, WebSocketCloseStatus.InvalidMessageType, "Cannot accept binary frame");
break;
case WebSocketMessageType.Text:
OnRecieve?.Invoke(client, System.Text.Encoding.UTF8.GetString(ms.ToArray()));
break;
}
}
}
}
catch (WebSocketException ex)
{
RemoveClient(client, WebSocketCloseStatus.InternalServerError, ex.Message);
}
}
To prevent compiler warning, use method like this:
public static class TaskExtensions {
public static void Forget(this Task task) {
}
}
then just do
HandleClient(webSocket).Forget()
If you go this route, ensure that you handle all exceptions inside HandleClient somehow (wrap whole thing into try-catch for example). There is nothing inherently "bad" in this approach in this particular case.
Alternative approach would be:
HandleClient(webSocket).ContinueWith(task => {
if (task.IsFaulted && task.Exception != null) {
// handle it here
}
});
awaiting HandleClient is not an option in this case, as you see yourself.
it will do like that because you wrote code for it, my mean to say you wrote method as below.
private async void HandleListener()
{
try
{
while (listener != null && listener.IsListening)
{
HttpListenerContext listenerContext = await listener.GetContextAsync();
WebSocketContext webSocketContext = await listenerContext.AcceptWebSocketAsync(subProtocol: null);
WebSocket webSocket = webSocketContext.WebSocket;
clients.Add(webSocket);
await HandleClient(webSocket);
}
}
catch (HttpListenerException) { } // Got here probably because StopWSServer() was called
}
In this method when it encounter await control will get return to orignal caller ,till you await part got completed and next call start after it.
Check below image this how await and async works
If you just want fire and forget than try like this
private void HandleListener()
{
try
{
while (listener != null && listener.IsListening)
{
HttpListenerContext listenerContext = await listener.GetContextAsync();
WebSocketContext webSocketContext = await listenerContext.AcceptWebSocketAsync(subProtocol: null);
WebSocket webSocket = webSocketContext.WebSocket;
clients.Add(webSocket);
HandleClient(webSocket);
}
}
catch (HttpListenerException) { } // Got here probably because StopWSServer() was called
}
which means dont wait for completion of task

How can I convert a function with a ref paramter to an async function?

I have the following function which I want to convert to an async / non locking function.
Here is the function in its currenc form:
private static void BlockForResponse(ref bool localFlag)
{
int count = 0;
while (!localFlag)
{
Thread.Sleep(200);
if (count++ > 50) // 200 * 50 = 10 seconds
{
//timeout
throw new TimeOutException();
}
}
}
here is my attempt:
private static async Task BlockForResponse(ref bool localFlag)
{
int count = 0;
while (!localFlag)
{
await Task.Delay(200);
if (count++ > 50) // 200 * 50 = 10 seconds
{
//timeout
throw new TimeOutException();
}
}
}
however I get a compile error saying that async functions cant have ref or out parameters. However this is the core functionality of the function.
Is it possible to convert it to an async function?
Explanation of code:
I must admit this is an odd piece of code, let me try an explain what its trying to do:
so there is a 3rd party dll which I need to use. Which provides me with services, I sadly have no control over this dll.
The way it works,
I call a command in the dll providing it a callback function which it calls once it has finished the task.
I can only move on to what I want to do once I have the result from that call. hence the need fro this function.
I make the call to the dll, providing it with a call back function:
private bool _commandFlag = false;
private bool _commandResponse;
public async Task ExecuteCommand(string userId, string deviceId)
{
var link = await LinkProviderAsync.GetDeviceLinkAsync(deviceId, userId);
try
{
//execute command
if (link.Command(Commands.ConnectToDevice, CallBackFunction))
{
BlockForResponse(ref _commandFlag);
return; //Received a response
}
else
{ //Timeout Error
throw new ConnectionErrorException();
}
}
catch (Exception e)
{
throw e;
}
}
private void CallBackFunction(bool result)
{
_commandResponse = result;
_commandFlag = true;
}
The way it works, I call a command in the dll providing it a callback function which it calls once it has finished the task.
Then what you really want is to use TaskCompletionSource<T> to create a TAP method, something similar to this.
public static Task<bool> CommandAsync(this Link link, Commands command)
{
var tcs = new TaskCompletionSource<bool>();
if (!link.Command(command, result => tcs.TrySetResult(result)))
tcs.TrySetException(new ConnectionErrorException());
return tcs.Task;
}
With this extension method in place, your calling code is much cleaner:
public async Task ExecuteCommand(string userId, string deviceId)
{
var link = await LinkProviderAsync.GetDeviceLinkAsync(deviceId, userId);
var commandResponse = await link.CommandAsync(Commands.ConnectToDevice);
}
The problem with combining async and ref is that code inside an async function can run even after the method returns. So, if you did something like:
async Task BlockForResponseAsync(ref bool localFlag)
{
while (!localFlag)
{
...
}
}
void SomeMethod()
{
bool flag = false;
BlockForResponseAsync(ref flag); // note: no await here
}
Then the local variable flag would stop existing after SomeMethod() returned, but BlockForResponseAsync(), which has a reference to that variable, could still be executing. This is why the above code won't compile.
Basically, what you need is a closure, and in C#, ref doesn't create closures, but lambdas do. This means you can write your method like this:
async Task BlockForResponseAsync(Func<bool> localFlagFunc)
{
while (!localFlagFunc())
{
...
}
}
And use it like this:
bool flag = false;
var task = BlockForResponseAsync(() => flag);
// other code here
flag = true;
await task; // to make sure BlockForResponseAsync() completed successfully
This way also indicates your intention better. ref usually means something like: "give me a variable with some value, and I will change that value", which is not what you want here. On the other hand Func<T> means "give me something that I can use retrieve some value, potentially multiple times".

Is it safe to call .ConfigureAwait(false) in finally block?

I have a "rest client" that wraps HttpClient and whose methods are async.
Besides other reasons, I need to control signin/signout process with my rest client so that number of sessions is not exceeded.
The rest client implements IDisposable and upon disposing the client I need to check if the client is "still signed in" and sign out if it is.
Since doing any kind of external calls in Dispose method is considered bad practice, I have something as following
public class MappingsController : RestController
{
[HttpGet]
public async Task<HttpResponseMessage> GetYears()
{
return await ProcessRestCall(async rc => await rc.GetYearsAsync());
}
}
public class RestController : ApiController
{
protected async Task<HttpResponseMessage> ProcessRestCall<T>(Func<RestClient, Task<T>> restClientCallback)
{
RestClient restClient = null;
try
{
var credentials = GetCredentialsFromRequestHeader();
if (credentials == null)
{
return Request.CreateErrorResponse(HttpStatusCode.Unauthorized, "Missing credentials from header!");
}
var username = credentials["Username"];
var password = credentials["Password"];
restClient = new RestClient(username, password);
var authenticated = await restClient.SignInAsync();
if (!authenticated)
{
return CreateErrorResponseWithRestStatus(HttpStatusCode.Unauthorized, restClient);
}
var result = await restClientCallback(restClient);
// Following works, but since I need to do it in finally block in case exception happens, perhaps It should be done in finally anyways...
//await restClient.SignOutAsync();
var response = Request.CreateResponse(HttpStatusCode.OK, result);
return response;
}
catch (Exception e)
{
return CreateErrorResponseWithRestStatus(HttpStatusCode.BadRequest, restClient, e);
}
finally
{
if (restClient != null)
{
if (restClient.IsSignedIn)
{
//var signedOutOk = restClient.SignOutAsync();//.Result; //<-- problem - this blocks!!!
restClient.SignOutAsync().ConfigureAwait(false); // seems to work, but I am not sure if this is kosher + I can't get return var
//Logger.Warn(CultureInfo.InvariantCulture, m => m("Client was still signed in! Attempt to to sign out was {0}", signedOutOk ? "successful" : "unsuccessful"));
}
restClient.Dispose();
}
}
}
}
The use of .ConfigureAwait(false) is a non-issue. You aren't awaiting on the task at all. Since you don't await it, it doesn't matter what await is configured to do.
What you're doing is just basic fire and forget (which may or may not be acceptable for you).
You should remove the ConfigureAwait(false) no matter what, just because it does nothing and is confusing to the reader. If it's okay for you to send the request to sign out but not actually sign out, then this is okay.
If you need to ensure that restClient.Dispose(); isn't called until the sign out request returns, then you have a bit of a...problem. The problem stems from the fact that the sign out request might be unsuccessful, or much worse, it might not respond at all. You'd need some way of dealing with that.
You can't use await in a finally block, but you can more or less mimic its behavior through continuations. You may need to do something like this:
public static async Task DoStuff()
{
IDisposable disposable = null;
try { }
finally
{
var task = GenerateTask();
var continuation = Task.WhenAny(task, Task.Delay(5000))
.ContinueWith(t =>
{
if (task.IsCompleted) //if false we timed out or it threw an exception
{
var result = task.Result;
//TODO use result
}
disposable.Dispose();
});
}
}
Note that since you aren't using await the task returned from DoStuff will indicate that it is "done" as soon as it hits the finally block for the first time; not when the continuation fires and the object is disposed. That may or may not be acceptable.

Categories

Resources