2010-09-29 8 views
15

Sto usando il modulo di IIS 7 Rewrite per riscrivere un URL in ingresso come:ASP.NET MVC UrlHelper.GenerateUrl eccezione: "Non è possibile utilizzare una porta .. per uscire sopra la directory top"

http://server/year/all

a

http://server/application/controller/year/all

Tutto funziona bene, tranne quando, durante l'elaborazione della richiesta riscritto, io uso il metodo di MVC UrlHelper.GenerateUrl():

UrlHelper.GenerateUrl(
    "Assets", 
    "Css", 
    "Asset", 
    new RouteValueDictionary(new { site = site.Name, assetPath = assetPath }), 
    RouteTable.Routes, 
    controllerContext.RequestContext, 
    false); 

chiamata a questo metodo si traduce in un HttpException:

System.Web.HttpException: Cannot use a leading .. to exit above the top directory. 
    at System.Web.Util.UrlPath.ReduceVirtualPath(String path) 
    at System.Web.Util.UrlPath.Reduce(String path) 
    at System.Web.VirtualPath.Combine(VirtualPath relativePath) 
    at System.Web.VirtualPathUtility.Combine(String basePath, String relativePath) 
    at System.Web.Mvc.PathHelpers.GenerateClientUrlInternal(HttpContextBase httpContext, String contentPath) 
    at System.Web.Mvc.PathHelpers.GenerateClientUrl(HttpContextBase httpContext, String contentPath) 
    at System.Web.Mvc.UrlHelper.GenerateUrl(String routeName, String actionName, String controllerName, RouteValueDictionary routeValues, RouteCollection routeCollection, RequestContext requestContext, Boolean includeImplicitMvcValues) 

Guardando il RequestContext, sembra che tutti i percorsi di richiesta sono corrette (vale a dire, hanno i valori riscritti). Non riesco a capire perché stia cercando di uscire dalla directory di primo livello ... Non c'è nessun posto in cui stiamo usando .... in un percorso.

Ho anche assicurato che RewriteModule si trovi sopra il modulo UrlRouting in IIS.

Mentre posso accedere ai metodi framework, non riesco a esaminare nessuna delle variabili locali (in VS o WinDbg) perché è stato ottimizzato per il compilatore.

Qualche idea?

+0

sto affrontando lo stesso problema e non hanno trovato una soluzione. Per ora sono solo i collegamenti ipertestuali hard-coding invece di usare Html.ActionLink dove ottengo l'eccezione. Hai trovato una soluzione? –

+0

@Rob: non abbiamo trovato una soluzione. Sono stato in grado di rintracciare fino alla presenza dell'intestazione X_ORIGINAL_URL nella richiesta. IIS inserisce tale intestazione ogni volta che riscrive un URL. Utilizza quell'intestazione per cercare di annullare la riscrittura dell'URL, poiché probabilmente non si desidera che l'URL generato segua il formato riscritto. Ci viene appeso quando prende in considerazione l'url originale. Non ha molto senso * usare * sempre l'url originale - per noi, vogliamo solo che generi l'url e ignori quello originale. Non c'è modo che abbiamo scoperto di sovrascrivere questo comportamento. –

+0

Ho finito per passare da una riscrittura a un reindirizzamento e questo ha risolto il problema. i nostri URL ora contengono l'area, che non è l'ideale, ma è più importante che il sito funzioni senza rovinare troppo il routing di MVC. –

risposta

0

Non sono sicuro se aiuta, ma qui è il codice gettando eccezione:

internal static string ReduceVirtualPath(string path) 
{ 
    int length = path.Length; 
    int startIndex = 0; 
    while (true) 
    { 
     startIndex = path.IndexOf('.', startIndex); 
     if (startIndex < 0) 
     { 
      return path; 
     } 
     if (((startIndex == 0) || (path[startIndex - 1] == '/')) && ((((startIndex + 1) == length) || (path[startIndex + 1] == '/')) || ((path[startIndex + 1] == '.') && (((startIndex + 2) == length) || (path[startIndex + 2] == '/'))))) 
     { 
      break; 
     } 
     startIndex++; 
    } 
    ArrayList list = new ArrayList(); 
    StringBuilder builder = new StringBuilder(); 
    startIndex = 0; 
    do 
    { 
     int num3 = startIndex; 
     startIndex = path.IndexOf('/', num3 + 1); 
     if (startIndex < 0) 
     { 
      startIndex = length; 
     } 
     if ((((startIndex - num3) <= 3) && ((startIndex < 1) || (path[startIndex - 1] == '.'))) && (((num3 + 1) >= length) || (path[num3 + 1] == '.'))) 
     { 
      if ((startIndex - num3) == 3) 
      { 
       if (list.Count == 0) 
       { 
        throw new HttpException(SR.GetString("Cannot_exit_up_top_directory")); 
       } 
       if ((list.Count == 1) && IsAppRelativePath(path)) 
       { 
        return ReduceVirtualPath(MakeVirtualPathAppAbsolute(path)); 
       } 
       builder.Length = (int) list[list.Count - 1]; 
       list.RemoveRange(list.Count - 1, 1); 
      } 
     } 
     else 
     { 
      list.Add(builder.Length); 
      builder.Append(path, num3, startIndex - num3); 
     } 
    } 
    while (startIndex != length); 
    string str = builder.ToString(); 
    if (str.Length != 0) 
    { 
     return str; 
    } 
    if ((length > 0) && (path[0] == '/')) 
    { 
     return "/"; 
    } 
    return "."; 
} 
8

Si tratta di una soluzione grottesca che coinvolge i dettagli di implementazione private, ma aggiungere questo:

HttpContext.Current.Request.ServerVariables.Remove("IIS_WasUrlRewritten"); 

questo evita l'interno controllare fatto in PathHelper.GenerateClientUrlInternal per vedere se la richiesta è stata riscritta. E 'molto probabile che questo si romperà alcuni scenari, come suggerito da questo commento nelle fonti di riferimento:

// Since the rawUrl represents what the user sees in his browser, it is what we want to use as the base 
// of our absolute paths. For example, consider mysite.example.com/foo, which is internally 
// rewritten to content.example.com/mysite/foo. When we want to generate a link to ~/bar, we want to 
// base it from/instead of /foo, otherwise the user ends up seeing mysite.example.com/foo/bar, 
// which is incorrect. 
+0

Puoi dire dove si dovrebbe eseguire questo? Nel mio caso in realtà non esiste una variabile del server IIS_WasUrlRewritten ... Ma ho provato a rimuovere l'X-Original-URL dalle intestazioni e variabili del server che si suppone debbano fare qualcosa anche con Url Rewrite, ma né rimuovere quello lavorato da un Http Modulo (anche se il valore è lì, ma chiamare Remove() non fa nulla con esso). – Piedone

+0

Purtroppo questo non ha risolto il problema per noi. –

Problemi correlati