5

Ich möchte mehrere HTTP-Post-Anforderungen an einen Web-Service in C# senden. Zum Beispiel, wenn n = 3 dann HTTP-Anfragen von 3 xml-Dateien gemacht werden sollte und auch die Antwort sollte in einer Datei geschrieben werden. Sobald die ersten 3 Anfragen gemacht werden, werden die nächsten 3 Anfragen gemacht. Also habe ich den folgenden Code gemacht, aber ich bekam zuerst zufällige Ausgaben. Aber jetzt bekomme ich entweder außerhalb der Indexbereich Ausnahme in der inneren for-Schleife oder Interner Serverfehler (500). Plz schlägt entsprechende Änderungen vor. Ich bin mit .NET4.0Multithreading für HTTP-Anfragen an Web-Service

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.IO; 
using System.Threading; 
using System.Xml; 
using System.Net; 
using System.Threading.Tasks; 
namespace ConsoleApplication5 
{ 
class Program 
{ 
    static void Main(string[] args) 
    { 
     int n = 0; 
     Console.WriteLine("Enter the number"); 
     string s = Console.ReadLine(); 
     int.TryParse(s, out n); 
     string path = "C:\\"; 
     string[] files = null; 
     files = Directory.GetFiles(path, "*.xml", SearchOption.TopDirectoryOnly); 


     List<Task> tasks = new List<Task>(files.Length); 

     for (int i = 0; i < files.Length; i += n) 
     { 
      for (int j = 0; j < n; j++) 
      { 
       int x = i + j; 

       if (x < files.Length && files[x] != null) 
       { 
        Task t = new Task(() => function(files[x])); 
        t.Start(); 
        tasks.Add(t); 
       } 
      } 

      if (tasks.Count > 0) 
      { 
       Task.WaitAll(tasks.ToArray(), Timeout.Infinite); // or less than infinite 
       tasks.Clear(); 
      } 
     } 
    } 
    public static void function(string temp) 
    { 
     XmlDocument doc = new XmlDocument(); 
     doc.Load(temp); 
     HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://10.76.22.135/wpaADws/ADService.asmx"); 

     request.ContentType = "text/xml;charset=\"utf-8\""; 
     request.Accept = "text/xml"; 
     request.Method = "POST"; 
     Stream stream = request.GetRequestStream(); 
     doc.Save(stream); 
     stream.Close(); 
     HttpWebResponse response = (HttpWebResponse)request.GetResponse(); 
     using (StreamReader rd = new StreamReader(response.GetResponseStream())) 
     { 
      string soapResult = rd.ReadToEnd(); 
      doc.LoadXml(soapResult); 
      File.WriteAllText(temp, doc.DocumentElement.InnerText); 

      //XmlTextWriter xml=new XmlTextWriter(
      Console.WriteLine(soapResult); 
      Console.ReadKey(); 
     } 

    } 

} 

}

Antwort

3

Dieser Code funktioniert. Erklärung:

  • Zuerst gibt der Benutzer die Quell- und Zielpfade für die XML-Dateien.
  • Directory.getFiles() hilft uns, die .xml-Dateien im String-Array zu erhalten. (wir müssen .xml als Parameter übergeben).

  • SO jetzt, was im Grunde passiert, ist für jede Datei, die wir am Quell-pat bekommen, ein Thread erstellt.

  • Aber sagen, wenn der Benutzer "n" Anfragen zu einem Zeitpunkt senden will, dann werden n Threads auf einmal erstellt.
  • Und die nächste Gruppe von Threads wird nicht erstellt, wenn die vorherigen Threads nicht fertig ausgeführt werden.
  • Dies wird durch thread.Join() sichergestellt.
  • Und nach einer Anfrage an den Web-Service erhalten wir die Antwort von getResponse() und die Antwort wird in .XML-Dateien geschrieben, die auf den Zielpfaden gespeichert sind.

    using System; 
    using System.Collections.Generic; 
    using System.Linq; 
    using System.Text; 
    using System.IO; 
    using System.Threading; 
    using System.Xml; 
    using System.Net; 
    namespace ConsoleApplication4 
    { 
        class Program 
        { 
         int flag = 1; 
         string destination; 
         string source; 
         static void Main(string[] args) 
        { 
        Console.ForegroundColor = ConsoleColor.Red; 
    
        Console.WriteLine("**************************** Send HTTP Post Requests **************************"); 
        int n = 0; 
        Program p = new Program(); 
        Console.WriteLine("Enter the number of requests you want to send at a time"); 
        string s = Console.ReadLine(); 
        int.TryParse(s, out n); 
        Console.WriteLine("Enter Source"); 
        p.source = Console.ReadLine(); 
        Console.WriteLine("Enter Destination"); 
        p.destination = Console.ReadLine(); 
    
        string[] files = null; 
        files = Directory.GetFiles(p.source, "*.xml", SearchOption.TopDirectoryOnly); 
    
        Thread[] thread = new Thread[files.Length]; 
    
        int len = files.Length; 
        for (int i = 0; i<len; i+=n) 
        { 
         int x = i; 
         //Thread.Sleep(5000); 
         for (int j = 0; j < n && x < len; j++) 
         { 
    
          var localx = x; 
          thread[x] = new Thread(() => function(files[localx], p)); 
          thread[x].Start(); 
          Thread.Sleep(50); 
          //thread[x].Join(); 
          x++; 
         } 
         int y = x - n; 
         for (; y < x; y++) 
         { 
          int t = y; 
          thread[t].Join(); 
    
         } 
    
        } 
    
        // thread[0] = new Thread(() => function(files[0])); 
        //thread[0].Start(); 
        Console.ReadKey(); 
    
    } 
    public static void function(string temp,Program p) 
    { 
    
        XmlDocument doc = new XmlDocument(); 
        doc.Load(temp); 
    
        string final_d=p.destination + "response " + p.flag + ".xml"; 
        p.flag++; 
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://10.76.22.135/wpaADws/ADService.asmx"); 
        request.ContentType = "text/xml;charset=\"utf-8\""; 
        request.Accept = "text/xml"; 
        request.Method = "POST"; 
        Stream stream = request.GetRequestStream(); 
        doc.Save(stream); 
        stream.Close(); 
    
        HttpWebResponse response = (HttpWebResponse)request.GetResponse(); 
        using (StreamReader rd = new StreamReader(response.GetResponseStream())) 
        { 
         string soapResult = rd.ReadToEnd(); 
         doc.LoadXml(soapResult); 
         File.WriteAllText(final_d, doc.DocumentElement.InnerText); 
    
         //XmlTextWriter xml=new XmlTextWriter(
         Console.WriteLine(soapResult); 
         //Console.ReadKey(); 
        } 
    } 
    

    } }

1

Wie wäre es Aufgaben wie folgt aus:

List<Task> tasks = new List<Task>(n); 

    for (int i = 0; i < files.Length; i += n) 
    { 
     for (int j = 0; j < n; j++) 
     { 
      int x = i + j; 

      if (x < files.Length && files[x] != null) 
      { 
       Task t = new Task(() => function(files[x])); 
       t.Start(); 
       tasks.Add(t); 
      } 
     } 

     if (tasks.Count > 0) 
     { 
      Task.WaitAll(tasks.ToArray(), Timeout.Infinite); // or less than infinite 
      tasks.Clear(); 
     } 
    } 

Ich versuchte, ein wenig aufgeräumter auf der Indizierung zu sein ...

Beachten Sie auch, dass die int x = i + j; in der inneren Schleife wichtig ist, da C# Variablen für Lambda erfasst.

Wenn das Problem die Indexierungsarithmetik nachführt, verwenden Sie möglicherweise Indexierungsvariablen mit sinnvollen Namen?

List<Task> tasks = new List<Task>(taskCount); 

    for (int filesIdx = 0; filesIdx < files.Length; filesIdx += taskCount) 
    { 
     for (int tasksIdx = 0; tasksIdx < taskCount; tasksIdx++) 
     { 
      int index = filesIdx + tasksIdx; 

      if (index < files.Length && files[index] != null) 
      { 
       Task task = new Task(() => function(files[index])); 
       task.Start(); 
       tasks.Add(task); 
      } 
     } 

     if (tasks.Count > 0) 
     { 
      Task.WaitAll(tasks.ToArray(), Timeout.Infinite); // or less than infinite 
      tasks.Clear(); 
     } 
    } 
+0

Fehler 'System.Threading.Tasks.Task' enthält keine Definition für 'Run' ich diese Störung erhalte. Gleiches gilt für die Verzögerung. –

+0

Oh, ich sehe, dass Sie dotnet 4 verwenden ... Entschuldigung. Ich werde in einer Minute bearbeiten. –

+0

Ich habe den Code bearbeitet, um dotnet 4 zu unterstützen (ich habe ursprünglich für dotnet 4.5 geschrieben). –

2

Die IndexOutOfRangeException Sie in Ihrer ursprünglichen Post erfahren waren aufgrund des unsachgemäßen Index für die letzte Charge von Dateien verarbeiten Sie wurden verarbeitet. Die letzte Partie kann unvollständig sein und Sie behandeln, dass als reguläre Partie der Satzgröße

(n = 3 in Ihrem Beitrag)

Da Sie TPL und Tasks in Bewegung sind, schlage ich vor Parallel Programming with Microsoft .NET und die pipeline pattern, die für Ihr Szenario sehr geeignet scheint. Sie können die Leistung von gleichzeitigen Sammlungen und das Erzeuger/Verbraucher-Muster zusammen mit der Pipeline nutzen, wie unten. BlockingCollection stellt das gleichzeitige Hinzufügen von Elementen sicher und der Aufruf BlockingCollection.GetConsumingEnumerable erzeugt einen blockierenden Enumerator für Ihre Sammlung.

const int BUFFER_SIZE = 3; // no concurrent items to process 
const string XML_FOLDER_PATH = "<whatever>"; 


public static void Pipeline() 
{ 
    var bufferXmlFileNames = new BlockingCollection<string>(BUFFER_SIZE); 
    var bufferInputXmlDocuments = new BlockingCollection<XmlDocument>(BUFFER_SIZE); 
    var bufferWebRequests = new BlockingCollection<HttpWebRequest>(BUFFER_SIZE); 
    var bufferSoapResults = new BlockingCollection<string>(BUFFER_SIZE); 

    var f = new TaskFactory(TaskCreationOptions.LongRunning, TaskContinuationOptions.None); 

    // Stage 1: get xml file paths 
    var stage1 = f.StartNew(() => { 
    try 
    { 
    foreach (var phrase in Directory.GetFiles(XML_FOLDER_PATH, "*.xml", SearchOption.TopDirectoryOnly)) 
    { // build concurrent collection 
     bufferXmlFileNames.Add(phrase); 
    } 
    } 
    finally 
    { // no more additions acceptedin 
    bufferXmlFileNames.CompleteAdding(); 
    } 
}); 

    // Stage 2: ProduceInputXmlDocuments(bufferXmlFileNames, bufferInputXmlDocuments) 
    var stage2 = f.StartNew(() => { 
    try 
    { 
    foreach (var xmlFileName in bufferXmlFileNames.GetConsumingEnumerable()) 
    { 
     XmlDocument doc = new XmlDocument(); 
     doc.Load(xmlFileName); 
     bufferInputXmlDocuments.Add(doc);   
    } 
    } 
    finally 
    { 
    bufferInputXmlDocuments.CompleteAdding(); 
    } 
}); 

    // Stage 3: PostRequests(BlockingCollection<XmlDocument> xmlDocs, BlockingCollection<HttpWebRequest> posts) 
    var stage3 = f.StartNew(() => { 
    try 
    { 
    foreach (var xmlDoc in bufferInputXmlDocuments.GetConsumingEnumerable()) 
    { 
     HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://10.76.22.135/wpaADws/ADService.asmx"); 
     request.ContentType = "text/xml;charset=\"utf-8\""; 
     request.Accept = "text/xml"; 
     request.Method = "POST"; 
     // 
     Stream stream = request.GetRequestStream(); 
     xmlDoc.Save(stream); 
     stream.Close(); 
     // 
     bufferWebRequests.Add(request); 
    } 
    } 
    finally 
    { 
    bufferWebRequests.CompleteAdding(); 
    } 
}); 

    // Stage 4: ProcessResponses(bufferWebRequests, bufferSoapResults) 
    var stage4 = f.StartNew(() => 
    { 
    try 
    { 
     foreach (var postRequest in bufferWebRequests.GetConsumingEnumerable()) 
     { 
     HttpWebResponse response = (HttpWebResponse)postRequest.GetResponse(); 
     using (StreamReader rd = new StreamReader(response.GetResponseStream())) 
     { 
      string soapResult = rd.ReadToEnd(); 
      bufferSoapResults.Add(soapResult); 
     } 
     } 
    } 
    finally 
    { 
     bufferSoapResults.CompleteAdding(); 
    } 
    }); 

    // stage 5: update UI 
    var stage5 = f.StartNew(() => 
    { 
    foreach (var soapResult in bufferSoapResults.GetConsumingEnumerable()) 
    { 
     Console.WriteLine(soapResult); 
    } 
    }); 

    // display blocking collection load state, 
    // the number of elements in each blocking collection of the pipeline stages 
    // you can supress this call completely, because it is informational only 
    var stageDisplay = f.StartNew(
    () => 
    { 
     while (true) 
     { 
     Console.WriteLine("{0,10} {1,10} {2,10} {3,10}", bufferXmlFileNames.Count, bufferInputXmlDocuments.Count, bufferWebRequests.Count, bufferSoapResults.Count); 
     //check last stage completion 
     if (stage5.IsCompleted) 
      return; 
     } 
    } 
    ); 
    Task.WaitAll(stage1, stage2, stage3, stage4, stage5); //or 
    //Task.WaitAll(stage1, stage2, stage3, stage4, stage5, stageDisplay); 
} 
+0

Kannst du alle Namespaces nennen, die ich einfügen sollte, denn drei sind viele neue Konzepte für mich in deinem Code –

+0

Ok ich habe die Namespaces ... Kann man die Ausgabe erklären. Ich habe es nicht bekommen. http://prntscr.com/7fbpna http://prntscr.com/7fbp4f Hier sind Screenshots. –

+0

Bearbeitete ursprüngliche Antwort, siehe Kommentare ... –