Bri*_*Kay 1186 .net c# asp.net url path
Path.Combine很方便,但在.NET框架中是否有类似的URL功能?
我正在寻找这样的语法:
Url.Combine("http://MyUrl.com/", "/Images/Image.jpg")
Run Code Online (Sandbox Code Playgroud)
将返回:
"http://MyUrl.com/Images/Image.jpg"
Joe*_*ham 1119
Uri
有一个构造函数,应该为您执行此操作: new Uri(Uri baseUri, string relativeUri)
这是一个例子:
Uri baseUri = new Uri("http://www.contoso.com");
Uri myUri = new Uri(baseUri, "catalog/shownew.htm");
Run Code Online (Sandbox Code Playgroud)
编者注意:请注意,此方法无法按预期工作.在某些情况下,它可以削减部分baseUri.查看评论和其他答案.
Mat*_*rpe 145
这可能是一个非常简单的解决方案:
public static string Combine(string uri1, string uri2)
{
uri1 = uri1.TrimEnd('/');
uri2 = uri2.TrimStart('/');
return string.Format("{0}/{1}", uri1, uri2);
}
Run Code Online (Sandbox Code Playgroud)
Rya*_*ook 143
你用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);
}
Run Code Online (Sandbox Code Playgroud)
将返回:
http://msdn.microsoft.com/en-us/library/system.uri.trycreate.aspx
Ale*_*ina 122
这里已经有了一些很棒的答案.基于mdsharpe建议,这里是一个扩展方法,可以在想要处理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('/'))));
}
}
Run Code Online (Sandbox Code Playgroud)
用法示例:
var url = new Uri("http://example.com/subpath/").Append("/part1/", "part2").AbsoluteUri;
Run Code Online (Sandbox Code Playgroud)
这将生成http://example.com/subpath/part1/part2
Bri*_*Kay 87
Ryan Cook的答案接近我所追求的,可能更适合其他开发人员.但是,它将http://添加到字符串的开头,并且通常它比我之后的格式更多.
另外,对于我的用例,解析相对路径并不重要.
mdsharp的答案还包含一个好主意的种子,尽管实际的实现需要更多细节才能完成.这是尝试充实它(我在生产中使用它):
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);
}
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
此代码通过以下测试,恰好在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
Run Code Online (Sandbox Code Playgroud)
MiF*_*vil 39
上面有一个Todd Menier的评论,Flurl包含了一个Url.Combine.
更多细节:
Url.Combine基本上是URL的Path.Combine,确保部分之间只有一个分隔符:
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"
Run Code Online (Sandbox Code Playgroud)
PM> Install-Package Flurl.Http
PM> Install-Package Flurl
小智 34
根据您提供的示例网址,我将假设您要组合相对于您网站的网址.
基于这个假设,我将提出这个解决方案作为对你的问题的最恰当的回答:"Path.Combine很方便,URL的框架中是否有类似的功能?"
由于URL框架中存在类似的功能,我建议正确的是:"VirtualPathUtility.Combine"方法.这是MSDN参考链接:VirtualPathUtility.Combine方法
有一点需要注意:我认为这仅适用于相对于您网站的网址(也就是说,您无法使用它来生成指向其他网站的链接.例如,var url = VirtualPathUtility.Combine("www.google.com", "accounts/widgets");
).
Mik*_*chs 30
Path.Combine对我不起作用,因为可能有像"|"这样的字符 在QueryString参数中,因此是URL,这将导致ArgumentException.
我首先尝试了新的Uri(Uri baseUri, string relativeUri)
方法,由于URI的原因,我失败了http://www.mediawiki.org/wiki/Special:SpecialPages
:
new Uri(new Uri("http://www.mediawiki.org/wiki/"), "Special:SpecialPages")
Run Code Online (Sandbox Code Playgroud)
将导致Special:SpecialPages,因为之后的冒号Special
表示一个方案.
所以我最终不得不采用mdsharpe/Brian MacKays路线并进一步开发它以处理多个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;
}
Run Code Online (Sandbox Code Playgroud)
用法: CombineUri("http://www.mediawiki.org/", "wiki", "Special:SpecialPages")
Jer*_*eir 22
Path.Combine("Http://MyUrl.com/", "/Images/Image.jpg").Replace("\\", "/")
Run Code Online (Sandbox Code Playgroud)
小智 17
我只是把一个小的扩展方法放在一起:
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('/');
}
Run Code Online (Sandbox Code Playgroud)
它可以像这样使用:
"www.example.com/".UriCombine("/images").UriCombine("first.jpeg");
Run Code Online (Sandbox Code Playgroud)
mta*_*zva 12
一个很好的例子,Ryan,以这个功能的链接结束.做得好.
一个建议Brian:如果将此代码包装在函数中,您可能希望在TryCreate调用之前使用UriBuilder来包装基本URL.
否则,基本URL必须包含该方案(UriBuilder将采用http://).只是一个想法:
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");
}
Run Code Online (Sandbox Code Playgroud)
小智 9
一种简单的方法来组合它们并确保它始终是正确的:
string.Format("{0}/{1}", Url1.Trim('/'), Url2);
Run Code Online (Sandbox Code Playgroud)
组合URL的多个部分可能有点棘手.您可以使用双参数构造函数Uri(baseUri, relativeUri)
,也可以使用Uri.TryCreate()
实用程序函数.
在这两种情况下,你可能最终会返回一个不正确的结果,因为这些方法不断截断相对部分关闭的第一个参数baseUri
,即从像http://google.com/some/thing
到http://google.com
.
为了能够将多个部分组合成最终的URL,您可以复制以下两个函数:
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;
}
Run Code Online (Sandbox Code Playgroud)
可以在https://uricombine.codeplex.com/SourceControl/latest#UriCombine/Uri.cs上找到用于演示用法的单元测试的完整代码.
我有单元测试来涵盖三种最常见的情况:
正如在其他答案中发现的那样,无论是新的Uri()
还是TryCreate()
可以打勾的。但是,基本的 Uri 必须以 结尾,/
而相对的不能以/
;开头。否则它将删除基本 URL 的尾随部分
我认为最好将其作为扩展方法来完成,即
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);
}
Run Code Online (Sandbox Code Playgroud)
并使用它:
var baseUri = new Uri("http://test.com/test/");
var combinedUri = baseUri.Append("/Do/Something");
Run Code Online (Sandbox Code Playgroud)
在性能方面,这消耗的资源比它需要的要多,因为 Uri 类做了很多解析和验证;一个非常粗略的分析(调试)在大约 2 秒内完成了一百万次操作。这适用于大多数场景,但是为了更高效,最好将所有内容都作为字符串进行操作,这需要 125 毫秒进行 100 万次操作。IE
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;
}
Run Code Online (Sandbox Code Playgroud)
如果您仍想返回 URI,则 100 万次操作大约需要 600 毫秒。
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);
}
Run Code Online (Sandbox Code Playgroud)
我希望这有帮助。
我认为这应该给你更大的灵活性,因为你可以根据需要处理尽可能多的路径段:
public static string UrlCombine(this string baseUrl, params string[] segments)
=> string.Join("/", new[] { baseUrl.TrimEnd('/') }.Concat(segments.Select(s => s.Trim('/'))));
Run Code Online (Sandbox Code Playgroud)
我发现UriBuilder
这种事情非常好用:
UriBuilder urlb = new UriBuilder("http", _serverAddress, _webPort, _filePath);
Uri url = urlb.Uri;
return url.AbsoluteUri;
Run Code Online (Sandbox Code Playgroud)
有关更多构造函数和文档,请参阅UriBuilder类 - MSDN.
所以我有另一种方法,类似于使用 UriBuilder 的每个人。
我不想像javajavajavajavajava那样分割我的 BaseUrl (它可以包含路径的一部分 - 例如http://mybaseurl.com/dev/)。
以下片段显示了代码+测试。
注意:此解决方案会小写主机并附加端口。如果不需要这样做,可以通过利用 的属性来编写字符串表示Uri
形式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));
}
}
Run Code Online (Sandbox Code Playgroud)
在 Windows 10 上使用 .NET Core 2.1 进行了测试。
为什么这有效?
尽管Path.Combine
会返回反斜杠(至少在 Windows 上),但 UriBuilder 在Path
.
取自https://github.com/dotnet/corefx/blob/master/src/System.Private.Uri/src/System/UriBuilder.cs(注意对 的调用string.Replace
)
[AllowNull]
public string Path
{
get
{
return _path;
}
set
{
if ((value == null) || (value.Length == 0))
{
value = "/";
}
_path = Uri.InternalEscapeString(value.Replace('\\', '/'));
_changed = true;
}
}
Run Code Online (Sandbox Code Playgroud)
这是最好的方法吗?
当然,这个解决方案是非常自我描述的(至少在我看来)。但是您依赖于 .NET API 中未记录的“功能”(至少我通过快速谷歌搜索没有找到任何内容)。这可能会随着未来的版本而改变,因此请通过测试覆盖该方法。
https://github.com/dotnet/corefx/blob/master/src/System.Private.Uri/tests/FunctionalTests/UriBuilderTests.cs ( )中有一些测试Path_Get_Set
,检查是否\
正确转换。
旁注:UriBuilder.Uri
如果 uri 将用于 ctor,则还可以直接使用该属性System.Uri
。
对于任何正在寻找单行代码并且只想连接部分路径而不创建新方法或引用新库或构建 URI 值并将其转换为字符串的人,那么...
string urlToImage = String.Join("/", "websiteUrl", "folder1", "folder2", "folder3", "item");
Run Code Online (Sandbox Code Playgroud)
这是非常基本的,但我不明白你还需要什么。如果你害怕重复的“/”,那么你可以简单地.Replace("//", "/")
在后面做一个。如果您害怕替换“https://”中的双倍“//”,那么可以做一次连接,替换双倍“/”,然后加入网站网址(但是我很确定大多数浏览器会自动转换前面带有“https:”的任何内容,以便以正确的格式读取)。这看起来像:
string urlToImage = String.Join("/","websiteUrl", String.Join("/", "folder1", "folder2", "folder3", "item").Replace("//","/"));
Run Code Online (Sandbox Code Playgroud)
这里有很多答案可以处理上述所有问题,但就我而言,我只需要在一个位置使用一次,并且不需要严重依赖它。而且,很容易看出这里发生了什么。
请参阅:https ://learn.microsoft.com/en-us/dotnet/api/system.string.join?view=netframework-4.8
小智 6
如果你不想有像 Flurl 这样的依赖,你可以使用它的源代码:
/// <summary>
/// Basically a Path.Combine for URLs. Ensures exactly one '/' separates each segment,
/// and exactly on '&' separates each query parameter.
/// URL-encodes illegal characters but not reserved characters.
/// </summary>
/// <param name="parts">URL parts to combine.</param>
public static string Combine(params string[] parts) {
if (parts == null)
throw new ArgumentNullException(nameof(parts));
string result = "";
bool inQuery = false, inFragment = false;
string CombineEnsureSingleSeparator(string a, string b, char separator) {
if (string.IsNullOrEmpty(a)) return b;
if (string.IsNullOrEmpty(b)) return a;
return a.TrimEnd(separator) + separator + b.TrimStart(separator);
}
foreach (var part in parts) {
if (string.IsNullOrEmpty(part))
continue;
if (result.EndsWith("?") || part.StartsWith("?"))
result = CombineEnsureSingleSeparator(result, part, '?');
else if (result.EndsWith("#") || part.StartsWith("#"))
result = CombineEnsureSingleSeparator(result, part, '#');
else if (inFragment)
result += part;
else if (inQuery)
result = CombineEnsureSingleSeparator(result, part, '&');
else
result = CombineEnsureSingleSeparator(result, part, '/');
if (part.Contains("#")) {
inQuery = false;
inFragment = true;
}
else if (!inFragment && part.Contains("?")) {
inQuery = true;
}
}
return EncodeIllegalCharacters(result);
}
/// <summary>
/// URL-encodes characters in a string that are neither reserved nor unreserved. Avoids encoding reserved characters such as '/' and '?'. Avoids encoding '%' if it begins a %-hex-hex sequence (i.e. avoids double-encoding).
/// </summary>
/// <param name="s">The string to encode.</param>
/// <param name="encodeSpaceAsPlus">If true, spaces will be encoded as + signs. Otherwise, they'll be encoded as %20.</param>
/// <returns>The encoded URL.</returns>
public static string EncodeIllegalCharacters(string s, bool encodeSpaceAsPlus = false) {
if (string.IsNullOrEmpty(s))
return s;
if (encodeSpaceAsPlus)
s = s.Replace(" ", "+");
// Uri.EscapeUriString mostly does what we want - encodes illegal characters only - but it has a quirk
// in that % isn't illegal if it's the start of a %-encoded sequence /sf/answers/3334522621/
// no % characters, so avoid the regex overhead
if (!s.Contains("%"))
return Uri.EscapeUriString(s);
// pick out all %-hex-hex matches and avoid double-encoding
return Regex.Replace(s, "(.*?)((%[0-9A-Fa-f]{2})|$)", c => {
var a = c.Groups[1].Value; // group 1 is a sequence with no %-encoding - encode illegal characters
var b = c.Groups[2].Value; // group 2 is a valid 3-character %-encoded sequence - leave it alone!
return Uri.EscapeUriString(a) + b;
});
}
Run Code Online (Sandbox Code Playgroud)
我发现以下有用并具有以下功能:
params
为多个 Url 段参数班级
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);
}
Run Code Online (Sandbox Code Playgroud)
测试
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
Run Code Online (Sandbox Code Playgroud)
我有一个免分配字符串创建版本,我一直在使用它并取得了巨大成功。
笔记:
TrimEnd(separator)
对于第一个字符串:它使用- 所以仅从字符串末尾修剪分隔符。Trim(separator)
对于余数:它使用- 所以路径的开始和结束来修剪分隔符希望你觉得这个有用!
/// <summary>
/// This implements an allocation-free string creation to construct the path.
/// This uses 3.5x LESS memory and is 2x faster than some alternate methods (StringBuilder, interpolation, string.Concat, etc.).
/// </summary>
/// <param name="str"></param>
/// <param name="paths"></param>
/// <returns></returns>
public static string ConcatPath(this string str, params string[] paths)
{
const char separator = '/';
if (str == null) throw new ArgumentNullException(nameof(str));
var list = new List<ReadOnlyMemory<char>>();
var first = str.AsMemory().TrimEnd(separator);
// get length for intial string after it's trimmed
var length = first.Length;
list.Add(first);
foreach (var path in paths)
{
var newPath = path.AsMemory().Trim(separator);
length += newPath.Length + 1;
list.Add(newPath);
}
var newString = string.Create(length, list, (chars, state) =>
{
// NOTE: We don't access the 'list' variable in this delegate since
// it would cause a closure and allocation. Instead we access the state parameter.
// track our position within the string data we are populating
var position = 0;
// copy the first string data to index 0 of the Span<char>
state[0].Span.CopyTo(chars);
// update the position to the new length
position += state[0].Span.Length;
// start at index 1 when slicing
for (var i = 1; i < state.Count; i++)
{
// add a separator in the current position and increment position by 1
chars[position++] = separator;
// copy each path string to a slice at current position
state[i].Span.CopyTo(chars.Slice(position));
// update the position to the new length
position += state[i].Length;
}
});
return newString;
}
Run Code Online (Sandbox Code Playgroud)
与基准 DotNet 输出:
| Method | Mean | Error | StdDev | Median | Ratio | RatioSD | Gen 0 | Allocated |
|---------------------- |---------:|---------:|---------:|---------:|------:|--------:|-------:|----------:|
| ConcatPathWithBuilder | 404.1 ns | 27.35 ns | 78.48 ns | 380.3 ns | 1.00 | 0.00 | 0.3347 | 1,400 B |
| ConcatPath | 187.2 ns | 5.93 ns | 16.44 ns | 183.2 ns | 0.48 | 0.10 | 0.0956 | 400 B |
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
286103 次 |
最近记录: |