2016-04-05 13 views
2

この問題の基本的な前提は、Webサービスの可能性のあるデータのリストを持つテキストファイルがあることです。テキストファイルに存在するWebサービスのリストから、各Webサービスで使用可能なWebメソッドを解析し、このデータをExcelシートに公開する必要があります。解析ソリューションの改善

私はあなたのテストデータがどのように見えるかの例をあげる:基本的には、最後の行は、私が使用したいラインです

<Resource Name="APP1"> 
    <Uri UriType="PAGE" ResourceUri="http://exampleurl/default.aspx" /> 
</Resource> 
<Resource Name="App2"> 
    <Uri UriType="PAGE" ResourceUri="http://exampleurl2/example.aspx" /> 
</Resource> 
<Resource Name="App3"> 
    <Uri UriType="PAGE" ResourceUri="http://exampleurl3/exampleapp.asmx" /> 
</Resource> 

を。使用可能なラインの他の例は、

<Resource Name="Example" WSDL="http://example.wsdl"> 
    <Uri UriType="ASMX" ResourceUri="http://example.asmx" /> 
</Resource> 

だから、私は基本的に.asmx.wsdlファイルを探していますされています。私が問題を考えたのは、これらのWebサービスごとにWSDLだけを探すために入力を標準化することでした。したがって、.asmxのURLに対しては?wsdlを追加します。

今、私は解決策の下で実装しました。ソースファイルには何千ものWebサービスがあり、潜在的にn個のWebメソッドがあるため、実行時間は1〜2時間かかることがあります。ランタイムをスピードアップするために、このソリューションをさらに改善できるかどうか疑問に思っています。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.IO; 
using System.Text.RegularExpressions; 
using System.Xml; 
using System.Net; 
using System.Data; 
using ClosedXML.Excel; 

namespace ParseWebservices 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 

      var lines = File.ReadAllText(@"PATH\SourceFIle.xml"); 
      int count = 0; 
      string text = ""; 
      DataTable Webservices= new DataTable(); 
      Webservices.Columns.Add("Wsdl URL"); 
      Webservices.Columns.Add("Webservice Name"); 
      Webservices.Columns.Add("WebMethod"); 

      Regex r = new Regex("(?<=ResourceUri=\")(.*)(.asmx)(?=\")", RegexOptions.IgnoreCase); 
      Match m = r.Match(lines.ToString()); 
      while (m.Success) 
      { 


       try 
       { 

        string[] test = m.ToString().Split('/'); 
        string webservicename = test[test.Length - 1].Replace(".asmx", ""); 
        string wsdlurl=""; 

        var webClient = new WebClient(); 
        string readHtml=""; 
        try 
        { 
         readHtml = webClient.DownloadString(wsdlurl); 
        } 
        catch (Exception excxx) 
        { 
         wsdlurl = m.ToString().Replace(".asmx", ".wsdl"); 
         readHtml = webClient.DownloadString(wsdlurl); 
        } 

        int count2 = 0; 
        string text2 = ""; 
        Regex r2 = new Regex(@"(?<=s:element name\=\"")(.*)(?=Response"")", RegexOptions.IgnoreCase); 
        Match m2 = r2.Match(readHtml); 
        while (m2.Success) 
        { 
         DataRow dr = Webservices.NewRow(); 

         dr[0] = wsdlurl; 
         dr[1] = webservicename; 
         dr[2] = m2.ToString(); 
         Console.WriteLine(wsdlurl + "\n" + webservicename + "\n" + m2.ToString()); 
         Webservices.Rows.Add(dr); 
         count2++; 
         m2 = m2.NextMatch(); 
        } 
        count++; 
        m = m.NextMatch(); 
       } 
       catch (Exception ex) 
       { 
        m = m.NextMatch(); 
       } 
      } 

      XLWorkbook wb = new XLWorkbook(); 
      wb.Worksheets.Add(Webservices, "Example"); 
      wb.SaveAs(@"PATH\example.xlsx"); 
     } 
    } 
} 

私がこのソリューションについて気に入らないことの1つは、例外に依存していることです。正規表現は.asmxの文字列と一致するので、.wsdlという文字列が見つからないことに気付きました。しかし、私はまた、.wsdlを含むソーステキストで、接頭辞.asmxはまったく同じであることに気付きました。だから私はそれらのテストケースのエラー処理を追加しましたが、間違いなく理想的ではありません。

とにかく、私はどのように改善し、より速く(そしてより良いものにする)ための提案に感謝します。

+0

そのドキュメントは完全に有効なXMLのようですが、XDocumentまたはXmlDocumentを使用してデータを解析しようとしましたか?それは非常に大きなファイルを解析する正規表現を使用するよりもはるかに速くなります。 – Gusman

+0

ここで間違ったアプローチをしている可能性があります。入力ファイルがXMLの場合は、正規表現ではなくXMLの解析を調べる必要があります。 –

+0

また、別のスレッドでurlのcreateを連続してチェックするのではなく、これらのurlを消費するキューをparallell – Gusman

答えて

0

あなたの例が有効なXMLであれば、XML解析ソリューションはRegexより簡単に動作することができると思われます。返し

var files = XElement.Parse(xmlString) 
    .Descendants("Resource").SelectMany(resource => 
    { 
     XAttribute wsdlAttribute = resource.Attribute("WSDL"); 
     XAttribute resourceUriAttribute = resource.Element("Uri").Attribute("ResourceUri"); 
     if (wsdlAttribute != null) 
      return new[] { wsdlAttribute.Value, resourceUriAttribute.Value }; 
     else 
      return new[] { resourceUriAttribute.Value }; 
    }).Select(uri => Path.GetFileName(uri)); 

  • default.aspxを
  • example.aspx
  • exampleapp.asmx
  • example.wsdl
  • example.asmx
  • をあなたはのような何かを試みることができます

私はあなたのポストから作成されたテスト用XML文字列を使用:

 string xmlString = 
@"<Root> 
    <Resource Name=""APP1""> 
     <Uri UriType=""PAGE"" ResourceUri=""http://exampleurl/default.aspx"" /> 
    </Resource> 
    <Resource Name=""App2""> 
     <Uri UriType=""PAGE"" ResourceUri=""http://exampleurl2/example.aspx"" /> 
    </Resource> 
    <Resource Name=""App3""> 
     <Uri UriType=""PAGE"" ResourceUri=""http://exampleurl3/exampleapp.asmx"" /> 
    </Resource> 
    <Resource Name=""Example"" WSDL=""http://example.wsdl""> 
     <Uri UriType=""ASMX"" ResourceUri=""http://example.asmx"" /> 
    </Resource> 
</Root>"; 

私はそれはあなたのソリューションよりも高速になることを約束することはできませんが、それをテストすることを歓迎以上です!処理するファイルが複数ある場合は、これをスレッドすることもできます。

+0

私はこれをショットにして、結果を報告します! – user2044754

1

すべてが1つのスレッドで実行されているため、時間がかかります。(xmlか正規表現のどちらが遅いかは関係ありません:すべてのインラインWebリクエストがあなたを遅くしています)

あなたのソースファイルがなければ、 URLのリストを非同期的にロードするためのヘルパー拡張 - これはあなたのコードを囲む必要があります。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.IO; 
using System.Text.RegularExpressions; 
using System.Xml; 
using System.Net; 
using System.Data; 
using System.Collections.Concurrent; 

using System.Threading.Tasks; 

namespace ParseWebservices 
{ 
    static class UrlLoaderExtension 
    { 
    public static async Task<ConcurrentDictionary<string, string>> LoadUrls(this IEnumerable<string> urls) 
    { 
     var result = new ConcurrentDictionary<string,string>();     
     Task[] tasks = urls.Select(url => { 
      return Task.Run(async() => 
      { 
       using (WebClient wc = new WebClient()) 
       { 
        // Console.WriteLine("Thread: " + System.Threading.Thread.CurrentThread.ManagedThreadId); 
        try 
        { 
         var r = await wc.DownloadStringTaskAsync(url); 
         result[url] = r; 
        } 
        catch (Exception err) 
        { 
         result[url] = err.Message; 
        } 
       } 
      }); 
     }).ToArray();     
     await Task.WhenAll(tasks); 
     return result; 
    } 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      var requests = new ConcurrentDictionary<string,string>(); 

      // load desired urls into the structure 
      requests["http://www.microsoft.com"] = null; 
      requests["http://www.google.com"] = null; 
      requests["http://www.google.com/asdfdsaf"] = null; 

      try 
      { 
       Task.Run(async() => 
       { 
        requests = await requests.Keys.LoadUrls(); 
       }).GetAwaiter().GetResult(); 
      } 
      catch (Exception ex) 
      { 
       Console.WriteLine("Error: " + ex.Message); 
       Console.ReadLine(); 
       return; 
      } 

      Console.WriteLine("Finished loading data concurrently"); 
      Console.ReadLine(); 

      // this part is synchronous (it's not waiting for IO) 
      foreach(var url in requests.Keys) 
      { 
       var response = requests[url]; 
       Console.WriteLine(response); // 
       Console.WriteLine("Response from " + url); 
       Console.ReadLine(); 
      } 



      Console.Write("DONE"); 
      Console.ReadLine(); 
     } 
    } 
} 

は、私はあなたがデータをロードできるようになりますどのくらい迅速のアイデアを得るために、このデモにあなたのURLを入れてお勧め:それはすべての回答を持っているとき、それはあなたを伝えるポイントは、それが終わっロードがあります集めました。その後

、あなたはどのように決定した後(非常に!)はるかに速く、これは、その後、あなたはその周りにあなたの他のロジックを埋めるために動機づけされますされて:)

はそれが役に立てば幸い!

+0

@ user2044754これは試してもらえましたか? :) – Nathan

関連する問題