2009-08-03 17 views
15

Esiste un metodo che verifica se 2 URL sono uguali, ovvero puntano allo stesso punto. Non sto parlando di circa 2 URL con diversi nomi di dominio che puntano allo stesso indirizzo IP, ma per esempio 2 URL che puntano alla stessa pagina aspx:Verifica se 2 URL sono uguali

è uguale a questi:

Nota/assumtions

  1. valori QueryString vengono ignorati
  2. ASP.NET (C#) Pref
  3. Default.aspx è la pagina predefinita

---- AGGIORNAMENTO ----

Questo è un metodo molto grezzo che verifica un URL per vedere se corrisponde all'URL corrente: Ho provato a creare un nuovo Uri() con entrambi gli URL locali e di controllo ma non so che funziona e sono andato giù per la stringa controllando viale. L'implementazione di SiteMapProvider ignora questo passaggio se l'URL inizia con "Http" in quanto ciò presuppone un URL esterno. Dal momento che ho un framework SaaS che garantirà sempre percorsi relativi (come questi possono essere su sottodomini diversi) è più facile eliminare le cose.

Eventuali commenti sull'ottimizzazione? Immagino che per cominciare possiamo passare una variabile contenente l'URL corrente? Non sei sicuro dell'overhead di chiamare HttpContext.Current.Request.Url.LocalPath molte volte?

/// <summary> 
    /// Assumes URL is relative aspx page or folder path 
    /// </summary> 
    /// <param name="url"></param> 
    /// <returns></returns> 
    public static bool CurrentURLMatch(string url) 
    { 
     string localURL = HttpContext.Current.Request.Url.LocalPath; 
     if (HttpContext.Current.Request.Url.Host == "localhost") 
     { 
      localURL = localURL.Substring(localURL.IndexOf('/') + 1); 
      localURL = localURL.Substring(localURL.IndexOf('/')); 
     } 
     string compareURL = url.ToLower(); 

     // Remove QueryString Values 
     if (localURL.Contains("?")) 
     { 
      localURL = localURL.Split('?')[0]; 
     } 

     if (compareURL.Contains("?")) 
     { 
      compareURL = compareURL.Split('?')[0]; 
     } 

     if (localURL.Contains("#")) 
     { 
      localURL = localURL.Split('#')[0]; 
     } 
     if (compareURL.Contains("?")) 
     { 
      compareURL = compareURL.Split('#')[0]; 
     } 

     // Prepare End of Local URL 
     if (!localURL.Contains("aspx")) 
     { 
      if (!localURL.EndsWith("/")) 
      { 
       localURL = String.Concat(localURL, "/"); 
      } 
     } 

     // Prepare End of Compare URL 
     if (!compareURL.Contains("aspx")) 
     { 
      if (!compareURL.EndsWith("/")) 
      { 
       compareURL = String.Concat(localURL, "/"); 
      } 
     } 

     if (localURL.EndsWith(@"/")) 
     { 
      localURL = String.Concat(localURL, "Default.aspx"); 
     } 

     if (compareURL.EndsWith(@"/")) 
     { 
      compareURL = String.Concat(compareURL, "Default.aspx"); 
     } 

     if (compareURL.Contains(@"//")) 
     { 
      compareURL = compareURL.Replace(@"//", String.Empty); 
      compareURL = compareURL.Substring(compareURL.IndexOf("/") + 1); 
     } 

     compareURL = compareURL.Replace("~", String.Empty); 

     if (localURL == compareURL) 
     { 
      return true; 
     } 

     return false; 
    } 
+0

Si prega di notare, il codice di cui sopra non è completamente testato e richiede l'ottimizzazione. Lo aggiornerò attraverso i test. Qualsiasi suggerimento benvenuto. –

+0

@Mark: Probabilmente sarebbe un po 'più facile usare la classe 'Uri'. Tutto quello che devi stringere a corda è sostituire '~' con l'attuale URL di base, quindi creare oggetti 'Uri' dagli URL e fare semplicemente un confronto di equivalenza. Questo eliminerebbe molto del codice che hai nella tua soluzione. – JAB

+0

(Fondamentalmente, la classe 'Uri' fa la maggior parte se non tutte quelle tecniche di normalizzazione per te.) – JAB

risposta

6

Si potrebbe essere alla ricerca di URL normalization tecniche. Potrebbero essere un buon punto di partenza :)

Una volta normalizzati gli URL, devi semplicemente verificare se sono uguali (tieni a mente le tue ipotesi, ad esempio, scarti la querystring).

+0

Ho seguito questa rotta, osservando il link che hai fornito e, come dici tu, con i requisiti che rende leggermente più semplice ridurre il URL fino a qualcosa che posso confrontare. Penso che un confronto basato su stringhe ottimizzato sia la soluzione più efficiente in questo caso. Grazie –

+0

... È per questo motivo che sto contrassegnando questo come la risposta accettata. –

1

Forse questo tutorial può essere di aiuto?

"... volete vedere come gestire URL identici nella mappa del sito (che è proibito dalla out-of-the-box SiteMapProvider) ..."

/// <summary> 
/// SiteMap datasources cannot have duplicate Urls with the default provider. 
/// This finds duplicate urls in your heirarchy and tricks the provider into treating 
/// them correctly 
/// </summary> 
private void modifyDuplicateUrls() 
{ 
StringCollection urls = new StringCollection(); 
string rowUrl = String.Empty; 
uint duplicateCounter = 0; 
string urlModifier = String.Empty; 
foreach (DataTable dt in this.DataSource.Tables) 
{ 
foreach (DataRow dr in dt.Rows) 
{ 
rowUrl = (string)dr["Url"]; 
if (urls.Contains(rowUrl)) 
{ 
duplicateCounter++; 
if (rowUrl.Contains("?")) 
{ 
urlModifier = "&instance=" + duplicateCounter.ToString(); 
} 
else 
{ 
urlModifier = "?instance=" + duplicateCounter.ToString(); 
} 
dr["Url"] = rowUrl + urlModifier; 
} 
else 
{ 
urls.Add(rowUrl); 
} 
} 
} 
} 
} 
+1

Ho implementato un SiteMapProvider personalizzato e ho risolto questo problema per adattarlo al menu ASP.NET standard. Nel mio caso sto implementando un menu personalizzato collegato al fornitore di sitemap e voglio davvero la possibilità di evidenziare tutti i percorsi verso la stessa pagina. Grazie per il suggerimento. –

+0

@ Made4Print siete i benvenuti - dicci cosa ti è venuto in mente che ha risolto il tuo problema :) – pageman

4

Probabilmente si potrebbe usare la classe Uri per controllare le singole parti degli URL, dopo averli convertiti nel formato corretto.

// Create the URI objects 
// TODO: Use the right constructor overloads, 
// or do some processing beforehand to accomodate for the different scenarios 
Uri uri1 = new Uri(url1); 
Uri uri2 = new Uri(url2); 

// There are overlaods for the constructor too 
Uri uri3 = new Uri(url3, UriKind.Absolute); 

// Check the correct properties 
// TODO: Use the right properties... 
if (uri1.AbsolutePath == uri2.AbsolutePath) 
{ 
    // Urls match 
} 
+1

Sembra che farà ciò che vuole Made4Print. Per ulteriori riferimenti: http://msdn.microsoft.com/en-us/library/system.uri.aspx – JAB

+0

sì, sono impegnato a provare questo: if (HttpContext.Current.Request.Url.AbsolutePath == nuovo Uri (tempUrl, UriKind.Absolute) .AbsolutePath) che è molto simile. Tuttavia, se ho ~/nella mia sitemap, il provider sta ancora aggiungendo? Z = per mantenere le cose univoche e l'Uri non può analizzare "~ /? Z = 2" ecc. Così come dici tu devi fare dei pre-controlli. –

+0

Esistono proprietà che non contengono la stringa di query? Potrebbe essere necessario concatenare più proprietà per ottenere un risultato che non contiene la stringa di query. Scusa, non ne so molto di più sulla classe. –

0

Che dire se Server.MapPath è uguale per entrambi gli URL? (Supponendo che questa è un'applicazione ASP.NET, non ASP.NET MVC)

if (Server.MapPath(url1).ToLower() == Server.MapPath(url2).ToLower()) 
{ 
    return true; 
} 
else 
{ 
    return false; 
} 
+0

Questo aspetto è fattibile, ma sulla base di ciò si stanno verificando gli URL del menu, cioè potrebbero essere pochi, potrebbero esserci molti overhead qui? ma indagherà. –

-1

francamente, basta caricare gli URL e confrontare i loro contenuti html?

+1

Gli URL devono essere confrontati per ogni URL in un Menu/Navigazione per verificare se è la pagina corrente (per evidenziare la pagina corrente) Confrontando il contenuto sarebbe troppo sovraccarico. –

9

per la cronaca, ecco la traduzione di http://en.wikipedia.org/wiki/URL%5Fnormalization a C#:

using System; 
using System.Web; 

namespace UrlNormalizationTest 
{ 
    public static class UrlNormalization 
    { 
     public static bool AreTheSameUrls(this string url1, string url2) 
     { 
      url1 = url1.NormalizeUrl(); 
      url2 = url2.NormalizeUrl(); 
      return url1.Equals(url2); 
     } 

     public static bool AreTheSameUrls(this Uri uri1, Uri uri2) 
     { 
      var url1 = uri1.NormalizeUrl(); 
      var url2 = uri2.NormalizeUrl(); 
      return url1.Equals(url2); 
     } 

     public static string[] DefaultDirectoryIndexes = new[] 
      { 
       "default.asp", 
       "default.aspx", 
       "index.htm", 
       "index.html", 
       "index.php" 
      }; 

     public static string NormalizeUrl(this Uri uri) 
     { 
      var url = urlToLower(uri); 
      url = limitProtocols(url); 
      url = removeDefaultDirectoryIndexes(url); 
      url = removeTheFragment(url); 
      url = removeDuplicateSlashes(url); 
      url = addWww(url); 
      url = removeFeedburnerPart(url); 
      return removeTrailingSlashAndEmptyQuery(url); 
     } 

     public static string NormalizeUrl(this string url) 
     { 
      return NormalizeUrl(new Uri(url)); 
     } 

     private static string removeFeedburnerPart(string url) 
     { 
      var idx = url.IndexOf("utm_source=", StringComparison.Ordinal); 
      return idx == -1 ? url : url.Substring(0, idx - 1); 
     } 

     private static string addWww(string url) 
     { 
      if (new Uri(url).Host.Split('.').Length == 2 && !url.Contains("://www.")) 
      { 
       return url.Replace("://", "://www."); 
      } 
      return url; 
     } 

     private static string removeDuplicateSlashes(string url) 
     { 
      var path = new Uri(url).AbsolutePath; 
      return path.Contains("//") ? url.Replace(path, path.Replace("//", "/")) : url; 
     } 

     private static string limitProtocols(string url) 
     { 
      return new Uri(url).Scheme == "https" ? url.Replace("https://", "http://") : url; 
     } 

     private static string removeTheFragment(string url) 
     { 
      var fragment = new Uri(url).Fragment; 
      return string.IsNullOrWhiteSpace(fragment) ? url : url.Replace(fragment, string.Empty); 
     } 

     private static string urlToLower(Uri uri) 
     { 
      return HttpUtility.UrlDecode(uri.AbsoluteUri.ToLowerInvariant()); 
     } 

     private static string removeTrailingSlashAndEmptyQuery(string url) 
     { 
      return url 
        .TrimEnd(new[] { '?' }) 
        .TrimEnd(new[] { '/' }); 
     } 

     private static string removeDefaultDirectoryIndexes(string url) 
     { 
      foreach (var index in DefaultDirectoryIndexes) 
      { 
       if (url.EndsWith(index)) 
       { 
        url = url.TrimEnd(index.ToCharArray()); 
        break; 
       } 
      } 
      return url; 
     } 
    } 
} 

Con i seguenti test:

using NUnit.Framework; 
using UrlNormalizationTest; 

namespace UrlNormalization.Tests 
{ 
    [TestFixture] 
    public class UnitTests 
    { 
     [Test] 
     public void Test1ConvertingTheSchemeAndHostToLowercase() 
     { 
      var url1 = "HTTP://www.Example.com/".NormalizeUrl(); 
      var url2 = "http://www.example.com/".NormalizeUrl(); 

      Assert.AreEqual(url1, url2); 
     } 

     [Test] 
     public void Test2CapitalizingLettersInEscapeSequences() 
     { 
      var url1 = "http://www.example.com/a%c2%b1b".NormalizeUrl(); 
      var url2 = "http://www.example.com/a%C2%B1b".NormalizeUrl(); 

      Assert.AreEqual(url1, url2); 
     } 

     [Test] 
     public void Test3DecodingPercentEncodedOctetsOfUnreservedCharacters() 
     { 
      var url1 = "http://www.example.com/%7Eusername/".NormalizeUrl(); 
      var url2 = "http://www.example.com/~username/".NormalizeUrl(); 

      Assert.AreEqual(url1, url2); 
     } 

     [Test] 
     public void Test4RemovingTheDefaultPort() 
     { 
      var url1 = "http://www.example.com:80/bar.html".NormalizeUrl(); 
      var url2 = "http://www.example.com/bar.html".NormalizeUrl(); 

      Assert.AreEqual(url1, url2); 
     } 

     [Test] 
     public void Test5AddingTrailing() 
     { 
      var url1 = "http://www.example.com/alice".NormalizeUrl(); 
      var url2 = "http://www.example.com/alice/?".NormalizeUrl(); 

      Assert.AreEqual(url1, url2); 
     } 

     [Test] 
     public void Test6RemovingDotSegments() 
     { 
      var url1 = "http://www.example.com/../a/b/../c/./d.html".NormalizeUrl(); 
      var url2 = "http://www.example.com/a/c/d.html".NormalizeUrl(); 

      Assert.AreEqual(url1, url2); 
     } 

     [Test] 
     public void Test7RemovingDirectoryIndex1() 
     { 
      var url1 = "http://www.example.com/default.asp".NormalizeUrl(); 
      var url2 = "http://www.example.com/".NormalizeUrl(); 

      Assert.AreEqual(url1, url2); 
     } 

     [Test] 
     public void Test7RemovingDirectoryIndex2() 
     { 
      var url1 = "http://www.example.com/default.asp?id=1".NormalizeUrl(); 
      var url2 = "http://www.example.com/default.asp?id=1".NormalizeUrl(); 

      Assert.AreEqual(url1, url2); 
     } 

     [Test] 
     public void Test7RemovingDirectoryIndex3() 
     { 
      var url1 = "http://www.example.com/a/index.html".NormalizeUrl(); 
      var url2 = "http://www.example.com/a/".NormalizeUrl(); 

      Assert.AreEqual(url1, url2); 
     } 

     [Test] 
     public void Test8RemovingTheFragment() 
     { 
      var url1 = "http://www.example.com/bar.html#section1".NormalizeUrl(); 
      var url2 = "http://www.example.com/bar.html".NormalizeUrl(); 

      Assert.AreEqual(url1, url2); 
     } 

     [Test] 
     public void Test9LimitingProtocols() 
     { 
      var url1 = "https://www.example.com/".NormalizeUrl(); 
      var url2 = "http://www.example.com/".NormalizeUrl(); 

      Assert.AreEqual(url1, url2); 
     } 

     [Test] 
     public void Test10RemovingDuplicateSlashes() 
     { 
      var url1 = "http://www.example.com/foo//bar.html".NormalizeUrl(); 
      var url2 = "http://www.example.com/foo/bar.html".NormalizeUrl(); 

      Assert.AreEqual(url1, url2); 
     } 

     [Test] 
     public void Test11AddWww() 
     { 
      var url1 = "http://example.com/".NormalizeUrl(); 
      var url2 = "http://www.example.com".NormalizeUrl(); 

      Assert.AreEqual(url1, url2); 
     } 

     [Test] 
     public void Test12RemoveFeedburnerPart() 
     { 
      var url1 = "http://site.net/2013/02/firefox-19-released/?utm_source=rss&utm_medium=rss&utm_campaign=firefox-19-released".NormalizeUrl(); 
      var url2 = "http://site.net/2013/02/firefox-19-released".NormalizeUrl(); 

      Assert.AreEqual(url1, url2); 
     } 
    } 
} 
+0

buon codice ..Basta fare attenzione, la normalizzazione dell'URL non è sempre una buona cosa, dipende dal contesto. Ad esempio nel tuo 'Test5AddingTrailing' i due indirizzi possono essere considerati diversi in cui può puntare a due cose diverse. – nawfal

Problemi correlati