Add scheme to URL if needed
To create a Uri from a string you can do this:
Uri u = new Uri("example.com");
But the problem is if the string (like the one above) doesn't contain the protocol you will get an exception: "Invalid URI: The format of the URI could not be determined.
"
To avoid the exception you should secure the string includes a protocol, like below:
Uri u = new Uri("http://example.com");
But if you take the url as input, how can you add the protocol if it's missing?
I mean apart from some IndexOf/Substring manipulation?Something elegant and fast开发者_如何学编程?
You could also use UriBuilder
:
public static Uri GetUri(this string s)
{
return new UriBuilder(s).Uri;
}
Remarks from MSDN:
This constructor initializes a new instance of the UriBuilder class with the Fragment, Host, Path, Port, Query, Scheme, and Uri properties set as specified in uri.
If uri does not specify a scheme, the scheme defaults to "http:".
If you just want to add the scheme, without validating the URL, the fastest/easiest way is to use string lookups, eg:
string url = "mydomain.com";
if (!url.StartsWith("http://", StringComparison.OrdinalIgnoreCase)) url = "http://" + url;
A better approach would be to use Uri
to also validate the URL using the TryCreate
method:
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
}
As @JanDavidNarkiewicz pointed out in the comments, validating the Scheme
is necessary to guard against invalid schemes when a port is specified without scheme, e.g. mydomain.com:80
.
My solution was for protocall-less urls to make sure they have protocal was regex :
Regex.Replace(s, @"^\/\/", "http://");
Interestingly, although Uri
and UriBuilder
completely mangle any url without a scheme, WebProxy
does it right.
So just call:
new WebProxy(proxy.ProxyServer).Address
The accepted answer results in http and not https. I've found this answer and built up on it
namespace UrlHelper
{
using System;
public class UrlExtensions
{
public static Uri AddHttpsPrefixToString(string url)
{
if (string.IsNullOrWhiteSpace(url))
{
return null;
}
Uri uri;
try
{
uri = new UriBuilder(url) {
Scheme = Uri.UriSchemeHttps,
Port = -1 // default port for scheme
}.Uri;
}
catch
{
Console.WriteLine($"UrlExtensions.AddHttpsPrefixToString: Could not parse {url}");
return null;
}
return uri;
}
}
}
Use it like this: var termsStringOrNull = UrlExtensions.AddHttpsPrefixToString("example.com")?.ToString()
We had some specific cases where there was a legacy allowance to input stuff like: localhost:8800 or similar. Which means we needed to parse that. We built a little more elaborate ParseUri method that separated the possibility to specify a URI very loosely, but also caught the times where people would specify a non-standard scheme (and also the host in IP-long notation, because sometimes people do that)
Just like UriBuilder it will default to the http scheme if none is specified. It will have issues if a basic authentication is specified and the password consists only of numbers. (Feel free to fix that community)
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);
}
精彩评论