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..
})
})
});
Related
I'm coding a function that receives a condition to be met and a time out and it finishes when the condition is met or it times out.
This is what I have so far :
public static bool CheckWithTimeout(bool toBeChecked, int msToWait)
{
//var src = CancellationSource
var task = Task.Run(()=> {
while (!toBeChecked)
{
System.Threading.Thread.Sleep(25);
}
});
if (task.Wait(TimeSpan.FromMilliseconds(msToWait)))
return toBeChecked;
else
return false;
}
It works nice for simple bools but I would like to call it like:
CheckWithTimeout(myValue > 10, 500)
And it would return when myValue is bigger than ten, or 500 ms passed (and returns false in this case)
I checked and I think Func is what I need but.. I cannot find a proper example.
Additionally, if there is an already existing method to achieve this I'd definitely prefer it.
It's better to use separate tasks for the result and the waiting.
private async Task<bool> CheckWithTimeout(Func<bool> toBeChecked, int msToWait)
{
var waitTask = Task.Delay(msToWait);
var checkTask = Task.Run(toBeChecked);
await Task.WhenAny(waitTask, checkTask);
return checkTask.IsCompleted && await checkTask;
}
private async Task<bool> CheckWithTimeout<T>(Predicate<T> toBeChecked, T predicateParameter, int msToWait)
{
var waitTask = Task.Delay(msToWait);
var checkTask = Task.Run(() => toBeChecked(predicateParameter));
await Task.WhenAny(waitTask, checkTask);
return checkTask.IsCompleted && await checkTask;
}
That way you do not nescessary have to wait for the timeout.
(And Taks.Delay is better than Task.Wait because it doesn't block)
Edit: Example with function or predicate
If you use a simple bool parameter, it will be evaluated only once when the method is called. If you want to perform the evaluation multiple times, you need to use Func<bool>:
public static bool CheckWithTimeout(Func<bool> toBeChecked, int msToWait)
{
//var src = CancellationSource
var task = Task.Run(()=> {
while (!toBeChecked())
{
System.Threading.Thread.Sleep(25);
}
});
if (task.Wait(TimeSpan.FromMilliseconds(msToWait)))
return toBeChecked();
else
return false;
}
Now you can use a lambda to call the method:
CheckWithTimeout(() => myValue > 10, 500)
Or just create a method which returns a bool and pass its name in.
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
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".
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;
}
// ...
}
I'm trying to implement this trivial task of listing all objects in an AmazonS3 bucket with paged requests asynchronously in C#4. I have it working in C#5 using the following snippet:
var listRequest = new ListObjectsRequest().WithBucketName(bucketName);
ListObjectsResponse listResponse = null;
var list = new List<List<S3Object>>();
while (listResponse == null || listResponse.IsTruncated)
{
listResponse = await Task<ListObjectsResponse>.Factory.FromAsync(
client.BeginListObjects, client.EndListObjects, listRequest, null);
list.Add(listResponse.S3Objects);
if (listResponse.IsTruncated)
{
listRequest.Marker = listResponse.NextMarker;
}
}
return list.SelectMany(l => l);
I'm calling the BeginListObjects/EndListObjects pair asynchronously, but I have to repeat that call every time the response says it's truncated. This piece of code works for me.
However, I now want to do this in C#4's TPL, where I don't have the luxury of using async/await and want to understand if this can be done using continuations.
How do I do this same thing in C#4?
Okay, so rather than putting the items into a list with each task/continuation it's easier in a non-await model to just have each task/continuation return the entire sequence. Given that, I used the following helper method to add each one's iterative results onto the aggregate total.
public static Task<IEnumerable<T>> Concat<T>(Task<IEnumerable<T>> first
, Task<IEnumerable<T>> second)
{
return Task.Factory.ContinueWhenAll(new[] { first, second }, _ =>
{
return first.Result.Concat(second.Result);
});
}
Next, I used the follow method to take a task of a single result and turn it into a task of a sequence (containing just that one item).
public static Task<IEnumerable<T>> ToSequence<T>(this Task<T> task)
{
var tcs = new TaskCompletionSource<IEnumerable<T>>();
task.ContinueWith(_ =>
{
if (task.IsCanceled)
tcs.SetCanceled();
else if (task.IsFaulted)
tcs.SetException(task.Exception);
else
tcs.SetResult(Enumerable.Repeat(task.Result, 1));
});
return tcs.Task;
}
Note here that you have some fields/locals not defined; I'm assuming you can add them to the appropriate method without difficulty.
private Task<IEnumerable<S3Object>> method(object sender, EventArgs e)
{
ListObjectsResponse listResponse = null;
return Task<ListObjectsResponse>.Factory.FromAsync(
client.BeginListObjects, client.EndListObjects, listRequest, null)
.ToSequence()
.ContinueWith(continuation);
}
Here is where the real magic happens. Basically,
public Task<IEnumerable<S3Object>> continuation(Task<IEnumerable<S3Object>> task)
{
if (task.Result == null) //not quite sure what null means here//may need to edit this recursive case
{
return Task<ListObjectsResponse>.Factory.FromAsync(
client.BeginListObjects, client.EndListObjects, listRequest, null)
.ToSequence()
.ContinueWith(continuation);
}
else if (task.Result.First().IsTruncated)
{
//if the results were trunctated then concat those results with
//TODO modify the request marker here; either create a new one or store the request as a field and mutate.
Task<IEnumerable<S3Object>> nextBatch = Task<ListObjectsResponse>.Factory.FromAsync(
client.BeginListObjects, client.EndListObjects, listRequest, null)
.ToSequence()
.ContinueWith(continuation);
return Concat(nextBatch, task);//recursive continuation call
}
else //if we're done it means the existing results are sufficient
{
return task;
}
}