HTTPCliend Handler on Status code 401 block other Tasks - c#

This is code from my handler:
public class MoeZdravjeStatusCodeHandler : DelegatingHandler
{
public MoeZdravjeStatusCodeHandler(HttpMessageHandler innerHandler) : base(innerHandler) { }
public IMojLekDataStore<Object> MojLekDataStore => DependencyService.Get<IMojLekDataStore<Object>>();
public bool flag=true;
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
HttpResponseMessage response = new HttpResponseMessage();
response = await base.SendAsync(request, cancellationToken);
int status_code = (int)response.StatusCode;
if (response.IsSuccessStatusCode)
{
return response;
}
else if(status_code == 401 && DependencyService.Get<ISharedFunctions>().GetUserValidation() == true )
{
try
{
if (flag)
{
flag = false;
string date = DateTime.Today.ToString("yyyy-MM-dd") + "MoeZdravje";
string password = Helpers.ServiceHelper.HashPassword(date).ToString();
LoginMoeZdravje log = new LoginMoeZdravje();
log.EZBO = DependencyService.Get<ISharedFunctions>().GetPatient().Ezbo.ToString();
log.PASSWORD = password;
log.CONFIRMED_USER = 1;
var response_token = await MojLekDataStore.GetMoeZdravjeToken(log);
if (response_token != null && !String.IsNullOrEmpty(response_token.Token))
{
flag = true;
DependencyService.Get<ISharedFunctions>().SaveMoeZdravjeToken(response_token.Token);
await Application.Current.MainPage.DisplayAlert("", "ВАШИОТ ТОКЕН Е ОСВЕЖЕН", AppResources.BTNOK);
Application.Current.MainPage = new NavigationPage(new MainMenu());
}
else
{
flag = true;
await Application.Current.MainPage.DisplayAlert("", AppResources.SERVER_ERROR, AppResources.BTNOK);
}
}
else
{
CancellationTokenSource source = new CancellationTokenSource();
cancellationToken = source.Token;
source.Cancel();
source.Dispose();
}
}
catch (AggregateException ae)
{
foreach (Exception e in ae.InnerExceptions)
{
if (e is TaskCanceledException)
Console.WriteLine("Unable to compute mean: {0}",
((TaskCanceledException)e).Message);
else
Console.WriteLine("Exception: " + e.GetType().Name);
}
}
finally
{
}
}
return response;
}
I want when come to await MojLekDataStore.GetToken(log); block every async Task until finish this request because with this request i get a new token from my Api and need to save that token and call the requests to get the data with the new token. I have a tabbedPage with 4 async Tasks and this handler called two times for get a new token but i need one and to start work with the new token.
EDIT
I added CancellationTokenSource source = new CancellationTokenSource();
but i dont know if this could stop other 3 async task ? The flag is used when first 401status_code request come .

Related

UI only partly responsive while running tasks and updating ui

i have the following ui -
For each line connection to crm should be tested. This is done in separate thread.
The test status of the connection to crm system is then updated in last column.
The problem is that the ui is only partly reponsive during threads run and updating of the ui, i.e.
i would like to click through the lines whilst updating.
Here is my code:
private async void btnTestAllConnections_Click(object sender, EventArgs e)
{
await TestConnectionsAsync();
}
private async Task TestConnectionsAsync()
{
try
{
int idxConn = columnLookup[ColumnIndex.Connection].Index;
if (lvInitParameters.Items.Count == 0)
return;
ManagedConnection connection = null;
btnTestAllConnections.Visible = false;
btnTestConnection.Visible = false;
panel2.Enabled = false;
panel3.Enabled = false;
tableLayoutPanel1.Enabled = false;
btnCancelTest.Visible = true;
List<Task> tasks = new List<Task>();
var cts = new CancellationTokenSource();
CancellationToken token = cts.Token;
foreach (ListViewItem lvi in lvInitParameters.Items)
{
InitParamProxy currentProfile = (InitParamProxy)lvi.Tag;
lvi.SubItems[idxConn].Text = "Testing...";
Task<bool> result =null;
try
{
result = Task.Run(
() =>
{
try
{
connection = currentProfile.ManagedConnection;
return connection?.ConnectionSuccess ?? false;
}
catch (Exception ex)
{
// crm exception
return false;
}
}, token);
if (token.IsCancellationRequested)
{
Console.WriteLine("\nCancellation requested in continuation...\n");
token.ThrowIfCancellationRequested();
}
ListViewItem testItem =
items.Where(si => ((InitParamProxy)lvi.Tag).ProfileKey.Equals(((InitParamProxy)si.Tag).ProfileKey)).SingleOrDefault();
lvi.SubItems[idxConn].Text = (result.Result) ? "Success" : "Fail";
if (testItem != null)
testItem.SubItems[idxConn].Text = (result.Result) ? "Success" : "Fail";
}
catch
{
ListViewItem testItem =
items.Where(si => ((InitParamProxy)lvi.Tag).ProfileKey.Equals(((InitParamProxy)si.Tag).ProfileKey)).SingleOrDefault();
lvi.SubItems[idxConn].Text = "Canceled";
if (testItem != null)
testItem.SubItems[idxConn].Text = "Canceled";
}
tasks.Add(result);
}
Task.WaitAll(tasks.ToArray());
btnTestAllConnections.Visible = true;
btnTestConnection.Visible = true;
panel2.Enabled = true;
panel3.Enabled = true;
tableLayoutPanel1.Enabled = true;
btnCancelTest.Visible = false;
}
catch (Exception)
{
}
}
In the end of your method you have
Task.WaitAll(tasks.ToArray());
This will block until all tasks are done. You should instead use WhenAll
await Task.WhenAll(tasks.ToArray());
You are also using result.Result in several places, and this also blocks. This should be replaced by awaiting the task, i.e. await result

CancellationToken in Web API not working correctly

I have Web Api which gets CancellationToken from users, the method inside it (DoWork) also get CancellationToken:
[HttpPost]
public async Task<long> GetInfo(CancellationToken cancellationToken)
{
long result = 0;
bool notDone = true;
Task<long> t = Task.Run(async () =>
{
if (cancellationToken.IsCancellationRequested)
cancellationToken.ThrowIfCancellationRequested();
while (notDone && !cancellationToken.IsCancellationRequested)
{
result = await DoWork(cancellationToken);
notDone = false;
}
return result;
}, cancellationToken);
try
{
return await t;
}
catch (AggregateException e)
{
Debug.WriteLine("Exception messages:");
foreach (var ie in e.InnerExceptions)
Debug.WriteLine(" {0}: {1}", ie.GetType().Name, ie.Message);
Debug.WriteLine("\nTask status: {0}", t.Status);
throw;
}
catch (Exception ex)
{
throw;
}
}
private Task<long> DoWork(CancellationToken token)
{
long result = 0;
bool notDone = true;
Task<long> task = Task.Run(() =>
{
if (token.IsCancellationRequested)
token.ThrowIfCancellationRequested();
while (notDone && !token.IsCancellationRequested)
{
Thread.Sleep(8000);
result = 2;
notDone = false;
}
return result;
}, token);
return task;
}
I expect when the user cancels the request it aborts the DoWork method and not continue the function, but after sending an Exception, when "Thread.Sleep" complete, the DoWork method continue.
the user can call the API service like this method "cc" as you can see it cancel after 5 seconds and in the DoWork method "Thread.Sleep" is 9 seconds. the user gets an Exception but the method still running.
private async Task<bool> cc()
{
UriBuilder builder = new UriBuilder("http://localhost:12458/api/Test/GetInfo");
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
HttpClient client = new HttpClient();
System.Threading.CancellationTokenSource s = new System.Threading.CancellationTokenSource();
s.CancelAfter(5000);
try
{
var result = client.PostAsJsonAsync<model1>(builder.ToString(), new model1 { }, s.Token).Result;
string tmp = result.Content.ReadAsStringAsync().Result;
long ApiResult = JsonConvert.DeserializeObject<long>(tmp);
}
catch (TaskCanceledException ex)
{
}
catch (OperationCanceledException ex)
{
}
catch (Exception ex)
{
}
finally
{
s.Dispose();
}
return false;
}
When use Thread.Sleep(8000) actually hold the main thread for 8 seconds and It can't check the cancellation token. you should use Task.Delay with cancellation token like this:
while (notDone && !token.IsCancellationRequested)
{
await Task.Delay(8000, token);
result = 2;
notDone = false;
}
Task.Delay check the cancellation token itself.
Ok, in your code you should process CancellationToken.IsCancellationRequested too. It's not kinda of magic, you should do this work.
public void DoWork(CancellationToken ctsToken)
{
ctsToken.ThrowIfCancellationRequested();
DoSomething();
ctsToken.ThrowIfCancellationRequested();
DoSomethingElse();
// end so on with checking CancellationToken before every part of work
}
And your Task should look like this
Task<long> t = Task.Run(async () =>
{
cancellationToken.ThrowIfCancellationRequested();
result = await DoWork(cancellationToken);
notDone = false;
cancellationToken.ThrowIfCancellationRequested();
return result;
}, cancellationToken);
In my case it was because of fiddler. When I closed the fiddler app, it started working like a charm.

Correct way of starting a forever-running loop with Async

I've an existing code I wrote some time ago, that works but I dislike the fact that the thread I start remains in loop.
This piece of code is a consumer on an IBMMQ code, waiting for messages to be processed.The problem I've is that with the following code
private Task ExecuteQueuePolling(CancellationToken cancellationToken)
{
return Task.Factory.StartNew(() =>
{
ConnectToAccessQueue();
Logger.Debug($"Accessed to the queue {queueName}");
Logger.DebugFormat("Repeating timer started, checking frequency: {checkingFrequency}",
checkingFrequency);
while (!cancellationToken.IsCancellationRequested)
{
Logger.Trace( () => "Listening on queues for new messages");
// isChecking = true;
var mqMsg = new MQMessage();
var mqGetMsgOpts = new MQGetMessageOptions
{ WaitInterval = (int)checkingFrequency.TotalMilliseconds };
// 15 second limit for waiting
mqGetMsgOpts.Options |= MQC.MQGMO_WAIT | MQC.MQGMO_FAIL_IF_QUIESCING |
MQC.MQCNO_RECONNECT_Q_MGR | MQC.MQOO_INPUT_AS_Q_DEF;
try
{
mqQueue.Get(mqMsg, mqGetMsgOpts);
if (string.Compare(mqMsg.Format, MQC.MQFMT_STRING, StringComparison.Ordinal) == 0)
{
var text = mqMsg.ReadString(mqMsg.MessageLength);
Logger.Debug($"Message received : [{text}]");
Message message = new Message { Content = text };
foreach (var observer in observers)
observer.OnNext(message);
}
else
{
Logger.Warn("Non-text message");
}
}
catch (MQException ex)
{
if (ex.Message == MQC.MQRC_NO_MSG_AVAILABLE.ToString())
{
Logger.Trace("No messages available");
//nothing to do, emtpy queue
}
else if (ex.Message == MQC.MQRC_CONNECTION_BROKEN.ToString())
{
Logger.ErrorException("MQ Exception, trying to recconect", ex);
throw new ReconnectException();
}
}
Thread.Sleep(100);
}
},cancellationToken);
}
//Calling method
try
{
string queueManagerName = configuration.GetValue<string>("IBMMQ:QUEUE_MANAGER_NAME");
// var queueManager = new MQQueueManager(queueManagerName,dictionary2);
QueueMonitor monitor = new QueueMonitor(configuration, "IMPORTER_RECEIVER_TEST");
//_subscription = monitor.Subscribe(receiver);
await monitor.StartAsync(cts.Token).ConfigureAwait(false);
}
catch (Exception e)
{
log.Error(e, "Error creating the queue monitor or it's subscription");
}
finally
{
WaitForCancel(cts);
}
The call to await monitor.StartAsync(cts.Token).ConfigureAwait(false); remains pending.
How should I modify my code, so that the call returns and in background the task continue to loop?
Thanks in advance
Here is how you can simplify your code by replacing Thread.Sleep with Task.Delay:
private async Task ExecuteQueuePolling(CancellationToken cancellationToken)
{
while (true)
{
// Process mqQueue here
await Task.Delay(100, cancellationToken);
}
}
Task.Delay has the advantage that accepts a CancellationToken, so in case of cancellation the loop will exit immediately. This could be important if the pooling of the MQ was lazier (for example every 5 seconds).
private static Task _runningTask;
static void Main(string[] args)
{
var cts = new CancellationTokenSource();
_runningTask = ExecuteQueuePolling(cts.Token);
WaitForCancel(cts);
}
private static void WaitForCancel(CancellationTokenSource cts)
{
var spinner = new SpinWait();
while (!cts.IsCancellationRequested
&& _runningTask.Status == TaskStatus.Running) spinner.SpinOnce();
}
private static Task ExecuteQueuePolling(CancellationToken cancellationToken)
{
var t = new Task(() =>
{
while (!cancellationToken.IsCancellationRequested)
; // your code
if (cancellationToken.IsCancellationRequested)
throw new OperationCanceledException();
}, cancellationToken, TaskCreationOptions.LongRunning);
t.Start();
return t;
}

UI hangs when multiple httpclient or httpresponse sent

trying to get page source from list of urls. but it hangs the UI. i would prefer httpclient so i can use single instance. please let me know what can i do so it wont hang the ui during the process.
async Task AccessTheWebAsync(CancellationToken ct)
{
HttpClient client = new HttpClient();
List<string> urlToSearch = UrlToSearchList();
IEnumerable<Task<string>> downloadTasksQuery =from url in urlToSearch select ProcessURL2(url, client, ct);
List<Task<string>> downloadTasks = downloadTasksQuery.ToList();
while (downloadTasks.Count > 0)
{
Task<string> firstFinishedTask = await Task.WhenAny(downloadTasks);
downloadTasks.Remove(firstFinishedTask);
string length = await firstFinishedTask;
resultsTextBox.Text += $"\r\nLength of the download: {length}";
}
}
private List<string> UrlToSearchList()
{
var urlToSearchList = new List<string>();
foreach (var item in lbURLToSearch.Items)
{
urlToSearchList.Add(item.ToString());
}
return urlToSearchList;
}
async Task<string> ProcessURL2(string url, HttpClient client, CancellationToken ct)
{
HttpResponseMessage response = await client.GetAsync(url, ct);
var contents = await response.Content.ReadAsStringAsync();
return contents;
}
private void CancelButton_Click(object sender, EventArgs e)
{
if (cts != null)
{
cts.Cancel();
}
}
private async void StartButton_Click(object sender, EventArgs e)
{
resultsTextBox.Clear();
cts = new CancellationTokenSource();
try
{
await AccessTheWebAsync(cts.Token);
resultsTextBox.Text += "\r\nDownloads complete.";
}
catch (OperationCanceledException)
{
resultsTextBox.Text += "\r\nDownloads canceled.\r\n";
}
catch (Exception)
{
resultsTextBox.Text += "\r\nDownloads failed.\r\n";
}
cts = null;
}
i also tried various async methods. still same result, it hangs. below is one of the async method i tried.
private async void TsbtnStartURLScraper_Click(object sender, EventArgs e)
{
for (int i = 0; i < lbURLToSearch.Items.Count; i++)
{
txtScrapeURL.Text = lbURLToSearch.Items[i].ToString();
string urlAddress = lbURLToSearch.Items[i].ToString();
var returnedresult = await DownloadStringV1(urlAddress);
resultsTextBox.Text += returnedresult;
}
}
public async Task<String> DownloadStringV1(String url)
{
// good code
var request = await reusableHTTPClient.GetAsync(url);
var download = await request.Content.ReadAsStringAsync();
return download;
}
NOTE: what i am trying to do is, loop through a list of url and get page source from them. but when i am doing this it is freezing the form.

Set time of Activity.Typing animation

I'm trying to create some animation during the time when I fetch the data from a server. "Typing" activity seems to be reasonable but it works only for ~4 seconds :
Activity reply = activity.CreateReply();
reply.Type = ActivityTypes.Typing;
reply.Text = null;
ConnectorClient connector = new ConnectorClient(new Uri(activity.ServiceUrl));
await connector.Conversations.ReplyToActivityAsync(reply);
I was trying to do async listening:
while (!_fetchEnded)
{
await connector.Conversations.ReplyToActivityAsync(reply);
Thread.Sleep(3000);
}
But bot it creates laggy behaviour. Is there a possibility to set the duration of "typing" activity or another way around to prevent turning the typing on and off?
Typing is displayed only a few seconds by default. You can force the display typing indicator longer by sending again typing events at a lower frequency.
Implementation example, where it will send events every 2 seconds, for 30 seconds max:
public async Task<HttpResponseMessage> Post([FromBody]Microsoft.Bot.Connector.Activity activity, CancellationToken token)
{
// Send Typing messages
var typingCancellation = new CancellationTokenSource(TimeSpan.FromSeconds(30));
var typingTask = SendTypingActivityUntilCancellation(activity, TimeSpan.FromSeconds(2), typingCancellation.Token);
try
{
// Activity treatment
if (activity.Type == ActivityTypes.Message)
{
// ...
}
else if (activity.Type == ActivityTypes.Event && activity.ChannelId == ChannelEnum.directline.ToString())
{
// ...
}
typingCancellation.Cancel();
await typingTask;
return Request.CreateResponse(HttpStatusCode.OK);
}
catch (Exception e)
{
typingCancellation.Cancel();
await typingTask;
return Request.CreateResponse(HttpStatusCode.InternalServerError);
}
}
public async Task SendTypingActivityUntilCancellation(Activity activity, TimeSpan period, CancellationToken cancellationtoken)
{
try
{
var connector = new ConnectorClient(new Uri(activity.ServiceUrl));
Activity isTypingReply = activity.CreateReply();
isTypingReply.Type = ActivityTypes.Typing;
do
{
if (cancellationtoken.IsCancellationRequested == false)
{
await connector.Conversations.ReplyToActivityAsync(isTypingReply);
}
// Check again if token has not been canceled during the reply delay
if (cancellationtoken.IsCancellationRequested == false)
{
await Task.Delay(period);
}
}
while (cancellationtoken.IsCancellationRequested == false);
}
catch (OperationCanceledException)
{
//nothing to do.
}
}

Categories