Flurl inclui um Url.Combinemétodo que faz exatamente isso.
21414 Todd Menier
2
Na verdade, o // é tratado pelo roteamento do site ou servidor e não pelo navegador. Ele enviará o que você colocar na barra de endereço. É por isso que obtemos problemas ao digitar htp: // em vez de http: // Portanto, o // pode causar grandes problemas em alguns sites. Estou escrevendo uma DLL para um rastreador que lida com um site específico que lança um 404 se você tiver // no URL.
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"
Bem, essa pergunta recebe muito tráfego e a resposta com mais de 1000 upvotes na verdade não funciona em todos os casos. Anos depois, eu realmente uso o Flurl para isso, então estou aceitando este. Parece funcionar em todos os casos que encontrei. Se as pessoas não querem assumir uma dependência, postei uma resposta que também funciona bem.
Uri tem um construtor que deve fazer isso por você: new Uri(Uri baseUri, string relativeUri)
Aqui está um exemplo:
Uri baseUri =newUri("http://www.contoso.com");Uri myUri =newUri(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.
Gosto do uso da classe Uri, infelizmente ela não se comportará como Path.Combine, como o OP pediu. Por exemplo, novo Uri (novo Uri (" test.com/mydirectory/" ), "/helloworld.aspx"). ToString () fornece " test.com/helloworld.aspx "; o que seria incorreto se desejássemos um resultado no estilo Path.Combine.
Doctor Jones
195
Está tudo nas barras. Se a parte do caminho relativo começar com uma barra, ela se comportará como você descreveu. Mas, se você deixar a barra de fora, ela funcionará da maneira que você esperaria (observe a barra ausente no segundo parâmetro): new Uri (new Uri (nova Uri (" test.com/mydirectory/" ), "helloworld.aspx" ) .ToString () resulta em " test.com/mydirectory/helloworld.aspx ". Path.Combine se comporta de maneira semelhante. Se o parâmetro relativo do caminho começar com uma barra, ele retornará apenas o caminho relativo e não os combinará.
Joel Beckham
70
Se o seu baseUri fosse "test.com/mydirectory/mysubdirectory", o resultado seria "test.com/mydirectory/helloworld.aspx" em vez de "test.com/mydirectory/mysubdirectory/helloworld.aspx". A diferença sutil é a falta de barra final no primeiro parâmetro. Sou a favor do uso de métodos de estrutura existentes, se eu já tiver a barra final, acho que fazer partUrl1 + partUrl2 cheira muito menos - eu poderia estar perseguindo essa barra final por um bom tempo por não fazer concatenação de cordas.
Carl
64
A única razão pela qual eu quero um método de combinação de URI é para que eu não precise verificar a barra final. Request.ApplicationPath é '/' se seu aplicativo estiver na raiz, mas '/ foo' se não estiver.
23411 nickd em
24
Eu -1 esta resposta porque isso não responde ao problema. Quando você deseja combinar o URL, como quando deseja usar o Path.Combine, não deseja se preocupar com o / final. e com isso, você tem que se importar. Eu prefiro solução de Brian MacKay ou mdsharpe acima
+1: Embora isso não lide com caminhos de estilo relativo (../../whatever.html), eu gosto deste por sua simplicidade. Eu também adicionaria guarnições para o caractere '\'.
Brian MacKay
3
Veja minha resposta para uma versão mais completa disso.
quer
149
Você usa Uri.TryCreate( ... ):
Uri result =null;if(Uri.TryCreate(newUri("http://msdn.microsoft.com/en-us/library/"),"/en-us/library/system.uri.trycreate.aspx",out result)){Console.WriteLine(result);}
+1: Isso é bom, embora eu tenha um problema irracional com o parâmetro de saída. ;)
Brian MacKay
10
@ Brian: se ajudar, todos os métodos TryXXX ( 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.
Abel
41
Esta resposta sofre o mesmo problema que o de Joel : ingressar test.com/mydirectory/e /helloworld.aspxresultará no test.com/helloworld.aspxque aparentemente não é o que você deseja.
precisa saber é o seguinte
3
Olá, isso falhou no seguinte: if (Uri.TryCreate (new Uri (" localhost / MyService /" ), "/ Event / SomeMethod? Abc = 123", resultado final)) {Console.WriteLine (resultado); } Ele está mostrando me resultar como: localhost / evento / SomeMethod abc = 123? Nota: "http: //" é substituída a partir da base Uri aqui por stackoverflow
Faisal Mq
3
@FaisalMq Esse é o comportamento correto, desde que você passou um segundo parâmetro relativo à raiz. Se você tivesse deixado de fora o líder / o segundo parâmetro, teria obtido o resultado esperado.
precisa saber é o seguinte
127
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;publicstaticclassUriExtensions{publicstaticUriAppend(thisUri uri,paramsstring[] paths){returnnewUri(paths.Aggregate(uri.AbsoluteUri,(current, path)=>string.Format("{0}/{1}", current.TrimEnd('/'), path.TrimStart('/'))));}}
E exemplo de uso:
var url =newUri("http://example.com/subpath/").Append("/part1/","part2").AbsoluteUri;
Essa solução torna trivial escrever um método estático UriUtils.Combine ("base url", "part1", "part2", ...) que é muito semelhante ao Path.Combine (). Agradável!
Angularsen
Para dar suporte aos URIs relativos, tive que usar ToString () em vez de AbsoluteUri e UriKind.AbsoluteOrRelative no construtor Uri.
Angularsen
Obrigado pela dica sobre o Uris relativo. Infelizmente, o Uri não facilita o manuseio de caminhos relativos, pois sempre há algum problema com o Request.ApplicationPath envolvido. Talvez você também possa tentar usar o novo Uri (HttpContext.Current.Request.ApplicationPath) como base e apenas chamar Anexar? Isso fornecerá caminhos absolutos, mas deve funcionar em qualquer lugar da estrutura do site.
Ales Potocnik Hahonina
Ótimo. Ainda bem que ajudou alguém. Estou usando isso há algum tempo e não tive nenhum problema.
Ales Potocnik Hahonina
Também adicionei a verificação se algum dos caminhos a serem anexados não é nulo nem vazio.
precisa saber é o seguinte
92
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):
Falando de detalhes: e o obrigatório 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.
Abel
4
você pode usar params string [] e de forma recursiva se juntar a eles para permitir que mais de 2 combinações
jaider
4
Eu certamente gostaria que isso estivesse na Biblioteca de Classes Base, como Path.Combine.
Uriah Blatherwick
1
@ MarkHurd Editei o código novamente, para que ele seja comportamentalmente igual ao C # e sintaticamente equivalente também.
JJS 07/07
1
@BrianMacKay i partiu-o, markhurd apontou meu erro e rolou para trás, eu atualizado novamente ... aplausos
JJS
36
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:
resultará em Special: SpecialPages, por causa dos dois pontos depois Specialque 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:
publicstaticstringCombineUri(paramsstring[] uriParts){string uri =string.Empty;if(uriParts !=null&& uriParts.Length>0){char[] trims =newchar[]{'\\','/'};
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;}
+1: Agora estamos conversando ... vou tentar isso. Isso pode até acabar sendo a nova resposta aceita. Depois de tentar o novo método Uri (), eu realmente não gosto. Muito finnicky.
precisa
Isso é exatamente o que eu precisava! Não era um fã de ter que cuidar onde eu coloquei arrastando barras, etc ...
Gromer
+1 para rolar na verificação nula, para que não explodir.
precisa
Count () deve ser Length, para que você não precise incluir o Linq na sua biblioteca apenas para isso.
PRMan
Era exatamente isso que eu estava procurando.
ThePeter
34
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");).
+1 porque está próximo do que estou procurando, embora seja ideal se funcione para qualquer URL antigo. Dobro, ficará muito mais elegante do que o que o mdsharpe propôs.
Brian MacKay
2
A ressalva está correta, não pode funcionar com uris absolutos e o resultado é sempre relativo a partir da raiz. Mas tem um benefício adicional, processa o til, como em "~ /". Isso o torna um atalho Server.MapPathe combinação.
Para fazê-lo funcionar, você deve remover o primeiro / o segundo argumento, ou seja, "/ Images" - / Path.Combine (" Http://MyUrl.com ", "Images / Image.jpg")
Por G
8
@SliverNinja Isso não está correto O valor desse campo é uma barra invertida ('\') no UNIX e uma barra ('/') nos sistemas operacionais Windows e Macintosh. Ao usar o Mono em um sistema Linux, você obteria o separador errado.
user247702
6
Todos os que estão pesquisando no separador de diretório estão esquecendo que as seqüências de caracteres podem ter vindo de um sistema operacional diferente do que você está agora. Basta substituir a barra invertida por barra e você estará coberto.
+1, embora isso seja muito semelhante à resposta do mdsharpe, que aprimorei na minha resposta. Esta versão funciona muito bem, a menos que o Url2 inicie com / ou \, ou o Url1 termine acidentalmente em \, ou se um estiver vazio! :)
Brian MacKay
9
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/thingpara http://google.com.
Para poder combinar várias partes em um URL final, você pode copiar as duas funções abaixo:
publicstaticstringCombine(paramsstring[] parts){if(parts ==null|| parts.Length==0)returnstring.Empty;var urlBuilder =newStringBuilder();foreach(var part in parts){var tempUrl = tryCreateRelativeOrAbsolute(part);
urlBuilder.Append(tempUrl);}returnVirtualPathUtility.RemoveTrailingSlash(urlBuilder.ToString());}privatestaticstring tryCreateRelativeOrAbsolute(string s){System.Uri uri;System.Uri.TryCreate(s,UriKind.RelativeOrAbsolute,out uri);string tempUrl =VirtualPathUtility.AppendTrailingSlash(uri.ToString());return tempUrl;}
Parece muito bom para mim. Embora você possa substituir o loop I por um loop foreach para melhor clareza.
Chris Marisic
Obrigado Chris. Acabei de alterar meu código para usar o Foreach.
Believe2014
1
+1 para todo o esforço extra. Eu preciso manter essa pergunta um pouco para algumas das respostas mais votadas, você jogou a manopla. ;)
Brian MacKay
Desculpe, mas não o suficiente. Funciona nos poucos casos que você mostra, mas está longe de ser utilizável em todas as combinações. Por exemplo, dois pontos no caminho causarão danos.
Gábor
Você pode dar um exemplo do que você quer dizer? Ficarei feliz em corrigir o problema e ajudar os próximos usuários.
usar o seguinte
7
Eu achei que UriBuilderfuncionou muito bem para esse tipo de coisa:
Parece que isso pode ser para caminhos, e não para URLs.
Brian MacKay
@BrianMacKay Concordaram que se parece com isto, mas é a partir da classe UrlUtility e utilizada no contexto da combinação de URLs
2
Editado para esclarecer a qual classe pertence #
Tome cuidado ao usar esta classe, o restante da classe contém artefatos específicos do SharePoint.
Harry Berry
4
Acho o seguinte útil e possui os seguintes recursos:
Lança espaço nulo ou em branco
Toma vários paramsparâmetros para vários segmentos de URL
lança em nulo ou vazio
Classe
publicstaticclassUrlPath{privatestaticstringInternalCombine(string source,string dest){if(string.IsNullOrWhiteSpace(source))thrownewArgumentException("Cannot be null or white space", nameof(source));if(string.IsNullOrWhiteSpace(dest))thrownewArgumentException("Cannot be null or white space", nameof(dest));return $"{source.TrimEnd('/', '\\')}/{dest.TrimStart('/', '\\')}";}publicstaticstringCombine(string source,paramsstring[] args)=> args.Aggregate(source,InternalCombine);}
Testes
UrlPath.Combine("test1","test2");UrlPath.Combine("test1//","test2");UrlPath.Combine("test1","/test2");// Result = test1/test2UrlPath.Combine(@"test1\/\/\/",@"\/\/\\\\\//test2",@"\/\/\\\\\//test3\");// Result = test1/test2/test3UrlPath.Combine("/test1/","/test2/",null);UrlPath.Combine("","/test2/");UrlPath.Combine("/test1/",null);// Throws an ArgumentException
Alguns problemas com os testes: // Resultado = test1 / test2 / test3 \ para o quarto e último dos testes de arremessos fornecem ArgumentNullException em vez de ArgumentException
Moriya
3
Minha solução genérica:
publicstaticstringCombine(paramsstring[] uriParts){string uri =string.Empty;if(uriParts !=null&& uriParts.Any()){char[] trims =newchar[]{'\\','/'};
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;}
Esse método auxiliar é muito flexível e funciona bem em muitos casos de uso diferentes. Obrigado!
Shiva
3
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>publicstaticstringPathCombine(boolIsURL,boolIsRelative,boolIsFixInternal,paramsstring[] parts){if(parts ==null|| parts.Length==0)returnstring.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;}
Eu estava olhando para a versão PowerShell deste que seria: [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")
Underverse 6/18
Boa ideia, mas falha, quando um dos parâmetros é nulo.
Pholpar # 22/18
2
Regras ao combinar URLs com um URI
Para evitar comportamentos estranhos, há uma regra a seguir:
O 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 da URL.
Há uma exceção: o endereço URL base (sem informações do 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 string.Emptyserã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 ...
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 PathStringque se destina ao objetivo de criar URI caminhos. Você pode criar seu URI completo usando uma combinação disso Urie UriBuilder.
Isso fornece todas as partes constituintes sem a necessidade de especificar os separadores no URL base. Infelizmente, PathStringrequer 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.
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 Uripropriedade de UriBuilder.
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.
Esta é uma abordagem muito confiável. Polegares para cima para o teste de unidade !!
aggsol
2
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 ...
É 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:
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.
Aqui está minha abordagem e também a utilizarei para mim:
publicstaticstringUrlCombine(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 seperatorif(string.IsNullOrEmpty(part1)||string.IsNullOrEmpty(part2)){
seperator =string.Empty;}// If part1 is not empty,// remove '/' at lastif(!string.IsNullOrEmpty(part1)){
newPart1 = part1.TrimEnd('/');}// If part2 is not empty,// remove '/' at firstif(!string.IsNullOrEmpty(part2)){
newPart2 = part2.TrimStart('/');}// Now finally combinereturnstring.Format("{0}{1}{2}", newPart1, seperator, newPart2);}
Isso é aceitável apenas para o seu caso. Há casos que podem danificar seu código. Além disso, você não fez a codificação adequada das partes do caminho. Essa pode ser uma enorme vulnerabilidade quando se trata de ataques de script entre sites.
Believe2014
Eu concordo com seus pontos. O código deve fazer apenas uma combinação simples de duas partes de URL.
Toque agradável com 'WebPath'. :) O código pode ser desnecessariamente denso - é difícil para mim olhar para isso e dizer: sim, isso é perfeito. Isso me faz querer ver testes de unidade. Talvez seja só eu!
precisa
1
x.StartsWith ("/") &&! x.StartsWith ("http") - por que o http verifica? o que você ganha?
Penguat
Você não deseja remover a barra se ela começar com http.
27413 Martin Murphy
@BrianMacKay, não tenho certeza de que dois revestimentos justifiquem um teste de unidade, mas se você quiser, faça um teste. Não é como se eu estivesse aceitando patches ou algo assim, mas fique à vontade para editar a sugestão.
27413 Martin Murphy
1
Eu descobri que o Uriconstrutor vira '\' em '/'. Então você também pode usar Path.Combine, com o Uriconstrutor.
Uri baseUri =newUri("http://MyUrl.com");string path =Path.Combine("Images","Image.jpg");Uri myUri =newUri(baseUri, path);
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,
var baseUri =newUri("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,
publicstaticstringAppend(thisUri 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 itvar 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.
publicstaticUriAppendUri(thisUri 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 itvar baseUri = absoluteUri.EndsWith('/')? absoluteUri : absoluteUri +'/';var relative = relativePath.StartsWith('/')? relativePath.Substring(1): relativePath;returnnewUri(baseUri + relative);}
Url.Combine
método que faz exatamente isso.Respostas:
Há um comentário de Todd Menier acima de que Flurl inclui um
Url.Combine
.Mais detalhes:
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
fonte
Flurl
e seria perfer uma versão leve, github.com/jean-lourenco/UrlCombineUri
tem um construtor que deve fazer isso por você:new Uri(Uri baseUri, string relativeUri)
Aqui está um exemplo:
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.
fonte
Esta pode ser uma solução adequadamente simples:
fonte
Você usa
Uri.TryCreate( ... )
:Retornará:
fonte
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á notest.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:
E exemplo de uso:
Isso produzirá http://example.com/subpath/part1/part2
fonte
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 #
VB.NET
Esse código passa no seguinte teste, que acontece no VB:
fonte
ArgumentNullException("url1")
se o argumento forNothing
? 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 comohttp://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:
Uso:
CombineUri("http://www.mediawiki.org/", "wiki", "Special:SpecialPages")
fonte
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");
).fonte
Server.MapPath
e combinação.fonte
path.Replace(Path.DirectorySeparatorChar, '/');
path.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)
Acabei de montar um pequeno método de extensão:
Pode ser usado assim:
fonte
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:
fonte
Uma maneira fácil de combiná-los e garantir que esteja sempre correto é:
fonte
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 aUri.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 comohttp://google.com/some/thing
parahttp://google.com
.Para poder combinar várias partes em um URL final, você pode copiar as duas funções abaixo:
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:
fonte
Eu achei que
UriBuilder
funcionou muito bem para esse tipo de coisa:Consulte Classe UriBuilder - MSDN para obter mais construtores e documentação.
fonte
Aqui está o método UrlUtility.Combine da Microsoft (OfficeDev PnP) :
Fonte: GitHub
fonte
Acho o seguinte útil e possui os seguintes recursos:
params
parâmetros para vários segmentos de URLClasse
Testes
fonte
Minha solução genérica:
fonte
Eu criei esta função que facilitará sua vida:
Funciona para URLs e para caminhos normais.
Uso:
fonte
Por que não usar apenas o seguinte.
fonte
[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 ...
fonte
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 dissoUri
eUriBuilder
.Nesse caso, seria:
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 umArgumentException
! Mas pelo menos você pode criar seu URI deterministicamente de uma maneira que seja facilmente testável por unidade.fonte
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 deUriBuilder
.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 dePath
.Retirado de https://github.com/dotnet/corefx/blob/master/src/System.Private.Uri/src/System/UriBuilder.cs (lembre-se da chamada para
string.Replace
)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 umSystem.Uri
ctor.fonte
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 ...
É 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: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
fonte
Usar:
Tem o benefício de se comportar exatamente como
Path.Combine
.fonte
Aqui está minha abordagem e também a utilizarei para mim:
fonte
Usa isto:
fonte
Eu descobri que o
Uri
construtor vira '\' em '/'. Então você também pode usarPath.Combine
, com oUri
construtor.fonte
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.
fonte
Como encontrado em outras respostas, novo
Uri()
ouTryCreate()
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 baseEu acho que isso é melhor feito como um método de extensão, ou seja,
e para usá-lo:
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,
E se você ainda deseja retornar um URI, leva cerca de 600 milissegundos para 1 milhão de operações.
Eu espero que isso ajude.
fonte
Eu acho que isso deve lhe dar mais flexibilidade, pois você pode lidar com quantos segmentos de caminho desejar:
fonte