Path.Combine é útil, mas existe uma função semelhante na estrutura do .NET para URLs ?
Estou procurando uma sintaxe como esta:
Url.Combine("http://MyUrl.com/", "/Images/Image.jpg")
que retornaria:
"http://MyUrl.com/Images/Image.jpg"
Path.Combine é útil, mas existe uma função semelhante na estrutura do .NET para URLs ?
Estou procurando uma sintaxe como esta:
Url.Combine("http://MyUrl.com/", "/Images/Image.jpg")
que retornaria:
"http://MyUrl.com/Images/Image.jpg"
Respostas:
Há um comentário de Todd Menier acima de que Flurl inclui umUrl.Combine
.
Mais detalhes:
Url.Combine é basicamente um Path.Combine para URLs, garantindo um e apenas um caractere separador entre partes:
var url = Url.Combine(
"http://MyUrl.com/",
"/too/", "/many/", "/slashes/",
"too", "few?",
"x=1", "y=2"
// result: "http://www.MyUrl.com/too/many/slashes/too/few?x=1&y=2"
Obtenha o Flurl.Http no NuGet :
PM> Flurl.Http do pacote de instalação
Ou obtenha o construtor de URL independente sem os recursos HTTP:
PM> Flurl do pacote de instalação
Flurl
e seria perfer uma versão leve, github.com/jean-lourenco/UrlCombine
Uri
tem um construtor que deve fazer isso por você: new Uri(Uri baseUri, string relativeUri)
Aqui está um exemplo:
Uri baseUri = new Uri("http://www.contoso.com");
Uri myUri = new Uri(baseUri, "catalog/shownew.htm");
Nota do editor: Cuidado, este método não funciona conforme o esperado. Pode cortar parte do baseUri em alguns casos. Veja comentários e outras respostas.
Esta pode ser uma solução adequadamente simples:
public static string Combine(string uri1, string uri2)
{
uri1 = uri1.TrimEnd('/');
uri2 = uri2.TrimStart('/');
return string.Format("{0}/{1}", uri1, uri2);
}
Você usa Uri.TryCreate( ... )
:
Uri result = null;
if (Uri.TryCreate(new Uri("http://msdn.microsoft.com/en-us/library/"), "/en-us/library/system.uri.trycreate.aspx", out result))
{
Console.WriteLine(result);
}
Retornará:
http://msdn.microsoft.com/en-us/library/system.uri.trycreate.aspx
int.TryParse
, DateTime.TryParseExact
) possuem esse parâmetro de saída para facilitar o uso em uma instrução if. Aliás, você não precisa inicializar a variável como Ryan fez neste exemplo.
test.com/mydirectory/
e /helloworld.aspx
resultará no test.com/helloworld.aspx
que aparentemente não é o que você deseja.
Já existem ótimas respostas aqui. Com base na sugestão do mdsharpe, aqui está um método de extensão que pode ser facilmente usado quando você deseja lidar com instâncias do Uri:
using System;
using System.Linq;
public static class UriExtensions
{
public static Uri Append(this Uri uri, params string[] paths)
{
return new Uri(paths.Aggregate(uri.AbsoluteUri, (current, path) => string.Format("{0}/{1}", current.TrimEnd('/'), path.TrimStart('/'))));
}
}
E exemplo de uso:
var url = new Uri("http://example.com/subpath/").Append("/part1/", "part2").AbsoluteUri;
Isso produzirá http://example.com/subpath/part1/part2
A resposta de Ryan Cook está próxima do que estou procurando e pode ser mais apropriada para outros desenvolvedores. No entanto, ele adiciona http: // ao início da string e, em geral, faz um pouco mais de formatação do que estou procurando.
Além disso, para meus casos de uso, resolver caminhos relativos não é importante.
A resposta do mdsharp também contém a semente de uma boa idéia, embora essa implementação real precise de mais alguns detalhes para ser concluída. Esta é uma tentativa de detalhar (e estou usando isso na produção):
C #
public string UrlCombine(string url1, string url2)
{
if (url1.Length == 0) {
return url2;
}
if (url2.Length == 0) {
return url1;
}
url1 = url1.TrimEnd('/', '\\');
url2 = url2.TrimStart('/', '\\');
return string.Format("{0}/{1}", url1, url2);
}
VB.NET
Public Function UrlCombine(ByVal url1 As String, ByVal url2 As String) As String
If url1.Length = 0 Then
Return url2
End If
If url2.Length = 0 Then
Return url1
End If
url1 = url1.TrimEnd("/"c, "\"c)
url2 = url2.TrimStart("/"c, "\"c)
Return String.Format("{0}/{1}", url1, url2)
End Function
Esse código passa no seguinte teste, que acontece no VB:
<TestMethod()> Public Sub UrlCombineTest()
Dim target As StringHelpers = New StringHelpers()
Assert.IsTrue(target.UrlCombine("test1", "test2") = "test1/test2")
Assert.IsTrue(target.UrlCombine("test1/", "test2") = "test1/test2")
Assert.IsTrue(target.UrlCombine("test1", "/test2") = "test1/test2")
Assert.IsTrue(target.UrlCombine("test1/", "/test2") = "test1/test2")
Assert.IsTrue(target.UrlCombine("/test1/", "/test2/") = "/test1/test2/")
Assert.IsTrue(target.UrlCombine("", "/test2/") = "/test2/")
Assert.IsTrue(target.UrlCombine("/test1/", "") = "/test1/")
End Sub
ArgumentNullException("url1")
se o argumento for Nothing
? Desculpe, apenas sendo exigente ;-). Observe que uma barra invertida não tem nada a ver em um URI (e, se houver, não deve ser aparada), para que você possa removê-la do seu TrimXXX.
Path.Combine não funciona para mim porque pode haver caracteres como "|" nos argumentos QueryString e, portanto, na URL, que resultará em ArgumentException.
Tentei pela primeira vez a nova Uri(Uri baseUri, string relativeUri)
abordagem, que falhou por causa de URIs como http://www.mediawiki.org/wiki/Special:SpecialPages
:
new Uri(new Uri("http://www.mediawiki.org/wiki/"), "Special:SpecialPages")
resultará em Special: SpecialPages, por causa dos dois pontos depois Special
que denota um esquema.
Por fim, tive que seguir a rota mdsharpe / Brian MacKays e a desenvolver um pouco mais para trabalhar com várias partes de URI:
public static string CombineUri(params string[] uriParts)
{
string uri = string.Empty;
if (uriParts != null && uriParts.Length > 0)
{
char[] trims = new char[] { '\\', '/' };
uri = (uriParts[0] ?? string.Empty).TrimEnd(trims);
for (int i = 1; i < uriParts.Length; i++)
{
uri = string.Format("{0}/{1}", uri.TrimEnd(trims), (uriParts[i] ?? string.Empty).TrimStart(trims));
}
}
return uri;
}
Uso: CombineUri("http://www.mediawiki.org/", "wiki", "Special:SpecialPages")
Com base no URL de amostra você forneceu, suponho que você queira combinar URLs relativos ao seu site.
Com base nessa premissa, proponho esta solução como a resposta mais apropriada à sua pergunta, que foi: "Path.Combine é útil, existe uma função semelhante na estrutura para URLs?"
Como existe uma função semelhante na estrutura dos URLs, proponho que o correto seja: "VirtualPathUtility.Combine". Aqui está o link de referência do MSDN: Método VirtualPathUtility.Combine
Há uma ressalva: acredito que isso funcione apenas para URLs relativos ao seu site (ou seja, você não pode usá-lo para gerar links para outro site. Por exemplo, var url = VirtualPathUtility.Combine("www.google.com", "accounts/widgets");
).
Server.MapPath
e combinação.
Path.Combine("Http://MyUrl.com/", "/Images/Image.jpg").Replace("\\", "/")
path.Replace(Path.DirectorySeparatorChar, '/');
path.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)
Acabei de montar um pequeno método de extensão:
public static string UriCombine (this string val, string append)
{
if (String.IsNullOrEmpty(val)) return append;
if (String.IsNullOrEmpty(append)) return val;
return val.TrimEnd('/') + "/" + append.TrimStart('/');
}
Pode ser usado assim:
"www.example.com/".UriCombine("/images").UriCombine("first.jpeg");
Exemplo espirituoso, Ryan, para terminar com um link para a função. Bem feito.
Uma recomendação Brian: se você agrupar esse código em uma função, poderá usar um UriBuilder para agrupar o URL base antes da chamada TryCreate.
Caso contrário, o URL base DEVE incluir o esquema (onde o UriBuilder assumirá http: //). Apenas um pensamento:
public string CombineUrl(string baseUrl, string relativeUrl) {
UriBuilder baseUri = new UriBuilder(baseUrl);
Uri newUri;
if (Uri.TryCreate(baseUri.Uri, relativeUrl, out newUri))
return newUri.ToString();
else
throw new ArgumentException("Unable to combine specified url values");
}
Uma maneira fácil de combiná-los e garantir que esteja sempre correto é:
string.Format("{0}/{1}", Url1.Trim('/'), Url2);
Combinar várias partes de um URL pode ser um pouco complicado. Você pode usar o construtor de dois parâmetros Uri(baseUri, relativeUri)
ou a Uri.TryCreate()
função de utilitário.
Em qualquer um dos casos, você pode retornar um resultado incorreto, porque esses métodos continuam truncando as partes relativas do primeiro parâmetro baseUri
, ou seja, de algo como http://google.com/some/thing
para http://google.com
.
Para poder combinar várias partes em um URL final, você pode copiar as duas funções abaixo:
public static string Combine(params string[] parts)
{
if (parts == null || parts.Length == 0) return string.Empty;
var urlBuilder = new StringBuilder();
foreach (var part in parts)
{
var tempUrl = tryCreateRelativeOrAbsolute(part);
urlBuilder.Append(tempUrl);
}
return VirtualPathUtility.RemoveTrailingSlash(urlBuilder.ToString());
}
private static string tryCreateRelativeOrAbsolute(string s)
{
System.Uri uri;
System.Uri.TryCreate(s, UriKind.RelativeOrAbsolute, out uri);
string tempUrl = VirtualPathUtility.AppendTrailingSlash(uri.ToString());
return tempUrl;
}
O código completo com testes de unidade para demonstrar o uso pode ser encontrado em https://uricombine.codeplex.com/SourceControl/latest#UriCombine/Uri.cs
Eu tenho testes de unidade para cobrir os três casos mais comuns:
Eu achei que UriBuilder
funcionou muito bem para esse tipo de coisa:
UriBuilder urlb = new UriBuilder("http", _serverAddress, _webPort, _filePath);
Uri url = urlb.Uri;
return url.AbsoluteUri;
Consulte Classe UriBuilder - MSDN para obter mais construtores e documentação.
Aqui está o método UrlUtility.Combine da Microsoft (OfficeDev PnP) :
const char PATH_DELIMITER = '/';
/// <summary>
/// Combines a path and a relative path.
/// </summary>
/// <param name="path"></param>
/// <param name="relative"></param>
/// <returns></returns>
public static string Combine(string path, string relative)
{
if(relative == null)
relative = String.Empty;
if(path == null)
path = String.Empty;
if(relative.Length == 0 && path.Length == 0)
return String.Empty;
if(relative.Length == 0)
return path;
if(path.Length == 0)
return relative;
path = path.Replace('\\', PATH_DELIMITER);
relative = relative.Replace('\\', PATH_DELIMITER);
return path.TrimEnd(PATH_DELIMITER) + PATH_DELIMITER + relative.TrimStart(PATH_DELIMITER);
}
Fonte: GitHub
Acho o seguinte útil e possui os seguintes recursos:
params
parâmetros para vários segmentos de URLClasse
public static class UrlPath
{
private static string InternalCombine(string source, string dest)
{
if (string.IsNullOrWhiteSpace(source))
throw new ArgumentException("Cannot be null or white space", nameof(source));
if (string.IsNullOrWhiteSpace(dest))
throw new ArgumentException("Cannot be null or white space", nameof(dest));
return $"{source.TrimEnd('/', '\\')}/{dest.TrimStart('/', '\\')}";
}
public static string Combine(string source, params string[] args)
=> args.Aggregate(source, InternalCombine);
}
Testes
UrlPath.Combine("test1", "test2");
UrlPath.Combine("test1//", "test2");
UrlPath.Combine("test1", "/test2");
// Result = test1/test2
UrlPath.Combine(@"test1\/\/\/", @"\/\/\\\\\//test2", @"\/\/\\\\\//test3\") ;
// Result = test1/test2/test3
UrlPath.Combine("/test1/", "/test2/", null);
UrlPath.Combine("", "/test2/");
UrlPath.Combine("/test1/", null);
// Throws an ArgumentException
Minha solução genérica:
public static string Combine(params string[] uriParts)
{
string uri = string.Empty;
if (uriParts != null && uriParts.Any())
{
char[] trims = new char[] { '\\', '/' };
uri = (uriParts[0] ?? string.Empty).TrimEnd(trims);
for (int i = 1; i < uriParts.Length; i++)
{
uri = string.Format("{0}/{1}", uri.TrimEnd(trims), (uriParts[i] ?? string.Empty).TrimStart(trims));
}
}
return uri;
}
Eu criei esta função que facilitará sua vida:
/// <summary>
/// The ultimate Path combiner of all time
/// </summary>
/// <param name="IsURL">
/// true - if the paths are Internet URLs, false - if the paths are local URLs, this is very important as this will be used to decide which separator will be used.
/// </param>
/// <param name="IsRelative">Just adds the separator at the beginning</param>
/// <param name="IsFixInternal">Fix the paths from within (by removing duplicate separators and correcting the separators)</param>
/// <param name="parts">The paths to combine</param>
/// <returns>the combined path</returns>
public static string PathCombine(bool IsURL , bool IsRelative , bool IsFixInternal , params string[] parts)
{
if (parts == null || parts.Length == 0) return string.Empty;
char separator = IsURL ? '/' : '\\';
if (parts.Length == 1 && IsFixInternal)
{
string validsingle;
if (IsURL)
{
validsingle = parts[0].Replace('\\' , '/');
}
else
{
validsingle = parts[0].Replace('/' , '\\');
}
validsingle = validsingle.Trim(separator);
return (IsRelative ? separator.ToString() : string.Empty) + validsingle;
}
string final = parts
.Aggregate
(
(string first , string second) =>
{
string validfirst;
string validsecond;
if (IsURL)
{
validfirst = first.Replace('\\' , '/');
validsecond = second.Replace('\\' , '/');
}
else
{
validfirst = first.Replace('/' , '\\');
validsecond = second.Replace('/' , '\\');
}
var prefix = string.Empty;
if (IsFixInternal)
{
if (IsURL)
{
if (validfirst.Contains("://"))
{
var tofix = validfirst.Substring(validfirst.IndexOf("://") + 3);
prefix = validfirst.Replace(tofix , string.Empty).TrimStart(separator);
var tofixlist = tofix.Split(new[] { separator } , StringSplitOptions.RemoveEmptyEntries);
validfirst = separator + string.Join(separator.ToString() , tofixlist);
}
else
{
var firstlist = validfirst.Split(new[] { separator } , StringSplitOptions.RemoveEmptyEntries);
validfirst = string.Join(separator.ToString() , firstlist);
}
var secondlist = validsecond.Split(new[] { separator } , StringSplitOptions.RemoveEmptyEntries);
validsecond = string.Join(separator.ToString() , secondlist);
}
else
{
var firstlist = validfirst.Split(new[] { separator } , StringSplitOptions.RemoveEmptyEntries);
var secondlist = validsecond.Split(new[] { separator } , StringSplitOptions.RemoveEmptyEntries);
validfirst = string.Join(separator.ToString() , firstlist);
validsecond = string.Join(separator.ToString() , secondlist);
}
}
return prefix + validfirst.Trim(separator) + separator + validsecond.Trim(separator);
}
);
return (IsRelative ? separator.ToString() : string.Empty) + final;
}
Funciona para URLs e para caminhos normais.
Uso:
// Fixes internal paths
Console.WriteLine(PathCombine(true , true , true , @"\/\/folder 1\/\/\/\\/\folder2\///folder3\\/" , @"/\somefile.ext\/\//\"));
// Result: /folder 1/folder2/folder3/somefile.ext
// Doesn't fix internal paths
Console.WriteLine(PathCombine(true , true , false , @"\/\/folder 1\/\/\/\\/\folder2\///folder3\\/" , @"/\somefile.ext\/\//\"));
//result : /folder 1//////////folder2////folder3/somefile.ext
// Don't worry about URL prefixes when fixing internal paths
Console.WriteLine(PathCombine(true , false , true , @"/\/\/https:/\/\/\lul.com\/\/\/\\/\folder2\///folder3\\/" , @"/\somefile.ext\/\//\"));
// Result: https://lul.com/folder2/folder3/somefile.ext
Console.WriteLine(PathCombine(false , true , true , @"../../../\\..\...\./../somepath" , @"anotherpath"));
// Result: \..\..\..\..\...\.\..\somepath\anotherpath
Por que não usar apenas o seguinte.
System.IO.Path.Combine(rootUrl, subPath).Replace(@"\", "/")
[System.IO.Path]::Combine("http://MyUrl.com/","/Images/Image.jpg")
no entanto isso falhar com um resultado de: /Images/Image.jpg
. Remova o /
segundo subcaminho e ele funcionará:[System.IO.Path]::Combine("http://MyUrl.com/","Images/Image.jpg")
Regras ao combinar URLs com um URI
Para evitar comportamentos estranhos, há uma regra a seguir:
string.Empty
serão descartadas ... adicionar um caminho de peça também removerá o diretório relativo da URL!Se você seguir as regras acima, poderá combinar URLs com o código abaixo. Dependendo da sua situação, você pode adicionar várias partes do 'diretório' ao URL ...
var pathParts = new string[] { destinationBaseUrl, destinationFolderUrl, fileName };
var destination = pathParts.Aggregate((left, right) =>
{
if (string.IsNullOrWhiteSpace(right))
return left;
return new Uri(new Uri(left), right).ToString();
});
Se você não deseja adicionar uma dependência de terceiros como Flurl ou criar um método de extensão personalizado, no ASP.NET Core (também disponível no Microsoft.Owin), pode usar o PathString
que se destina ao objetivo de criar URI caminhos. Você pode criar seu URI completo usando uma combinação disso Uri
e UriBuilder
.
Nesse caso, seria:
new Uri(new UriBuilder("http", "MyUrl.com").Uri, new PathString("/Images").Add("/Image.jpg").ToString())
Isso fornece todas as partes constituintes sem a necessidade de especificar os separadores no URL base. Infelizmente, PathString
requer que /
seja anexado a cada string, caso contrário, ele lança um ArgumentException
! Mas pelo menos você pode criar seu URI deterministicamente de uma maneira que seja facilmente testável por unidade.
Então, eu tenho outra abordagem, semelhante a todos que usaram o UriBuilder.
Eu não queria dividir meu BaseUrl (que pode conter uma parte do caminho - por exemplo, http://mybaseurl.com/dev/ ) como javajavajavajavajava .
O seguinte trecho mostra o código + testes.
Cuidado: esta solução coloca em minúsculas o host e anexa uma porta. Se isso não for desejado, pode-se escrever uma representação de string, por exemplo, aproveitando a Uri
propriedade de UriBuilder
.
public class Tests
{
public static string CombineUrl (string baseUrl, string path)
{
var uriBuilder = new UriBuilder (baseUrl);
uriBuilder.Path = Path.Combine (uriBuilder.Path, path);
return uriBuilder.ToString();
}
[TestCase("http://MyUrl.com/", "/Images/Image.jpg", "http://myurl.com:80/Images/Image.jpg")]
[TestCase("http://MyUrl.com/basePath", "/Images/Image.jpg", "http://myurl.com:80/Images/Image.jpg")]
[TestCase("http://MyUrl.com/basePath", "Images/Image.jpg", "http://myurl.com:80/basePath/Images/Image.jpg")]
[TestCase("http://MyUrl.com/basePath/", "Images/Image.jpg", "http://myurl.com:80/basePath/Images/Image.jpg")]
public void Test1 (string baseUrl, string path, string expected)
{
var result = CombineUrl (baseUrl, path);
Assert.That (result, Is.EqualTo (expected));
}
}
Testado com o .NET Core 2.1 no Windows 10.
Por que isso funciona?
Embora Path.Combine
retorne barras invertidas (no Windows pelo menos), o UriBuilder lida com esse caso no Setter de Path
.
Retirado de https://github.com/dotnet/corefx/blob/master/src/System.Private.Uri/src/System/UriBuilder.cs (lembre-se da chamada para string.Replace
)
[AllowNull]
public string Path
{
get
{
return _path;
}
set
{
if ((value == null) || (value.Length == 0))
{
value = "/";
}
_path = Uri.InternalEscapeString(value.Replace('\\', '/'));
_changed = true;
}
}
Essa é a melhor abordagem?
Certamente esta solução é bastante auto-descritiva (pelo menos na minha opinião). Mas você está confiando no "recurso" não documentado (pelo menos não encontrei nada com uma pesquisa rápida no google) da API do .NET. Isso pode mudar com uma versão futura, portanto, cubra o método com testes.
Existem testes em https://github.com/dotnet/corefx/blob/master/src/System.Private.Uri/tests/FunctionalTests/UriBuilderTests.cs ( Path_Get_Set
) que verificam se a \
transformação está correta.
Nota lateral: Também é possível trabalhar UriBuilder.Uri
diretamente com a propriedade, se o uri for usado para um System.Uri
ctor.
Para quem procura uma linha única e simplesmente deseja unir partes de um caminho sem criar um novo método ou fazer referência a uma nova biblioteca ou construir um valor de URI e convertê-lo em uma string, então ...
string urlToImage = String.Join("/", "websiteUrl", "folder1", "folder2", "folder3", "item");
É bem básico, mas não vejo o que mais você precisa. Se você tem medo de dobrar '/', basta fazer o .Replace("//", "/")
seguinte. Se você tem medo de substituir o '//' dobrado em 'https: //', faça uma junção, substitua o '/' dobrado e junte-se ao URL do site (no entanto, tenho certeza de que a maioria dos navegadores irá automaticamente converta qualquer coisa com 'https:' na frente para ler no formato correto). Seria assim:
string urlToImage = String.Join("/","websiteUrl", String.Join("/", "folder1", "folder2", "folder3", "item").Replace("//","/"));
Há muitas respostas aqui que tratam de tudo o que foi dito acima, mas, no meu caso, eu só precisava dela uma vez em um local e não precisaria depender muito delas. Além disso, é realmente fácil ver o que está acontecendo aqui.
Consulte: https://docs.microsoft.com/en-us/dotnet/api/system.string.join?view=netframework-4.8
Usar:
private Uri UriCombine(string path1, string path2, string path3 = "", string path4 = "")
{
string path = System.IO.Path.Combine(path1, path2.TrimStart('\\', '/'), path3.TrimStart('\\', '/'), path4.TrimStart('\\', '/'));
string url = path.Replace('\\','/');
return new Uri(url);
}
Tem o benefício de se comportar exatamente como Path.Combine
.
Aqui está minha abordagem e também a utilizarei para mim:
public static string UrlCombine(string part1, string part2)
{
string newPart1 = string.Empty;
string newPart2 = string.Empty;
string seperator = "/";
// If either part1 or part 2 is empty,
// we don't need to combine with seperator
if (string.IsNullOrEmpty(part1) || string.IsNullOrEmpty(part2))
{
seperator = string.Empty;
}
// If part1 is not empty,
// remove '/' at last
if (!string.IsNullOrEmpty(part1))
{
newPart1 = part1.TrimEnd('/');
}
// If part2 is not empty,
// remove '/' at first
if (!string.IsNullOrEmpty(part2))
{
newPart2 = part2.TrimStart('/');
}
// Now finally combine
return string.Format("{0}{1}{2}", newPart1, seperator, newPart2);
}
Usa isto:
public static class WebPath
{
public static string Combine(params string[] args)
{
var prefixAdjusted = args.Select(x => x.StartsWith("/") && !x.StartsWith("http") ? x.Substring(1) : x);
return string.Join("/", prefixAdjusted);
}
}
Para o que vale a pena, aqui estão alguns métodos de extensão. O primeiro combinará caminhos e o segundo adiciona parâmetros ao URL.
public static string CombineUrl(this string root, string path, params string[] paths)
{
if (string.IsNullOrWhiteSpace(path))
{
return root;
}
Uri baseUri = new Uri(root);
Uri combinedPaths = new Uri(baseUri, path);
foreach (string extendedPath in paths)
{
combinedPaths = new Uri(combinedPaths, extendedPath);
}
return combinedPaths.AbsoluteUri;
}
public static string AddUrlParams(this string url, Dictionary<string, string> parameters)
{
if (parameters == null || !parameters.Keys.Any())
{
return url;
}
var tempUrl = new StringBuilder($"{url}?");
int count = 0;
foreach (KeyValuePair<string, string> parameter in parameters)
{
if (count > 0)
{
tempUrl.Append("&");
}
tempUrl.Append($"{WebUtility.UrlEncode(parameter.Key)}={WebUtility.UrlEncode(parameter.Value)}");
count++;
}
return tempUrl.ToString();
}
Como encontrado em outras respostas, novo Uri()
ou TryCreate()
pode fazer o tick. No entanto, a base Uri precisa terminar /
e o parente NÃO deve começar /
; caso contrário, removerá a parte final do URL base
Eu acho que isso é melhor feito como um método de extensão, ou seja,
public static Uri Append(this Uri uri, string relativePath)
{
var baseUri = uri.AbsoluteUri.EndsWith('/') ? uri : new Uri(uri.AbsoluteUri + '/');
var relative = relativePath.StartsWith('/') ? relativePath.Substring(1) : relativePath;
return new Uri(baseUri, relative);
}
e para usá-lo:
var baseUri = new Uri("http://test.com/test/");
var combinedUri = baseUri.Append("/Do/Something");
Em termos de desempenho, isso consome mais recursos do que o necessário, devido à classe Uri, que faz muita análise e validação; um perfil muito difícil (Debug) realizou um milhão de operações em cerca de 2 segundos. Isso funcionará na maioria dos cenários; no entanto, para ser mais eficiente, é melhor manipular tudo como seqüências de caracteres; isso leva 125 milissegundos para 1 milhão de operações. Ou seja,
public static string Append(this Uri uri, string relativePath)
{
//avoid the use of Uri as it's not needed, and adds a bit of overhead.
var absoluteUri = uri.AbsoluteUri; //a calculated property, better cache it
var baseUri = absoluteUri.EndsWith('/') ? absoluteUri : absoluteUri + '/';
var relative = relativePath.StartsWith('/') ? relativePath.Substring(1) : relativePath;
return baseUri + relative;
}
E se você ainda deseja retornar um URI, leva cerca de 600 milissegundos para 1 milhão de operações.
public static Uri AppendUri(this Uri uri, string relativePath)
{
//avoid the use of Uri as it's not needed, and adds a bit of overhead.
var absoluteUri = uri.AbsoluteUri; //a calculated property, better cache it
var baseUri = absoluteUri.EndsWith('/') ? absoluteUri : absoluteUri + '/';
var relative = relativePath.StartsWith('/') ? relativePath.Substring(1) : relativePath;
return new Uri(baseUri + relative);
}
Eu espero que isso ajude.
Eu acho que isso deve lhe dar mais flexibilidade, pois você pode lidar com quantos segmentos de caminho desejar:
public static string UrlCombine(this string baseUrl, params string[] segments)
=> string.Join("/", new[] { baseUrl.TrimEnd('/') }.Concat(segments.Select(s => s.Trim('/'))));
Url.Combine
método que faz exatamente isso.