2009-08-03 22 views
15

¿Hay un método alrededor de esas pruebas si 2 URL son iguales, es decir, apuntan al mismo lugar? No estoy hablando de alrededor de 2 direcciones URL con diferentes nombres de dominio que apuntan a la misma dirección IP, pero por ejemplo 2 URLs que apunten a la misma página .aspx:Compruebe si 2 URL son iguales

es igual a las siguientes:

Nota/assumtions

  1. Valores de cadena de consulta se ignoran
  2. ASP.NET (C#) Pref
  3. Default.aspx es la página predeterminada

---- ACTUALIZACIÓN ----

Este es un método muy crudo que prueba una URL para ver si coincide con la URL actual: Intenté crear una nueva Uri() con las URL locales y de verificación pero no sé que funciona y bajé la cadena revisando la avenida. La implementación de SiteMapProvider omite este paso si la URL comienza con "Http", ya que supone una URL externa. Como tengo un marco SaaS que siempre asegurará las rutas relativas (ya que pueden estar en diferentes subdominios) es más fácil desmantelar las cosas.

¿Algún comentario sobre la optimización? Supongo que para empezar, podemos pasar una variable que contiene la URL actual. ¿No está seguro de la sobrecarga de llamar a HttpContext.Current.Request.Url.LocalPath muchas veces?

/// <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

Tenga en cuenta, el código anterior no se ha probado y requiere la optimización totalmente. Lo actualizaré a través de pruebas. Cualquier sugerencia bienvenida –

+0

@Mark: Sin embargo, probablemente sería un poco más fácil usar la clase 'Uri'. Todo lo que tendrías que hacer con la cadena es reemplazar '~' con la URL base actual, luego crear objetos 'Uri' a partir de las URL y simplemente hacer una comparación de equivalencia. Eso eliminaría una gran cantidad del código que tienes en tu solución. – JAB

+0

(Básicamente, la clase 'Uri' hace la mayoría si no todas esas técnicas de normalización) – JAB

Respuesta

6

Usted podría estar buscando URL normalization técnicas. Pueden ser un buen punto de partida :)

Una vez que haya normalizado las URL, simplemente necesita verificar si son iguales (tenga en cuenta sus suposiciones, por ejemplo, descarte la cadena de consulta).

+0

He seguido esta ruta, mirando el enlace que proporcionó y, como dice, con los requisitos hace que sea ligeramente más fácil reducir el URL a algo que puedo comparar Creo que una comparación optimizada basada en cuerdas es la solución más eficiente en este caso. Gracias –

+0

... Es por esta razón que estoy marcando esto como la respuesta aceptada. –

1

Tal vez esto tutorial puede ser de ayuda para usted?

"... ¿Quieres ver cómo manejar URL idénticas en el mapa del sitio (que está prohibido por el fuera-de-la-caja 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

Implementé un SiteMapProvider personalizado, y he solucionado este problema para adaptarlo al menú estándar de ASP.NET. En mi caso, estoy implementando un menú personalizado conectado al proveedor del mapa del sitio y, de hecho, quiero la capacidad de resaltar todas las rutas a la misma página. Gracias por la sugerencia. –

+0

@ Made4Print de nada, díganos qué ha solucionado su problema :) – pageman

4

Probablemente podría utilizar la clase Uri para verificar partes individuales de las URL, después de convertir cada una al formato correcto.

// 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

Parece que hará lo que Made4Print quiere. Para referencia adicional: http://msdn.microsoft.com/en-us/library/system.uri.aspx – JAB

+0

sí, estoy ocupado probando esto: if (HttpContext.Current.Request.Url.AbsolutePath == new Uri (tempUrl, UriKind.Absolute) .AbsolutePath) que es muy parecido. Sin embargo, si tengo ~/en mi mapa del sitio, el proveedor todavía está agregando? Z = para mantener las cosas únicas y el URI no puede analizar "~ /? Z = 2", etc. por lo que dice que debe hacer algunas comprobaciones previas. –

+0

¿Hay propiedades que no contienen la cadena de consulta? Puede que tenga que concatenar varias propiedades para obtener un resultado que no contenga la cadena de consulta. Lo siento, no sé mucho más sobre la clase. –

0

¿Qué hay de ver si Server.MapPath es igual para ambas URL? (Suponiendo que se trata de una aplicación ASP.NET, ASP.NET MVC no)

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

Este aspecto es factible, pero sobre la base de que esto es revisar las URL de menú, es decir, podrían ser algunas, ¿podría haber muchos gastos generales aquí? pero investigará. –

-1

francamente, sólo tiene que cargar las direcciones URL y comparar sus contenidos html?

+1

Las URL deben compararse para cada URL en un Menú/Navegación para verificar si es la página actual (para resaltar la página actual) Comparar el contenido sería demasiada sobrecarga. –

9

para que conste, aquí es la traducción de 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 las siguientes pruebas:

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

buen código ...Solo ten cuidado, la normalización de URL no siempre es buena, depende del contexto. Por ejemplo, en su 'Test5AddingTrailing' las dos direcciones se pueden considerar diferentes donde puede señalar dos cosas diferentes. – nawfal

Cuestiones relacionadas