2009-07-13 116 views
11

我有一個方法,試圖創建一個Uri然後清理它(刪除片段,排除一些域和查詢字符串模式等)。方法是這樣的:Uri.TryCreate拋出UriFormatException?

static public bool TryCreateCleanUri(Uri baseUri, string relstr, out Uri result) 
{ 
    if (!Uri.TryCreate(baseUri, relstr, out result)) 
    { 
     return false; 
    } 
    return CleanupUri(result, out result); 
} 

這種方法一直工作好幾個月。但昨晚它失敗了。 Uri.TryCreate()拋出異常!這裏的堆棧跟蹤:

Uri.TryCreate(Uri, String, out Uri)
ERROR: Unhandled exception caught. Program terminating. 
System.UriFormatException: Invalid URI: The hostname could not be parsed. 
    at System.Uri.CreateHostStringHelper(String str, UInt16 idx, UInt16 end, Flags& flags, String& scopeId) 
    at System.Uri.CreateHostString() 
    at System.Uri.GetComponentsHelper(UriComponents uriComponents, UriFormat uriFormat) 
    at System.Uri.CombineUri(Uri basePart, String relativePart, UriFormat uriFormat) 
    at System.Uri.GetCombinedString(Uri baseUri, String relativeStr, Boolean dontEscape, String& result) 
    at System.Uri.ResolveHelper(Uri baseUri, Uri relativeUri, String& newUriString, Boolean& userEscaped, UriFormatException& e) 
    at System.Uri.TryCreate(Uri baseUri, Uri relativeUri, Uri& result) 
    at System.Uri.TryCreate(Uri baseUri, String relativeUri, Uri& result) 

文檔中說,返回值是True如果成功,否則False,但它是沉默異常。然而,對於Uri.TryCreate(Uri, Uri, out Uri)文檔說:

此方法構造URI,使 它的規範形式,並驗證 它。如果發生未處理的異常,則此方法會捕獲該異常。如果您想要 創建一個Uri並獲得例外使用 Uri構造函數之一。

堆棧跟蹤顯示在Uri.TryCreate(Uri, Uri, out Uri)中引發異常,根據文檔,該異常不應該發生。

這是非常罕見的事件。我一直在使用該代碼數月,通過它運行數十億個URL,直到現在還沒有遇到問題。不幸的是,我不知道是什麼組合導致了這個問題。我希望構建一個顯示錯誤的測試用例。

這是一個已知的錯誤Uri.TryCreate,還是我錯過了什麼?

+0

你知道它試圖解析導致失敗的URL嗎? – 2009-07-13 22:56:58

+0

如果我知道,我會發布它。 – 2009-07-16 23:01:36

+0

使用反射器查找「TryCreate」正在做什麼 – DevinB 2009-07-22 17:48:03

回答

18

不願意等待潛在的幾個月對我的代碼,再遇到這種情況,我花了一些時間與ILDASM弄清楚什麼TryCreate正在做,然後多一點時間想出一個重現錯誤的方法。

Uri.TryCreate(Uri baseUri, Uri relativeUri, out Uri result)中發生崩潰的原因似乎是格式錯誤的baseUri。例如,Uri構造函數允許以下:

Uri badUri = new Uri("mailto:[email protected]@mischel.com"); 

按照RFC爲的mailto:URIs,它們不應該被允許。雖然構造函數創建並返回一個Uri對象,但嘗試訪問(某些)對象的屬性會拋出UriFormatException。例如,給定上面的代碼,這條線將拋出一個異常:

string badUriString = badUri.AbsoluteUri; 

我覺得很有趣的是,Uri類似乎使用兩種不同的分析算法:一是施工過程中使用,以及一個用於獲取內部使用個別組件。

通過此無效UriTryCreate將導致我原來的問題中描述的例外。 TryCreate方法檢查baseUri參數null,但沒有(不能,我會想象)否則驗證它。它必須假設,如果參數非空,傳遞的對象是一個完全初始化和有效的實例。但是在構建結果的某個時候,TryCreate嘗試獲取baseUri的組件,並拋出異常。

我不能說我的程序實際上遇到了這樣格式化的mailto:URL。不過,我可以肯定地說,一個無效的Uri對象是我的程序崩潰的原因,只是因爲我的程序中的異常堆棧跟蹤與測試程序的堆棧跟蹤相匹配。簡而言之,該錯誤位於構造函數Uri(也包含在TryCreate方法中),它允許創建無效的Uri

您可以按照Microsoft Connect上的bug report

3

現在你知道它可能會失敗,讓我們獲得更多的信息:

static public bool TryCreateCleanUri(Uri baseUri, string relstr, out Uri result) 
{ 
    try { 
     if (!Uri.TryCreate(baseUri, relstr, out result)) 
     { 
      return false; 
     } 
    } 
    catch (UriFormatException ex) { 
     throw new InalidOperationException(
      String.Format("Can create URI for base={0}, rel={1}", baseUri.ToString(), relstr), 
      ex); 
    }   
    return CleanupUri(result, out result); 
} 
-1
public static bool CheckUrlValid(string url) 
    { 
     Uri uriResult; 
     bool result = Uri.TryCreate(url, UriKind.Absolute, out uriResult); 
     if(result) 
     { 
      uriResult = new Uri(url); 
      if (uriResult.Scheme == Uri.UriSchemeHttps || uriResult.Scheme == Uri.UriSchemeHttp) 
       return true; 
     } 

     return false; 
    } 
相關問題