2010-02-23 5 views
12

je dois demander l'URL suivante dans mon application:System.Net.Uri avec des personnages urlencoded

http://feedbooks.com/type/Crime%2FMystery/books/top 

Quand je lance le code suivant:

Uri myUri = new Uri("http://feedbooks.com/type/Crime%2FMystery/books/top"); 

Le constructeur Uri décode le %2F en un littéral /, et j'obtiens une erreur 404 parce qu'il a changé l'URL à:

http://feedbooks.com/type/Crime/Mystery/books/top 

La classe Uri a un constructeur qui prend un paramètre dontEscape, mais ce constructeur est obsolète et le définir sur true n'a aucun effet.

Ma première pensée était de faire quelque chose comme:

Uri myUri = new Uri("http://feedbooks.com/type/Crime%252FMystery/books/top"); 

Avec l'espoir qu'il convertirait %25 dans un % littéral, mais cela ne fonctionne pas non plus.

Des idées pour créer un objet Uri correct pour cette URL particulière dans .NET?

+0

euh ... avez-vous essayé \% (ou \\%) ... :( – apandit

+0

J'aime la question. Maintenant, s'il vous plaît donner une réponse Java pour java.io.URI qui a la même sacrément problème, mais sans les drapeaux (aussi loin que je peux dire)! – davidbak

Répondre

5

je suis tombé sur le même problème en utilisant 2.0 ...

J'ai découvert une solution de contournement posté à this blog:

// System.UriSyntaxFlags is internal, so let's duplicate the flag privately 
private const int UnEscapeDotsAndSlashes = 0x2000000; 

public static void LeaveDotsAndSlashesEscaped(Uri uri) 
{ 
    if (uri == null) 
    { 
     throw new ArgumentNullException("uri"); 
    } 

    FieldInfo fieldInfo = uri.GetType().GetField("m_Syntax", BindingFlags.Instance | BindingFlags.NonPublic); 
    if (fieldInfo == null) 
    { 
     throw new MissingFieldException("'m_Syntax' field not found"); 
    } 
    object uriParser = fieldInfo.GetValue(uri); 

    fieldInfo = typeof(UriParser).GetField("m_Flags", BindingFlags.Instance | BindingFlags.NonPublic); 
    if (fieldInfo == null) 
    { 
     throw new MissingFieldException("'m_Flags' field not found"); 
    } 
    object uriSyntaxFlags = fieldInfo.GetValue(uriParser); 

    // Clear the flag that we don't want 
    uriSyntaxFlags = (int)uriSyntaxFlags & ~UnEscapeDotsAndSlashes; 

    fieldInfo.SetValue(uriParser, uriSyntaxFlags); 
} 

Il fonctionne parfaitement.

Hope this helps (mieux vaut tard que jamais!)

+0

Génial! Stackoverflow ne cesse de m'étonner –

+0

Content de pouvoir aider ... –

2

Il s'agit d'un bug I déposé il y a un certain temps. C'est censé être corrigé en 4.0, mais je ne retiens pas mon souffle. Apparemment, c'est toujours un problème dans le RC.

+0

Ah, connaissez-vous une solution de contournement pour un déploiement 3.5? –

+0

Désolé, mais je n'ai pas encore trouvé de solution de contournement. –

7

Il est un peu plus facile dans .NET 4.0. Vous pouvez mettre un paramètre dans votre fichier de configuration comme ceci:

<uri> 
<schemeSettings> 
    <add name="http" genericUriParserOptions="DontUnescapePathDotsAndSlashes" /> 
</schemeSettings> 
</uri> 

Il ne fonctionne que pour les systèmes de « http » et « https ».

Ou voici une nouvelle version de la méthode LeaveDotsAndSlashesEscaped. Il n'a pas besoin d'une instance particulière Uri, appelez simplement lorsque votre application démarre:

private void LeaveDotsAndSlashesEscaped() 
{ 
    var getSyntaxMethod = 
     typeof (UriParser).GetMethod("GetSyntax", BindingFlags.Static | BindingFlags.NonPublic); 
    if (getSyntaxMethod == null) 
    { 
     throw new MissingMethodException("UriParser", "GetSyntax"); 
    } 

    var uriParser = getSyntaxMethod.Invoke(null, new object[] { "http" }); 

    var setUpdatableFlagsMethod = 
     uriParser.GetType().GetMethod("SetUpdatableFlags", BindingFlags.Instance | BindingFlags.NonPublic); 
    if (setUpdatableFlagsMethod == null) 
    { 
     throw new MissingMethodException("UriParser", "SetUpdatableFlags"); 
    } 

    setUpdatableFlagsMethod.Invoke(uriParser, new object[] {0}); 
} 
1

En combinant les 2 réponses précédentes, vous pouvez avoir une méthode que vous suffit d'appeler une fois par processus qui fonctionne aussi bien sur. net 4 et .net 3.5.

// System.UriSyntaxFlags is internal, so let's duplicate the flag privately 
private const int UnEscapeDotsAndSlashes = 0x2000000; 

private void LeaveDotsAndSlashesEscaped() 
{ 
    var getSyntaxMethod = 
     typeof (UriParser).GetMethod("GetSyntax", BindingFlags.Static | BindingFlags.NonPublic); 
    if (getSyntaxMethod == null) 
    { 
     throw new MissingMethodException("UriParser", "GetSyntax"); 
    } 

    var uriParser = getSyntaxMethod.Invoke(null, new object[] { "http" }); 

    FieldInfo flagsFieldInfo = typeof(UriParser).GetField("m_Flags", BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.Instance); 

    if (flagsFieldInfo == null) 
    { 
     throw new MissingFieldException("UriParser", "m_Flags"); 
    } 
    int flags = (int) flagsFieldInfo.GetValue(uriParser); 
    // unset UnEscapeDotsAndSlashes flag and leave the others untouched 
    flags = flags & ~UnEscapeDotsAndSlashes; 
    flagsFieldInfo.SetValue(uriParser, flags); 

} 
Questions connexes