2009-08-08 27 views
8

WebClient sınıfını bir denetleyici eyleminin içinden harici bir web servisine basit bir çağrı yapmak için kullanan bir ASP.NET MVC uygulamasına sahibim.WebClient'i ASP.NET MVC içinde eşzamansız olarak mı kullanıyorsunuz?

Şu anda, eşzamanlı çalışan bir DownloadString yöntemini kullanıyorum. Dış web hizmetinin yanıt vermediği sorunlarla karşılaştım, bu da tüm ASP.NET uygulamamın iş parçacığı açılmış ve yanıt vermiyor olmasına neden oluyor.

Bu sorunu düzeltmenin en iyi yolu nedir? Bir DownloadStringAsync yöntemi var, ancak denetleyiciden bunu nasıl arayacağımı bilmiyorum. AsyncController sınıfını kullanmam gerekir mi? Öyleyse, AsyncController ve DownloadStringAsync yöntemi nasıl etkileşir? Yardım için

teşekkürler.

cevap

7

AsyncControllers kullanarak, istek iş parçacığı işleme kapalı yük olarak burada yardımcı olacaktır düşünüyorum.

I (this article açıklandığı gibi olay deseni kullanılarak) Böyle bir şey kullanmak istiyorum:

public class MyAsyncController : AsyncController 
{ 
    // The async framework will call this first when it matches the route 
    public void MyAction() 
    { 
     // Set a default value for our result param 
     // (will be passed to the MyActionCompleted method below) 
     AsyncManager.Parameters["webClientResult"] = "error"; 
     // Indicate that we're performing an operation we want to offload 
     AsyncManager.OutstandingOperations.Increment(); 

     var client = new WebClient(); 
     client.DownloadStringCompleted += (s, e) => 
     { 
      if (!e.Cancelled && e.Error == null) 
      { 
       // We were successful, set the result 
       AsyncManager.Parameters["webClientResult"] = e.Result; 
      } 
      // Indicate that we've completed the offloaded operation 
      AsyncManager.OutstandingOperations.Decrement(); 
     }; 
     // Actually start the download 
     client.DownloadStringAsync(new Uri("http://www.apple.com")); 
    } 

    // This will be called when the outstanding operation(s) have completed 
    public ActionResult MyActionCompleted(string webClientResult) 
    { 
     ViewData["result"] = webClientResult; 
     return View(); 
    } 
} 

Ve emin olun (Global.asax.cs olarak) mesela ne gerek yolları kurulumu,:

public class MvcApplication : System.Web.HttpApplication 
{ 
    public static void RegisterRoutes(RouteCollection routes) 
    { 
     routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 

     routes.MapAsyncRoute(
      "Default", 
      "{controller}/{action}/{id}", 
      new { controller = "Home", action = "Index", id = "" } 
     ); 
    } 
} 
+0

Webclient async çağrısı için bir zaman aşımı eklemenin bir yolu var mı? –

+1

Sadece bir not, bu cevap MVC 1.0 gün içinde geri 09 gibi görünüyor. Şimdi MVC 2/3 ile cevap farklıdır. MapAsyncRoute yöntemi gitti ve artık gerekmiyor. Ayrıca, MyAction yönteminin şimdi MyActionAsync olarak yeniden adlandırılması gerekiyor.Aksi takdirde, her şey aynı şekilde çalışır. – BFree

3

DownloadStringAsync yöntemi, bittiğinde DownloadStringCompleted'u yükselterek bir olay modeli kullanır. Ayrıca, WebClient.CancelAsync() numaralı telefonu arayarak çok uzun sürüyorsa isteği durdurabilirsiniz. Bu, ana istek iş parçacığınızın ve WebClient iş parçacığının paralel olarak çalışmasına izin verir ve ana iş parçacığının ne kadar süre sonra dönmesini beklemeniz gerektiğine karar vermenizi sağlar.

Aşağıdaki örnekte, indirme işlemini başlattık ve tamamlandığında başlatılmasını istediğiniz olay işleyicisini ayarlıyoruz. DownloadStringAsync hemen geri döner, böylece isteğimizin geri kalanını işleme devam edebiliriz.

Bu işlem üzerinde daha ayrıntılı bir denetim göstermek için, denetleyici eylemimizin sonuna ulaştığımızda, indirme işleminin tamamlanıp tamamlanmadığını kontrol edebiliriz; değilse, 3 saniye daha verin ve sonra iptal edin.

string downloadString = null; 

ActionResult MyAction() 
{ 
    //get the download location 
    WebClient client = StartDownload(uri); 
    //do other stuff 
    CheckAndFinalizeDownload(client); 
    client.Dispose(); 
} 

WebClient StartDownload(Uri uri) 
{ 
    WebClient client = new WebClient(); 
    client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(Download_Completed); 
    client.DownloadStringAsync(uri); 
    return client; 
} 

void CheckAndFinalizeDownload(WebClient client) 
{ 
    if(this.downloadString == null) 
    { 
     Thread.Sleep(3000); 
    } 
    if(this.downloadString == null) 
    { 
     client.CancelAsync(); 
     this.downloadString = string.Empty; 
    } 
} 

void Download_Completed(object sender, DownloadStringCompletedEventArgs e) 
{ 
    if(!e.Cancelled && e.Error == null) 
    { 
     this.downloadString = (string)e.Result; 
    } 
} 
+0

Bu yaklaşımın yine de istek iş parçacığını engelleyeceğine inanıyorum - yine de Uyku çağrınız sırasında istek iş parçacığısınız. Async denetleyicileri, dış kaynağı beklerken isteği iş parçacığını serbest bıraktıkları için burada yardımcı olacaktır. –

+0

@Michael gerçekten. Bu yaklaşım, WebClient isteğinin, denetleyici iş parçacığının yapması gereken her şeyi yapmasıyla bitmediği sürece istek iş parçacığına paralel olarak çalışacaktır - bu noktada denetleyici, engellemeyi/uyumaya ya da devam etmeyi seçer. Sorunun özellikle AsyncController'ın nasıl kullanılacağıyla ilgili olduğunu, ancak WebClient'in eşzamansız çalışmasını nasıl sağlayacağı izlenimini almadım. Bu sorunun yanlış okunması olabilir. –

+0

@Rex Evet, web uygulamasının açıklamasının "iş parçacığı açılmış ve yanıt vermiyor" şeklindeki açıklamasından dolayı, OP'nin istek iş parçacıklarının tükendiğine inanıyorum. Dış yanıtı 3 saniyeliğine sınırlamak biraz yardımcı olacaktır (eğer dış talepleriniz bundan daha uzun sürüyorsa), ancak iş parçacığını tutmak için çok uzun bir süre vardır ve bu yüzden ölçeklenmeyecektir. –