Comment annuler une Tâche d'attendre après un délai d'attente

Je suis en utilisant cette méthode pour instancier un navigateur web par programme, accédez à une url et retourne le résultat lorsque le document est terminé.

Comment pourrais-je être en mesure d'arrêter la Task et ont GetFinalUrl() retour null si le document prend plus de 5 secondes à charger?

J'ai vu de nombreux exemples à l'aide d'un TaskFactory mais je n'ai pas été en mesure de l'appliquer à ce code.

 private Uri GetFinalUrl(PortalMerchant portalMerchant)
{
SetBrowserFeatureControl();
Uri finalUri = null;
if (string.IsNullOrEmpty(portalMerchant.Url))
{
return null;
}
Uri trackingUrl = new Uri(portalMerchant.Url);
var task = MessageLoopWorker.Run(DoWorkAsync, trackingUrl);
task.Wait();
if (!String.IsNullOrEmpty(task.Result.ToString()))
{
return new Uri(task.Result.ToString());
}
else
{
throw new Exception("Parsing Failed");
}
}
//by Noseratio - http://stackoverflow.com/users/1768303/noseratio    
static async Task<object> DoWorkAsync(object[] args)
{
_threadCount++;
Console.WriteLine("Thread count:" + _threadCount);
Uri retVal = null;
var wb = new WebBrowser();
wb.ScriptErrorsSuppressed = true;
TaskCompletionSource<bool> tcs = null;
WebBrowserDocumentCompletedEventHandler documentCompletedHandler = (s, e) => tcs.TrySetResult(true);
foreach (var url in args)
{
tcs = new TaskCompletionSource<bool>();
wb.DocumentCompleted += documentCompletedHandler;
try
{
wb.Navigate(url.ToString());
await tcs.Task;
}
finally
{
wb.DocumentCompleted -= documentCompletedHandler;
}
retVal = wb.Url;
wb.Dispose();
return retVal;
}
return null;
}
public static class MessageLoopWorker
{
#region Public static methods
public static async Task<object> Run(Func<object[], Task<object>> worker, params object[] args)
{
var tcs = new TaskCompletionSource<object>();
var thread = new Thread(() =>
{
EventHandler idleHandler = null;
idleHandler = async (s, e) =>
{
//handle Application.Idle just once
Application.Idle -= idleHandler;
//return to the message loop
await Task.Yield();
//and continue asynchronously
//propogate the result or exception
try
{
var result = await worker(args);
tcs.SetResult(result);
}
catch (Exception ex)
{
tcs.SetException(ex);
}
//signal to exit the message loop
//Application.Run will exit at this point
Application.ExitThread();
};
//handle Application.Idle just once
//to make sure we're inside the message loop
//and SynchronizationContext has been correctly installed
Application.Idle += idleHandler;
Application.Run();
});
//set STA model for the new thread
thread.SetApartmentState(ApartmentState.STA);
//start the thread and await for the task
thread.Start();
try
{
return await tcs.Task;
}
finally
{
thread.Join();
}
}
#endregion
}
  • Agréable de voir quelqu'un qui est réellement à l'aide de ce code :), j'ai un autre exemple qui fait une chose similaire avec un délai d'attente: stackoverflow.com/a/21152965/1768303. Recherchez var cts = new CancellationTokenSource(30000).
  • Merci. Avez-vous un exemple de la façon de faire dans une application console, par hasard? Aussi je ne pense pas que webBrowser peut être une variable de classe parce que je suis en cours d'exécution le tout dans un parallèle pour chacun, le parcours des milliers d'URLs
  • J'ai utilisé le code que vous avez suggéré dans mon application console et a obtenu: Système.Le filetage.ThreadStateException: contrôle ActiveX '8856f961-340a-11d0-a96b-00c04fd705a2' ne peut pas être instanciée car le thread actuel n'est pas en single-threaded apartment. Qui, j'imagine, est-ce que la boucle de message thread de travail dans votre autre exemple de code. Qui est ce que je ne pourrais pas obtenir de travail avec le cancellationToken. Aide appréciée. Je vais continuer d'essayer.
  • Il semble que non seulement il a besoin pour s'exécuter sur un thread STA, mais aussi besoin d'une boucle de message travailleur à: stackoverflow.com/a/19737374/1768303
InformationsquelleAutor Dan Cook | 2014-03-07