web-dev-qa-db-fra.com

Ajouter un schéma à l'URL si nécessaire

Pour créer un Uri à partir d'une chaîne, vous pouvez procéder comme suit:

Uri u = new Uri("example.com");

Mais le problème est que si la chaîne (comme celle ci-dessus) ne contient pas le protocole, vous obtiendrez une exception: "Invalid URI: The format of the URI could not be determined. "

Pour éviter l'exception, vous devez sécuriser la chaîne comprend un protocole, comme ci-dessous:

Uri u = new Uri("http://example.com");

Mais si vous prenez l'URL en entrée, comment pouvez-vous ajouter le protocole s'il est manquant?
Je veux dire en dehors de certaines manipulations IndexOf/Substring?

Quelque chose d'élégant et de rapide?

62
Max Favilli

Vous pouvez également utiliser UriBuilder :

public static Uri GetUri(this string s)
{
    return new UriBuilder(s).Uri;
}

Remarques de MSDN:

Ce constructeur initialise une nouvelle instance de la classe UriBuilder avec les propriétés Fragment, Host, Path, Port, Query, Scheme et Uri définies comme spécifié dans uri.

Si uri ne spécifie pas de schéma, le schéma par défaut est "http:".

125
as-cii

Si vous souhaitez simplement ajouter le schéma, sans valider l'URL, le moyen le plus rapide/le plus simple consiste à utiliser des recherches de chaînes, par exemple:

string url = "mydomain.com";
if (!url.StartsWith("http://", StringComparison.OrdinalIgnoreCase)) url = "http://" + url;

Une meilleure approche serait d'utiliser Uri pour valider également l'URL en utilisant la méthode TryCreate :

string url = "mydomain.com";
Uri uri;
if ((Uri.TryCreate(url, UriKind.Absolute, out uri) || Uri.TryCreate("http://" + url, UriKind.Absolute, out uri)) &&
    (uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps))
{
    // Use validated URI here
}

Comme @JanDavidNarkiewicz l'a souligné dans les commentaires, la validation de Scheme est nécessaire pour se prémunir contre les schémas non valides lorsqu'un port est spécifié sans schéma, par ex. mydomain.com:80.

7
Ronald

Ma solution était d'utiliser des URL sans protocole pour m'assurer qu'elles avaient un protocole regex:

Regex.Replace(s, @"^\/\/", "http://");
3
John

Nous avons eu des cas spécifiques où il y avait une allocation héritée pour entrer des choses comme: localhost: 8800 ou similaire. Ce qui signifie que nous devions analyser cela. Nous avons construit une méthode ParseUri un peu plus élaborée qui séparait la possibilité de spécifier un URI de manière très lâche, mais a également saisi les moments où les gens spécifiaient un schéma non standard (et aussi l'hôte en notation IP longue, car parfois les gens le font)

Tout comme UriBuilder, il utilisera par défaut le schéma http si aucun n'est spécifié. Il y aura des problèmes si une authentification de base est spécifiée et que le mot de passe se compose uniquement de chiffres. (N'hésitez pas à réparer cette communauté)

        private static Uri ParseUri(string uri)
        {

            if (uri.StartsWith("//"))
                return new Uri("http:" + uri);
            if (uri.StartsWith("://"))
                return new Uri("http" + uri);

            var m = System.Text.RegularExpressions.Regex.Match(uri, @"^([^\/]+):(\d+)(\/*)", System.Text.RegularExpressions.RegexOptions.IgnoreCase | System.Text.RegularExpressions.RegexOptions.Singleline);
            if (m.Success)
            {
                var port = int.Parse(m.Groups[2].Value);
                if (port <= 65535) //part2 is a port (65535 highest port number)
                    return new Uri("http://" + uri);
                else if (port >= 16777217) //part2 is an ip long (16777217 first ip in long notation)
                    return new UriBuilder(uri).Uri;
                else
                    throw new ArgumentOutOfRangeException("Invalid port or ip long, technically could be local network hostname, but someone needs to be hit on the head for that one");
            }
            else
                return new Uri(uri);
        }
0
Peter