0

Ich entwickle eine Single-Form-App, die auf Knopfdruck eine einfache Inventory-Datenbank-API-Abfrage erstellt und jede zurückgegebene ItemID # auf ein entsprechendes Image überprüft kann oder darf nicht bei einer URL bestehen, die aus der ID # gebildet wird. Ich mache das gerade, indem ich HttpWebRequest.Method = "HEAD" -Anfragen für jede URL sende und true zurückgebe, bis der catch-Block ausgelöst wird.C# Async Mehrere Webanforderungen an DataTable - Arbeit scheint aus unbekannten Gründen zu stoppen

Die Datenbankabfrage kann 50 - 150 Teilenummern zurückgeben, und das Senden von HEAD-Anforderungen an jede einzelne auf diese Weise dauert etwa 5 Minuten und dies ist nicht produktiv.

Ich versuche, diesen Prozess mit async Multi-Task und warten. Wenn ich auf die Schaltfläche klicke, funktioniert es einwandfrei und lädt Zeilen nacheinander in mein DataGridView mit einer Rate von etwa 2/Sekunde (was nicht schlimm ist, aber ich würde das gerne noch beschleunigen, wenn möglich).

ABER: Nach dem Finden von 2 erfolgreichen URL-Antworten hört es auf, Zeilen zu laden und scheint aufzugeben, aus Gründen, die mir unbekannt sind ??? Und der Block syncContext, der die Benutzeroberfläche wieder aktiviert, wird nie ausgeführt, da die Arbeit nie abgeschlossen wird. Kann jemand sehen, was das verursachen könnte?

Ich habe gearbeitet, basiert weg lose dieses doc:

"Gewusst wie: Erstellen Sie mehrere Web Requests parallel von Asynchron-Verwendung und warten (C#)" https://msdn.microsoft.com/en-us/library/mt674880.aspx

namespace ImageTableTest 
{ 
public partial class ImageTableTestForm : Form 
{ 
    //P21 Authentication Variables 
    private static Token P21token = null; 
    private static RestClientSecurity rcs; 

    //Create Tables and bindingSource 
    DataTable itemDataIMG = new DataTable(); 
    DataTable itemDataNOIMG = new DataTable(); 
    DataTable itemDataComplete = new DataTable(); 
    BindingSource bindingSource = new BindingSource(); 

    private readonly SynchronizationContext synchronizationContext; 


    public ImageTableTestForm() 
    { 
     InitializeComponent(); 

     //Create syncContexct on UI thread for updating UI 
     synchronizationContext = SynchronizationContext.Current; 

     //authenticate database API function 
     authenticateP21();  

     //Designing DataTables 
     itemDataIMG.Columns.Add("MPN#", typeof(string)); 
     itemDataIMG.Columns.Add("IMG", typeof(bool)); 
     itemDataIMG.Columns[1].ReadOnly = true; 

     itemDataNOIMG.Columns.Add("MPN#", typeof(string)); 
     itemDataNOIMG.Columns.Add("IMG", typeof(bool)); 
     itemDataNOIMG.Columns[1].ReadOnly = true; 

     itemDataComplete.Columns.Add("MPN#", typeof(string)); 
     itemDataComplete.Columns.Add("IMG", typeof(bool)); 
     itemDataComplete.Columns[1].ReadOnly = true; 

     //bind to DataGridView itemView 
     bindingSource.DataSource = itemDataComplete;   
     itemView.DataSource = bindingSource; 
     itemView.AutoGenerateColumns = false; 
    } 



    private async void testBtn_Click(object sender, EventArgs e) 
    { 
     //When button is clicked, disable UI and 
     //start background work: 
     testBtn.Enabled = false; 
     loadSpinner.Visible = true; 

     await Task.Run(() => 
     { 
      getItemView(); 
     }); 
    } 


    private async void getItemView() 
    { 
     try 
     { 
      //This executes the query and returns an array of Part objects: 
      PartResourceClient prc = new PartResourceClient(ConfigurationManager.AppSettings["P21.BaseURI"], rcs); 
      prc.QueryFilter("add_to_ebay eq 'Y'"); 
      Part[] pResults = prc.Resource.GetParts();    

      int numParts = pResults.Length;     
      Task<bool>[] taskArray = new Task<bool>[numParts]; 
      bool[] IMGboolArray = new bool[numParts]; 

      //For each part, create CheckImageURL task and add to task Array 
      //Then Await execution 
      for (int i = 0; i < numParts; i++) 
      { 
       taskArray[i] = CheckImageURL(pResults[i].ItemId); 
       IMGboolArray[i] = await taskArray[i]; 
      }     
     } 
     catch (Exception e) 
     { 
      MessageBox.Show(e.ToString()); 
     } 

     //When all Tasks finish, remove loadSpinner, re-enable UI 
     //(This never executes for unknown reasons.) 
     synchronizationContext.Post(new SendOrPostCallback(o => 
     {    
      loadSpinner.Visible = false; 
      testBtn.Enabled = true; 
     }), null); 

     MessageBox.Show("<DONE>"); 
    } 


    async Task<bool> CheckImageURL(string MPN) 
    { 
     //Here I am forming and executing the web HEAD request, 
     //If there is there is a 'NOT FOUND' response it goes to 'catch' block: 
     string URL = "https://s3-us-west-2.amazonaws.com/www.crosscreektractor.com/ebay-images/" + MPN + "_e.png"; 
     HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(URL); 
     request.Method = "HEAD"; 
     try 
     { 
      await request.GetResponseAsync(); 
      synchronizationContext.Post(new SendOrPostCallback(o => 
      { 
       addDataRows(MPN, true); 
      }), null); 

      return true; 
     } 
     catch 
     { 
      synchronizationContext.Post(new SendOrPostCallback(o => 
      { 
       addDataRows(MPN, false); 
      }), null); 

      return false; 
     } 
    } 

    private void addDataRows(string MPN, bool IMG) 
    { 
     //Add data to respective table: 
     if (IMG) 
     { 
      itemDataIMG.Rows.Add(MPN, IMG); 
     } 
     else 
     { 
      itemDataNOIMG.Rows.Add(MPN, IMG); 
     } 

     //Here I am sorting the IMG and NOIMG tables, 
     //then merging them into the Complete table which 
     //The DataGridView is bound to, so that IMG entries are on top: 
     itemDataIMG.DefaultView.Sort = ("MPN# DESC"); 
     itemDataNOIMG.DefaultView.Sort = ("MPN# DESC"); 

     itemDataComplete.Clear(); 
     itemDataComplete.Merge(itemDataIMG); 
     itemDataComplete.Merge(itemDataNOIMG); 
     itemView.Refresh(); 
    } 
+0

Sie sind in TAP verpasst und Asynchron/await . Es ist ein falscher Ansatz, ein aufgabenbasiertes asynchrones Muster zu implementieren und zu verwenden. –

+0

Hamlet, ist es das, was es zum Stillstand bringt, oder wäre es einfach weniger Aufwand, wenn es anders geht? Vielleicht könnten Sie mir Unterlagen zur Verfügung stellen oder mir sagen, welche Zeilen durcheinander geraten sind? – mholberger

+0

google mit Schlüsselwörtern TAP, async/await, aufgabenbasiertes asynchrones Muster. –

Antwort

0

Danke für den Rat auf meinen TAP-Mustern, auf jeden Fall eine Menge über TAP zu lernen.

Die Lösung für mein Problem war die HttpWebRequest Verbindungslimit. Auf den erfolgreichen Anforderungen ist es dann nicht automatisch die Verbindung schließen, und Sie müssen dies tun, indem Sie den WebResponse greifen und Schließen (nur auf den erfolgreichen Verbindungen erforderlich):

WebResponse response = await request.GetResponseAsync(); 
{do stuff} 
response.Close(); 
1

Ändern der getItemView() Methode seine Task Rückkehr, etwa so:

private async Task getItemView() 

Dann anstelleder Verwendungeinfach await dieser Aufruf in den Click-Ereignishandler wie folgt:

await getItemView(); 
+0

Es hört immernoch auf, Zeilen hinzuzufügen, nachdem CheckImageURL() aus irgendeinem Grund zweimal true zurückgibt. – mholberger

+0

Auch wenn ich es auf diese Weise mache, friert die Benutzeroberfläche ein, wenn die Abfrage abgeschlossen wird, also denke ich, dass ich weiter verwenden werde, hole Task.Run() – mholberger

Verwandte Themen