2010-12-30 15 views
7

Ho problemi con un vincolo specifico che sto cercando di impostare su un percorso. Il mio URL deve assomigliare a questo: http://hostname/id-my-title-can-be-that-long dove id è composto solo da cifre e il titolo è carattere minuscolo con separatore di trattini. Anche l'id e il titolo sono separati da un trattino. Ad esempio: http://hostname/123-my-title.ASP.NET MVC regex route constraint

Ecco la mia definizione della rotta:

routes.MapRoute(
    "Test", 
    "{id}-{title}", 
    new { controller = "Article", action = "Index" }, 
    new { id = @"(\d)+", title = @"([a-z]+-?)+" } 
); 

L'URL viene correttamente generata con l'aiuto del HTML:

<%: Html.ActionLink("My link", "Index", "Article", new { id = Model.IdArticle, title = Model.UrlTitle }, null) %> 

in cui, ovviamente, Model.IdArticle è un Int32 e Model.UrlTitle un stringa preformata del mio titolo che corrisponde alle mie esigenze (solo lettere minuscole, spazio sostituito da trattini).

Il problema è che quando si segue il collegamento, il metodo & del controller corretto non viene chiamato, cade sulla rotta successiva che è errata.

Per la cronaca, io sono su ASP.NET MVC 2.

Chiunque ha un'idea?

Grazie in anticipo, Fabian

+0

Infine, separeremo l'ID dal titolo con un punto. Mi sto ancora chiedendo perché questo non funziona, ma non lo blocca più. Grazie per l'aiuto! –

risposta

0

Si potrebbe provare a passare l'intera stringa percorso "{id} - {title}" e analizzare la stringa manualmente da soli prima che entri nella vostra azione facendo qualcosa di simile a Phil Haack di attributo slug to id actionfilter - link

Spero che questo aiuti.

+0

Ho letto il post di questo blog ma trovo eccessivo quando posso suddividere le informazioni sul percorso. Dato che il mio URL può essere creato dalla rotta ma non risolto come percorso, sto pensando a qualche tipo di bug in MVC. –

+0

Ah abbastanza giusto. Ne avrà un'altra :-) – WestDiscGolf

0

Diversi caratteri nel percorso sono "speciali" e suddivideranno i parametri come - e /. Potrebbe essere che gli extra nella rotta stanno causando il fallimento. Prova "{id}-{*title}" in quanto questo rende il titolo include tutto ciò che segue.

Aggiornamento

La risposta di cui sopra è ciò che accade quando si va in StackOverflow prima hai avuto abbastanza caffè.

Abbiamo riscontrato lo stesso problema relativo ai nomi di file per i file caricati dagli utenti, il percorso incluso "-" come delimitatore ma potrebbe essere utilizzato anche nel valore in un parametro successivo, potrebbe generare l'URL corretto ma non abbinarlo Alla fine ho scritto una classe SpecialFileRoute per gestire questo problema e registrato questa rotta. È un po 'brutto, ma fa il lavoro.

Nota che ho mantenuto la route MVC vecchio stile per generare l'URL, stavo giocando con questo per farlo correttamente, ma è qualcosa di cui tornare più tardi.

/// <summary> 
/// Special route to handle hyphens in the filename, a catchall parameter in the commented route caused exceptions 
/// </summary> 
public class SpecialFileRoute : RouteBase, IRouteWithArea 
{ 
    public string Controller { get; set; } 
    public string Action { get; set; } 
    public IRouteHandler RouteHandler = new MvcRouteHandler(); 
    public string Area { get; private set; } 

    //Doc/{doccode} - {CatNumber}.{version} - {*filename}, 

    public SpecialFileRoute(string area) 
    { 
     Area = area; 
    } 

    public override RouteData GetRouteData(HttpContextBase httpContext) 
    { 
     string url = httpContext.Request.AppRelativeCurrentExecutionFilePath.Substring(2); 
     var urlmatch = Regex.Match(url, @"doc/(\w*) - (\d*).(\d*) - (.*)", RegexOptions.IgnoreCase); 
     if (urlmatch.Success) 
     { 
      var routeData = new RouteData(this, this.RouteHandler); 

      routeData.Values.Add("doccode", urlmatch.Groups[1].Value); 
      routeData.Values.Add("CatNumber", urlmatch.Groups[2].Value); 
      routeData.Values.Add("version", urlmatch.Groups[3].Value); 
      routeData.Values.Add("filename", urlmatch.Groups[4].Value); 
      routeData.Values.Add("controller", this.Controller); 
      routeData.Values.Add("action", this.Action); 
      return routeData; 
     } 
     else 
      return null; 
    } 

    public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values) 
    { 
     if (values.ContainsKey("controller") && (!string.Equals(Controller, values["controller"] as string, StringComparison.InvariantCultureIgnoreCase))) 
      return null; 
     if (values.ContainsKey("action") && (!string.Equals(Action, values["action"] as string, StringComparison.InvariantCultureIgnoreCase))) 
      return null; 
     if ((!values.ContainsKey("contentUrl")) || (!values.ContainsKey("format"))) 
      return null; 
     return new VirtualPathData(this, string.Format("{0}.{1}", values["contentUrl"], values["format"])); 
    } 
} 

viene aggiunto il percorso come segue:

context.Routes.Add(new SpecialFileRoute(AreaName) { Controller = "Doc", Action = "Download" }); 

Come già detto questo è un po 'brutto e quando ho tempo c'è un sacco di lavoro mi piacerebbe fare per migliorare questo, ma risolto il problema di dividere l'URL nei parametri necessari. È fortemente legato ai requisiti specifici di questa unica rotta con il modello di URL, Regex e Valori codificati, anche se dovrebbe darti un inizio.

+0

Grazie per l'informazione, ma non possiamo usare un parametro catchall (*) in un segmento che contiene più di una sezione. –

+0

D'oh, certo. Mi sono imbattuto nello stesso problema qualche tempo fa – Chao