2009-01-26 3 views
4

Nous avons un site multilingue qui utilise les cultures asp.net 2.0. La culture actuelle est définie via l'URL réécrite comme une chaîne de requête. (~/Es/blah.aspx est la version espagnole de ~/blah.aspx - réécrite comme ~/blah.aspx lang = es?)ASP.Net Validation des noms de culture

Le code qui teste la culture est la suivante:

System.Globalization.CultureInfo ci; 
    try 
    { 
     ci = new System.Globalization.CultureInfo(Request.QueryString["lang"] ?? string.Empty); 
    } 
    catch 
    { 
     ci = new System.Globalization.CultureInfo(string.Empty); 
    } 

S'il n'y a pas de jeu de culture, il est par défaut en anglais, 127. Quand il y a une culture, tous les liens sur cette page sont ensuite pré-pendu avec le nom de culture correct. D'une manière ou d'une autre, une araignée a mis la main sur quelques liens sous la forme de ~/www.test.com/blah.aspx et martèle notre site avec une culture de www.test.com qui, en inondant notre erreur de journalisation.

Existe-t-il un moyen de tester si un nom de culture est valide en plus d'intercepter une exception?

Répondre

2

This site a un exemple en utilisant LINQ:

CultureInfo[] cultures = System.Globalization.CultureInfo.GetCultures 
         (CultureTypes.SpecificCultures); 

var selectCulture = from p in cultures 
        where p.Name == value 
        select p; 

if (selectCulture.Count() == 1) 
{ 
    // your culture is good 
} 

Il semble un peu lourd, cependant. Je resterais probablement avec ce que tu as.

+0

Merci, mais j'aurais dû mentionner que nous sommes toujours sur .net 2.0 –

+0

Vous pouvez retirer les pièces dont vous avez besoin. Roger l'a transformé en .net 2.0 pour vous. –

5

Vous n'avez pas ont utiliser LINQ:

private static bool IsValidCultureName(string cultureName) 
{ 
    CultureInfo[] cultures = 
     CultureInfo.GetCultures(CultureTypes.SpecificCultures); 
    foreach (CultureInfo culture in cultures) 
    { 
     if (culture.Name == cultureName) 
      return true; 
    } 

    return false; 
} 

Cela pourrait être assez cher, mais peut-être encore moins cher que de traiter avec des exceptions, qui sont assez cher - mesurer la différence avant de prendre ma parole pour cela, cependant.

Je ne pense pas que la liste des cultures définies changera entre les versions .NET, donc vous devriez probablement obtenir la liste au démarrage et la mettre en cache quelque part.

+0

J'ai fait quelques tests rapides pour voir quelle est la meilleure façon de faire cela, je pensais que les résultats justifient une nouvelle réponse. Si vous êtes toujours intéressé voir ci-dessous. – BenCr

+0

Dans le code de Microsoft, ils mettent déjà en cache la liste des cultures dans un dictionnaire, il n'y a donc pas grand intérêt à la mettre de nouveau en cache. Cela étant dit, nous avons constaté un gain de performance mesurable en mettant en cache un objet CultureInfo plutôt qu'en en construisant un nouveau sur chaque requête. – DannyMeister

6

A peu près la même réponse comme déjà dit qu'avec une expression LINQ plus compact:

private static bool IsValidCultureInfoName(string name) 
{ 
    return 
     CultureInfo 
     .GetCultures(CultureTypes.SpecificCultures) 
     .Any(c => c.Name == name); 
} 
10

Je pensais avoir un aller rapidement à la mesure de cette façon engrossé une application console rapide.

Il utilise essentiellement les 3 méthodes (constructeur, LINQ et foreach) pour obtenir un CultureInfo à partir d'une chaîne 10000 fois dans une boucle. J'ai enlevé le chronomètre et la sortie de console pour la brièveté.

string culture = "en-GB"; 
CultureInfo[] cultures = CultureInfo.GetCultures(CultureTypes.SpecificCultures); 
for (int i = 0; i < 10000; i++) 
{ 
    try 
    { 
     CultureInfo c = new CultureInfo(culture); 
    } 
    catch 
    { 
    } 
} 
for (int i = 0; i < 10000; i++) 
{ 
    CultureInfo c = cultures.FirstOrDefault((x) => x.Name == culture); 
} 
for (int i = 0; i < 10000; i++) 
{ 
    foreach (CultureInfo c in cultures) 
    { 
     if (c.Name == culture) 
      break; 
    } 
} 

Les résultats sont les suivants ...

Try Catch: 00:00:00.0023860 
LINQ: 00:00:00.0542459 
ForEach: 00:00:00.0238937 

Si vous supprimez les cultures variables et appelez ensuite chaque itération LINQ et boucles foreach prennent environ 2,5 secondes. Donc, en utilisant le constructeur est favorable si vous prévoyez obtenir beaucoup d'entrées valides et seulement l'invalide impair. Mais si vous changez la valeur si l'entrée de en-GB à TEST alors les choses changent massivement.

Invalid Culture Try Catch: 00:00:39.7163513 
Invalid Culture LINQ: 00:00:00.0791752 
Invalid Culture ForEach: 00:00:00.0291480 

Il est évident que ma demande de test n'est pas un scénario du monde réel, mais depuis l'OP a dit cela est appelé sur une base par demande, je peux imaginer que dans une grande application web ce code pourrait obtenir appelé beaucoup.C'est peut-être un vecteur de déni ou de service, prenez tout le CPU en spammant le serveur web avec des requêtes qui ont toutes un paramètre de culture invalide.

1

Voici ce que j'ai fini par faire pour mon filtre d'action. Nous vérifions seulement la langue, pas les paramètres régionaux.

public class HttpInternationalizationAttribute : ActionFilterAttribute 
{ 
    private static readonly HashSet<string> Langs = new HashSet<string>(CultureInfo.GetCultures(CultureTypes.NeutralCultures) 
                      .Select(x => x.TwoLetterISOLanguageName.ToUpper())); 

    public override void OnActionExecuting(HttpActionContext actionContext) 
    { 
     var language = (string)actionContext.ControllerContext.RouteData.Values["language"]; 

     if (!string.IsNullOrEmpty(language) && Langs.Contains(language.ToUpper())) 
     { 
      Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo(language); 
      Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(language); 
     } 
    } 
} 

En utilisant un hashset, cela fonctionnera dans O (1).

À la votre!

+0

Si vous utilisez un 'dictionary ' pour éviter les appels GetCultureInfo, cela l'accélèrera considérablement. – MHollis

Questions connexes