A petición GET corro (algo así):cliente Web de devolución de llamada asincrónica no se llama en ASP.NET MVC
public ActionResult Index(void) {
webClient.DownloadStringComplete += onComplete;
webClient.DownloadStringAsync(...);
return null;
}
veo que onComplete
no es GET invocado hasta después Index()
ha finalizado la ejecución. Veo que onComplete
se invoca en un subproceso diferente desde el que se ejecutó Index
.
Pregunta: ¿Por qué sucede esto? ¿Por qué el subproceso asincrónico de webClient está aparentemente bloqueado hasta que finaliza el proceso de solicitud de subprocesos?
¿Hay una manera de solucionar este problema sin necesidad de iniciar nuevo hilo de ThreadPool
(yo probamos este, y el uso de grupo de subprocesos funciona como se espera. Además de devolución de llamada de webclient ocurre como se espera si DownloadStringAsync se llama a partir de hilos de un ThreadPool).
ASP.NET MVC 3.0, .NET 4.0, MS Cassini servidor web dev (VS 2010)
EDIT: Aquí es un código completo:
public class HomeController : Controller {
private static ManualResetEvent done;
public ActionResult Index() {
return Content(DownloadString() ? "success" : "failure");
}
private static bool DownloadString() {
try {
done = new ManualResetEvent(false);
var wc = new WebClient();
wc.DownloadStringCompleted += (sender, args) => {
// this breakpoint is not hit until after Index() returns.
// It is weird though, because response isn't returned to the client (browser) until this callback finishes.
// Note: This thread is different from one Index() was running on.
done.Set();
};
var uri = new Uri(@"http://us.battle.net/wow/en/character/blackrock/hunt/simple");
wc.DownloadStringAsync(uri);
var timedout = !done.WaitOne(3000);
if (timedout) {
wc.CancelAsync();
// if this would be .WaitOne() instead then deadlock occurs.
var timedout2 = !done.WaitOne(3000);
Console.WriteLine(timedout2);
return !timedout2;
}
return true;
}
catch (Exception ex) {
Console.WriteLine(ex.Message);
}
return false;
}
}
que lo explica. Entonces, ¿WebClient no usa ThreadPool? ¿Cómo hace cola WebClient una solicitud? Lo vadeé con reflector por un tiempo, pero no pude encontrar dónde sucede. –
No está poniendo en cola una solicitud. En realidad, comienza la solicitud en ese momento. Pero después de iniciar la solicitud, DownloadStringAsync() regresará y le permitirá hacer otras cosas mientras se realiza la descarga. ¡Durante la descarga, en realidad no hay ningún hilo presente! Solo saca un hilo de la lista de hilos para avisarte de que se ha completado. – RandomEngy
Ya veo. Entonces, ¿en qué parte del código se invoca la devolución de llamada? Traté de poner Thread.Sleep (10000) antes de regresar de Index, pero la devolución de llamada no se invoca hasta que Index vuelva. Lo que significa que la llamada de devolución de llamada se pone en cola después de la llamada de índice. Tengo curiosidad de cómo sucede eso. Si se llama a la devolución de llamada en CLR ThreadPool, no se debe bloquear mediante el hilo de procesamiento de solicitud GET, ¿o sí? –