Path.Combine para URLs?

Path.Combine é útil, mas existe uma function semelhante no .NET framework para URLs ?

Eu estou procurando syntax como esta:

Url.Combine("http://sofpt.miximages.com/path/f") 

que retornaria:

"http://sofpt.miximages.com/path/f"

Uri tem um construtor que deve fazer isso para 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"); 

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/pt-br/library/system.uri.trycreate.aspx

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); } 

Já existem ótimas respostas aqui. Com base na sugestão de mdsharpe, aqui está um método de extensão que pode ser facilmente usado quando você deseja lidar com instâncias de 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

Esta pergunta tem ótimas respostas altamente votadas!

A resposta de Ryan Cook está perto do que eu estou procurando e pode ser mais apropriado 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 depois.

Além disso, para os meus casos de uso, a resolução de caminhos relativos não é importante.

A resposta do mdsharp também contém a semente de uma boa ideia, embora essa implementação real necessitasse 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 em VB:

  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 

Com base no URL de amostra fornecido, presumo que você queira combinar URLs relacionadas ao seu site.

Com base nessa suposição, proponho essa solução como a resposta mais apropriada à sua pergunta, que era: “Path.Combine é útil, existe uma function semelhante no framework para URLs?”

Uma vez que existe uma function semelhante no framework para URLs, proponho que o método correto é: “VirtualPathUtility.Combine”. Aqui está o link de referência do MSDN: VirtualPathUtility.Combine Method

Há uma ressalva: acredito que isso funcione apenas para URLs relativas ao seu site (ou seja, você não pode usá-lo para gerar links para outro site da Web. Por exemplo, var url = VirtualPathUtility.Combine("www.google.com", "accounts/widgets"); ).

Path.Combine não funciona para mim porque pode haver caracteres como “|” em argumentos QueryString e, portanto, o URL, que resultará em um ArgumentException.

Eu tentei pela primeira vez a nova abordagem Uri (Uri baseUri, string relativeUri), que falhou para mim por causa do Uri 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 após Special que denota um esquema.

Então eu finalmente tive que usar a rota mdsharpe / Brian MacKays e desenvolvi um pouco mais para trabalhar com várias partes uri:

 public static string CombineUri(params string[] uriParts) { string uri = string.Empty; if (uriParts != null && uriParts.Count() > 0) { char[] trims = new char[] { '\\', '/' }; uri = (uriParts[0] ?? string.Empty).TrimEnd(trims); for (int i = 1; i < uriParts.Count(); 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")

 Path.Combine("Http://MyUrl.com/", "/Images/Image.jpg").Replace("\\", "/") 

Acabei de montar o 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 inteligente, Ryan, para terminar com um link para a function. Bem feito.

Uma recomendação Brian: se você colocar este código em uma function, você pode querer usar um UriBuilder para envolver o URL base antes da chamada TryCreate.

Caso contrário, o URL base DEVE include 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"); } 

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 você pode usar a function utilitária Uri.TryCreate() . Em qualquer um dos casos, você pode acabar retornando um resultado incorreto porque esses methods 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; } 

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 3 casos mais comuns: insira a descrição da imagem aqui

Esta resposta provavelmente se perdeu em todas as respostas acima, mas descobri que o UriBuilder funcionava muito bem para esse tipo de coisa.

 UriBuilder urlb = new UriBuilder("http", _serverAddress, _webPort, _filePath); Uri url = urlb.Uri; return url.AbsoluteUri; 

Veja UriBuilder Class – MSDN para mais construtores e documentação.

Eu sei que isso foi respondido, mas uma maneira fácil de combiná-los e garantir que está sempre correta é ..

 string.Format("{0}/{1}", Url1.Trim('/'), Url2); 

Aqui está o método UrlUtility.Combine da Microsoft (OfficeDev PnP):

  const char PATH_DELIMITER = '/'; ///  /// Combines a path and a relative path. ///  ///  ///  ///  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

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 sei que estou atrasado para a festa, mas eu criei essa function que facilitará sua vida

  ///  /// the ultimate Path combiner of all time ///  ///  /// 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 ///  /// just adds the separator at the beginning /// fix the paths from within (by removing duplicate separators and correcting the separators) /// the paths to combine /// the combined path 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 tanto para URLs quanto 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 

Eu sei que esta pergunta é bem respondida, no entanto acho isso útil, pois tem os seguintes resources

  • Lança em espaço nulo ou branco
  • Classe estática que mais imita o System.Io.Path
  • params parâmetros params para vários segmentos de URL

Nota: O nome da class Url pode ser alterado, pois há uma class de sistema System.Security.Policy.Url

Classe

 public static class Url { private static string InternalCombine(string source, string dest) { // If the source is null or white space retune the dest only if (string.IsNullOrWhiteSpace(source)) { throw new ArgumentException("Cannot be null or white space", "source"); // throw new ArgumentException("Cannot be null or white space", nameof(source)); // c# 6.0 Nameof Expression } if (string.IsNullOrWhiteSpace(dest)) { throw new ArgumentException("Cannot be null or white space", "dest"); // throw new ArgumentException("Cannot be null or white space", nameof(dest)); // c# 6.0 Nameof Expression } source = source.TrimEnd('/', '\\'); dest = dest.TrimStart('/', '\\'); return string.Format("{0}/{1}", source, dest); // return $"{source}/{dest}"; // c# 6.0 string interpolation } public static string Combine(string source, params string[] args) { return args.Aggregate(source, InternalCombine); } } 

Resultados

 Url.Combine("test1", "test2"); Url.Combine("test1//", "test2"); Url.Combine("test1", "/test2"); // Result = test1/test2 Url.Combine(@"test1\/\/\/", @"\/\/\\\\\//test2", @"\/\/\\\\\//test3\") ; // Result = test1/test2/test3 Url.Combine("/test1/", "/test2/", null); Url.Combine("", "/test2/"); Url.Combine("/test1/", null); // Throws an ArgumentException 

Que tal agora?

  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); } } 

Aqui está a minha abordagem e eu vou usá-lo para mim também

 public static string UrlCombine(string part1, string part2) { string newPart1 = string.Empty; string newPart2 = string.Empty; string seprator = "/"; // if either part1 or part 2 is empty, // we don't need to combine with seprator if (string.IsNullOrEmpty(part1) || string.IsNullOrEmpty(part2)) { seprator = 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, seprator, newPart2); } 
  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 os benefícios de se comportar exatamente como Path.Combine

Regras ao combinar URLs com URI

Para evitar comportamentos estranhos, há uma regra a seguir:

  • caminho (diretório) deve terminar com ‘/’. Se o caminho terminar sem ‘/’, a última parte será tratada como um nome de arquivo e será concatenada ao tentar combinar com a próxima parte do URL.
  • há 1 exceção: o endereço URL base (sem informações de diretório) não precisa terminar com ‘/’
  • A parte do caminho não deve começar com ‘/’, se começar com ‘/’, todas as informações relativas existentes da URL serão eliminadas … adicionando string.Perfil da peça vazia 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 ‘diretório’ para 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(); }); 

Por que não apenas usar o seguinte.

 System.IO.Path.Combine(rootUrl, subPath).Replace(@"\", "/") 

Há um comentário de Todd Menier acima que Flurl inclui um Url.Combine.

Mais detalhes:

Url.Combine é basicamente um Path.Combine para URLs, garantindo um e apenas um caractere separador entre as partes:

 var url = Url.Combine( "http://foo.com/", "/too/", "/many/", "/slashes/", "too", "few?", "x=1", "y=2" // result: "http://www.foo.com/too/many/slashes/too/few?x=1&y=2" 

Mais sugestões … eu combinei todos os itens acima:

  public static string UrlPathCombine(string path1, string path2) { path1 = path1.TrimEnd('/') + "/"; path2 = path2.TrimStart('/'); return Path.Combine(path1, path2) .Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); } [TestMethod] public void TestUrl() { const string P1 = "http://msdn.microsoft.com/slash/library//"; Assert.AreEqual("http://msdn.microsoft.com/slash/library/site.aspx", UrlPathCombine(P1, "//site.aspx")); var path = UrlPathCombine("Http://MyUrl.com/", "Images/Image.jpg"); Assert.AreEqual( "Http://MyUrl.com/Images/Image.jpg", path); } 

Bem, apenas concateno duas strings e uso Expressões Regulares para fazer a parte de limpeza.

  public class UriTool { public static Uri Join(string path1, string path2) { string url = path1 + "/" + path2; url = Regex.Replace(url, "(?< !http:)/{2,}", "/"); return new Uri(url); } } 

Então, você pode usar assim:

  string path1 = "http://someaddress.com/something/"; string path2 = "/another/address.html"; Uri joinedUri = UriTool.Join(path1, path2); // joinedUri.ToString() returns "http://someaddress.com/something/another/address.html" 

Espero que possa ser útil para alguém!

Eu usei este código para resolver o problema:

 string[] brokenBaseUrl = Context.Url.TrimEnd('/').Split('/'); string[] brokenRootFolderPath = RootFolderPath.Split('/'); for (int x = 0; x < brokenRootFolderPath.Length; x++) { //if url doesn't already contain member, append it to the end of the string with / in front if (!brokenBaseUrl.Contains(brokenRootFolderPath[x])) { if (x == 0) { RootLocationUrl = Context.Url.TrimEnd('/'); } else { RootLocationUrl += String.Format("/{0}", brokenRootFolderPath[x]); } } } 

Ambos funcionam

  Uri final = new Uri(Regex.Replace(baseUrl + "/" + relativePath, "(?< !http:)/{2,}", "/")); 

Ou

  Uri final =new Uri(string.Format("{0}/{1}", baseUrl.ToString().TrimEnd('/'), relativePath.ToString().TrimStart('/'))); 

ou seja

E se

baseUrl = " http://tesrurl.test.com/Int18 "

e

relativePath = "To_Folder"

saída = http://tesrurl.test.com/Int18/To_Folder

Alguns erros aparecerão para o código abaixo

  // if you use below code, some issues will be there in final uri Uri final= new Uri(baseUrl ,relativePath ); 

Um simples forro:

 public static string Combine(this string uri1, string uri2) => $"{uri1.TrimEnd('/')}/{uri2.TrimStart('/')}"; 

Inspirado pela resposta do @Matt Sharpe.

We use the following simple helper method to join arbitrary number of URL parts together:

 public static string JoinUrlParts(params string[] urlParts) { return string.Join("/", urlParts.Where(up => !string.IsNullOrEmpty(up)).ToList().Select(up => up.Trim('/')).ToArray()); } 

Note, that it doesn’t support ‘../../something/page.htm’-style relative URL-s!

I have to point out that Path.Combine appears to work for this also directly atleast on .NET4