Update: A fix has now made it's way into mono. This is good news!
Updated: Added logic to fix fragment handling.
I am trying to send a request with an encoded slash on Mono using the Uri class. This is basically the Mono equivalent of this question: GETting a URL with an url-encoded slash
The issue is that Mono similar to .NET will unescape any slashes it finds in the Uri when it is constructed. This logic was originally put in in place in order to remove vulnerabilities that could occur if paths were escape encoded and not detected.
In the previous post there is a hack which shows setting flags on the underlying Uri class via reflection which force the escaped slashes to be left alone. This behavior has been fixed in .NET 4.5 and by default the escaped slashes are allowed (as I mentioned in the comments).
I tried to do the same on Mono, but it fails as the internals of the Uri class are different. I came up with this approach to achieve what I want, which works but it is TERRIBLY hacky.
class Program
{
static void Main(string[] args)
{
var uri = new Uri("http://www.yahoo.com/%2F?Foo=Bar%2F#frag");
UriHelper.ForceCanonicalPathAndQuery(uri);
Console.WriteLine ("uri.ToString() - " + uri.ToString ());
Console.WriteLine ("uri.AbsoluteUri - " + uri.AbsoluteUri);
Console.WriteLine ("uri.Host - " + uri.Host);
Console.WriteLine ("uri.Query - " + uri.Query);
Console.WriteLine ("uri.PathAndQuery - " + uri.PathAndQuery);
Console.WriteLine ("uri.AbsolutePath - " + uri.AbsolutePath);
Console.WriteLine ("uri.Fragment - " + uri.Fragment);
}
public class UriHelper {
private static Type uriType = typeof(Uri);
private static FieldInfo sourceField;
private static FieldInfo queryField;
private static FieldInfo pathField;
private static FieldInfo cachedToStringField;
private static FieldInfo cachedAbsoluteUriField;
static UriHelper ()
{
sourceField = uriType.GetField ("source", BindingFlags.NonPublic | BindingFlags.Instance);
queryField = uriType.GetField ("query", BindingFlags.NonPublic | BindingFlags.Instance);
pathField = uriType.GetField ("path", BindingFlags.NonPublic | BindingFlags.Instance);
cachedToStringField = uriType.GetField ("cachedToString", BindingFlags.NonPublic | BindingFlags.Instance);
cachedAbsoluteUriField = uriType.GetField ("cachedAbsoluteUri", BindingFlags.NonPublic | BindingFlags.Instance);
}
public static void ForceCanonicalPathAndQuery(Uri uri)
{
var source = (string) sourceField.GetValue (uri);
cachedToStringField.SetValue (uri, source);
cachedAbsoluteUriField.SetValue (uri, source);
var fragPos = source.IndexOf ("#");
var queryPos = source.IndexOf ("?");
var start = source.IndexOf (uri.Host) + uri.Host.Length;
var pathEnd = queryPos == -1 ? fragPos : queryPos;
if (pathEnd == -1)
pathEnd = source.Length+1;
var path = queryPos > -1 ? source.Substring (start, pathEnd - start) : source.Substring (start);
pathField.SetValue (uri, path);
queryField.SetValue(uri, fragPos > -1 ? source.Substring(queryPos, fragPos - queryPos) : source.Substring(queryPos));
}
}
}
When you run this, it outputs the following:
uri.ToString() - http://www.yahoo.com/%2F?Foo=Bar%2F#frag
uri.AbsoluteUri - http://www.yahoo.com/%2F?Foo=Bar%2F#frag
uri.Host - www.yahoo.com
uri.Query - ?Foo=Bar%2F
uri.PathAndQuery - /%2F?Foo=Bar%2F
uri.AbsolutePath - /%2F
uri.Fragment - #frag
I don't at all feel good about it, but it does work, at least for the basic scenario of taking a Uri and issuing a query.
I might be missing something in the Uri class, so if you have a better / less hacky way to do what I am doing here, I'd really appreciate it.
From the original question, it looks like the behaviour of MS.NET changed in .NET 4.5 to fix the bug.
Indeed, then, it is a bug in mono for not following the behaviour change in the .NET 4.5 profile. And it seems someone already fixed the bug and proposed a pull request, the problem is that nobody in the Mono team seems to have found the time to review it: https://github.com/mono/mono/pull/619
Related
I am not new to OOP, but am new to Reflection. I'm sure I'm missing something simple and have experimented for some time before posting.
I have been trying to get access to a field, both get and set, its value. The issue is the field is within property of a class within a property of a class.
The following code gets an existing window and works deeper into the classes until I hit a wall.
Ultimately I want to get and set "k_LineHeight" inside of an existing instance of TreeViewGUI.
The following code is heavily annotated. Thank you for taking the time to look at this. In Unity's Mono Debug.Log() is the equivalent of write to the console.
// Get the assembly
Assembly asm = typeof(UnityEditor.EditorWindow).Assembly;
Debug.Log (asm + "\n"); // returns -> UnityEditor, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
// Get the Type of SceneHierarchyWindow from 'asm'
Type wndType = asm.GetType("UnityEditor.SceneHierarchyWindow");
Debug.Log (wndType + "\n"); // returns -> UnityEditor.SceneHierarchyWindow <- Type
// 'GetWindow' retrieves the ACTIVE instance of the windows currently open
EditorWindow wnd = EditorWindow.GetWindow(wndType);
Debug.Log (wnd + "\n"); // returns -> U (UnityEditor.SceneHierarchyWindow) <- Active Object
// Retrieves the ACTIVE TreeView class stored in 'treeView' from 'wnd'
var treeViewVal = wndType.GetProperty("treeView", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(wnd, null);
Debug.Log (treeViewVal + "\n"); // returns -> UnityEditor.TreeView
// Retrieves the property 'state' that is (public TreeViewState state { get; set; }) inside of 'treeViewVal'
var stateVal = treeViewVal.GetType().GetProperty("state").GetValue(treeViewVal, null);
Debug.Log (stateVal + "\n"); // returns UnityEditor.TreeViewState
// Retrive the value of the field 'scrollPos' (public Vector2 scrollPos;) inside of the 'stateVal'
var v2 = (Vector2)stateVal.GetType ().GetField ("scrollPos").GetValue (stateVal);
Debug.Log (v2 + "\n"); // returns -> (0.0, 0.0)
/// ALL OF THE ABOVE WORKS AS EXPECTED THE FOLLOWING IS WHERE IM STUMPED ///
// Retrieves the property 'gui' that is ( internal class GameObjectTreeViewGUI : TreeViewGUI) inside of 'treeViewVal'
var guiVal = treeViewVal.GetType().GetProperty("gui").GetValue(treeViewVal, null);
Debug.Log (guiVal + "\n"); // returns -> UnityEditor.GameObjectTreeViewGUI <- Type but I believe I need the Object
// THIS is where I'm stuck...
// Should retrieve the value of the field 'k_LineHeight' (protected float k_LineHeight = 16f;) inside of 'TreeViewGUI' the
var k_Line = guiVal.GetType().GetField ("k_LineHeight").GetValue (guiVal);
Debug.Log (k_Line + "\n"); // returns -> NullReferenceException: Object reference not set to an instance of an object
// If I attempt to ...
Type testType = guiVal.GetType ();
object test = Activator.CreateInstance(testType);
Debug.Log (test + "\n"); // returns -> Method not found: 'Default constructor not found...ctor() of UnityEditor.GameObjectTreeViewGUI'.
UPDATE :
// ORIGINAL LINE
var k_LineA = guiVal.GetType().GetField ("k_LineHeight").GetValue(guiVal);
Debug.Log (k_LineA + "\n"); // returns-> Object reference not set to an instance of an object.
// SUGGESTED PART ONE
var k_LineB = guiVal.GetType().BaseType;
Debug.Log (k_LineB + "\n"); // returns -> UnityEditor.TreeViewGUI <- This is correct
// SUGGESTED PART TWO - > Have tried with an without various flags
var k_LineC = guiVal.GetType().BaseType.GetField("k_LineHeight", BindingFlags.Instance |
BindingFlags.Static |
BindingFlags.NonPublic |
BindingFlags.Public).GetValue(guiVal);
Debug.Log (k_LineC + "\n"); // returns -> Object reference not set to an instance of an object.
// GetValue wants guiVal to be an object???
// First part of UnityEditor.TreeViewGUI Class
namespace UnityEditor
{
internal abstract class TreeViewGUI : ITreeViewGUI
{
protected PingData m_Ping = new PingData();
private bool m_AnimateScrollBarOnExpandCollapse = true;
protected float k_LineHeight = 16f;
protected float k_BaseIndent = 2f;
protected float k_IndentWidth = 14f;
protected float k_FoldoutWidth = 12f;
protected float k_IconWidth = 16f;
protected float k_SpaceBetweenIconAndText = 2f;
protected float k_HalfDropBetweenHeight = 4f;
protected TreeView m_TreeView;
...
Thanks to your suggestion I am now into the proper class. Feel silly I didn't think of that. Unfortunately its still returning the same during access. GetValue wants guiVal to be an object???
Seems closer, anyone have additional thoughts?
You are trying to log an Object and not a Type.. Type is an attribute of an object defining what kind of type the object is, while Object is the class
k_LineHeight isn't a field in UnityEditor.GameObjectTreeViewGUI.
https://github.com/MattRix/UnityDecompiled/blob/master/UnityEditor/UnityEditor/GameObjectTreeViewGUI.cs
GameObjectTreeViewGUI inherits from TreeViewGUI. I googled and didn't find the source for that. But assuming that it is a field in TreeViewGUI you could do
var k_Line = guiVal.GetType().BaseType.GetField ("k_LineHeight").GetValue (guiVal);
^^^
ANSWER : The "Update" on my side had a typo. The answer to this is the one is a combination of both TheHenny's and Scott's. I was attempting to access a variable only visible in the BaseType. Thank you both!
Final code:
var k_LineC = guiVal.GetType().BaseType.GetField("k_LineHeight", BindingFlags.Instance |
BindingFlags.Static |
BindingFlags.NonPublic |
BindingFlags.Public).GetValue(guiVal);
Debug.Log (k_LineC + "\n"); // <-- returns 16
I need your help in finding better way in downloading a url using HttpWebResponse
I used next code
HttpWebResponse myboot = HttpWebRequest.Create("http://www.wwenews.us/m1.php?id=441229").GetResponse() as HttpWebResponse;
StreamReader myboot_content = new StreamReader(myboot.GetResponseStream(), Encoding.GetEncoding("windows-1256"));
string temp_data = myboot_content.ReadToEnd();
but a problem says
The server committed a protocol violation. Section=ResponseHeader Detail=CR must be followed by LF
appears to me when trying parsing http://www.wwenews.us/m1.php?id=441229
please help me to download string of this site
note: test your solution code before present it as I had tested several solutions and no one solve the problem
Add a reference to System.Configuration to your project and add the following method.
public static bool SetUnsafeHeaderParsing()
{
Assembly oAssembly = Assembly.GetAssembly(typeof(System.Net.Configuration.SettingsSection));
if (oAssembly != null)
{
Type oAssemblyType = oAssembly.GetType("System.Net.Configuration.SettingsSectionInternal");
if (oAssemblyType != null)
{
object oInstance = oAssemblyType.InvokeMember("Section",
BindingFlags.Static | BindingFlags.GetProperty | BindingFlags.NonPublic, null, null, new object[] { });
if (oInstance != null)
{
FieldInfo objFeild = oAssemblyType.GetField("useUnsafeHeaderParsing", BindingFlags.NonPublic | BindingFlags.Instance);
if (objFeild != null)
{
objFeild.SetValue(oInstance, true);
return true;
}
}
}
}
return false;
}
Call the method SetUnsafeHeaderParsing() before you use the HttpWebRequest.Create method call.
Its actually a problem with the server. The server is not following the HTTP specifications. However your .NET client by default would adhere to the specs and flags it as a potential problem.
Skype installed on the same machine as the web server can cause such problems, as it's using the same port (80) by default.
To change that port look here:
http://forum.skype.com/index.php?showtopic=31024
When the .NET System.Uri class parses strings it performs some normalization on the input, such as lower-casing the scheme and hostname. It also trims trailing periods from each path segment. This latter feature is fatal to OpenID applications because some OpenIDs (like those issued from Yahoo) include base64 encoded path segments which may end with a period.
How can I disable this period-trimming behavior of the Uri class?
Registering my own scheme using UriParser.Register with a parser initialized with GenericUriParserOptions.DontCompressPath avoids the period trimming, and some other operations that are also undesirable for OpenID. But I cannot register a new parser for existing schemes like HTTP and HTTPS, which I must do for OpenIDs.
Another approach I tried was registering my own new scheme, and programming the custom parser to change the scheme back to the standard HTTP(s) schemes as part of parsing:
public class MyUriParser : GenericUriParser
{
private string actualScheme;
public MyUriParser(string actualScheme)
: base(GenericUriParserOptions.DontCompressPath)
{
this.actualScheme = actualScheme.ToLowerInvariant();
}
protected override string GetComponents(Uri uri, UriComponents components, UriFormat format)
{
string result = base.GetComponents(uri, components, format);
// Substitute our actual desired scheme in the string if it's in there.
if ((components & UriComponents.Scheme) != 0)
{
string registeredScheme = base.GetComponents(uri, UriComponents.Scheme, format);
result = this.actualScheme + result.Substring(registeredScheme.Length);
}
return result;
}
}
class Program
{
static void Main(string[] args)
{
UriParser.Register(new MyUriParser("http"), "httpx", 80);
UriParser.Register(new MyUriParser("https"), "httpsx", 443);
Uri z = new Uri("httpsx://me.yahoo.com/b./c.#adf");
var req = (HttpWebRequest)WebRequest.Create(z);
req.GetResponse();
}
}
This actually almost works. The Uri instance reports https instead of httpsx everywhere -- except the Uri.Scheme property itself. That's a problem when you pass this Uri instance to the HttpWebRequest to send a request to this address. Apparently it checks the Scheme property and doesn't recognize it as 'https' because it just sends plaintext to the 443 port instead of SSL.
I'm happy for any solution that:
Preserves trailing periods in path segments in Uri.Path
Includes these periods in outgoing HTTP requests.
Ideally works with under ASP.NET medium trust (but not absolutely necessary).
Microsoft says it will be fixed in .NET 4.0 (though it appears from the comments that it has not been fixed yet)
https://connect.microsoft.com/VisualStudio/feedback/details/386695/system-uri-incorrectly-strips-trailing-dots?wa=wsignin1.0#tabs
There is a workaround on that page, however. It involves using reflection to change the options though, so it may not meet the medium trust requirement. Just scroll to the bottom and click on the "Workarounds" tab.
Thanks to jxdavis and Google for this answer:
http://social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/5206beca-071f-485d-a2bd-657d635239c9
I'm curious if part of the problem is that you are only accounting for "don't compress path", instead of all the defaults of the base HTTP parser: (including UnEscapeDotsAndSlashes)
private const UriSyntaxFlags HttpSyntaxFlags = (UriSyntaxFlags.AllowIriParsing | UriSyntaxFlags.AllowIdn | UriSyntaxFlags.UnEscapeDotsAndSlashes | UriSyntaxFlags.CanonicalizeAsFilePath | UriSyntaxFlags.CompressPath | UriSyntaxFlags.ConvertPathSlashes | UriSyntaxFlags.PathIsRooted | UriSyntaxFlags.AllowAnInternetHost | UriSyntaxFlags.AllowUncHost | UriSyntaxFlags.MayHaveFragment | UriSyntaxFlags.MayHaveQuery | UriSyntaxFlags.MayHavePath | UriSyntaxFlags.MayHavePort | UriSyntaxFlags.MayHaveUserInfo | UriSyntaxFlags.MustHaveAuthority);
That's as opposed to the news that has flags (for instance):
private const UriSyntaxFlags NewsSyntaxFlags = (UriSyntaxFlags.AllowIriParsing | UriSyntaxFlags.MayHaveFragment | UriSyntaxFlags.MayHavePath);
Dang, Brandon Black beat me to it while I was working on typing things up...
This may help with code readability:
namespace System
{
[Flags]
internal enum UriSyntaxFlags
{
AllowAnInternetHost = 0xe00,
AllowAnyOtherHost = 0x1000,
AllowDnsHost = 0x200,
AllowDOSPath = 0x100000,
AllowEmptyHost = 0x80,
AllowIdn = 0x4000000,
AllowIPv4Host = 0x400,
AllowIPv6Host = 0x800,
AllowIriParsing = 0x10000000,
AllowUncHost = 0x100,
BuiltInSyntax = 0x40000,
CanonicalizeAsFilePath = 0x1000000,
CompressPath = 0x800000,
ConvertPathSlashes = 0x400000,
FileLikeUri = 0x2000,
MailToLikeUri = 0x4000,
MayHaveFragment = 0x40,
MayHavePath = 0x10,
MayHavePort = 8,
MayHaveQuery = 0x20,
MayHaveUserInfo = 4,
MustHaveAuthority = 1,
OptionalAuthority = 2,
ParserSchemeOnly = 0x80000,
PathIsRooted = 0x200000,
SimpleUserSyntax = 0x20000,
UnEscapeDotsAndSlashes = 0x2000000,
V1_UnknownUri = 0x10000
}
}
You should be able to precent escape the '.' using '%2E', but that's the cheap and dirty way out.
You might try playing around with the dontEscape option a bit and it may change how Uri is treating those characters.
More info here:
http://msdn.microsoft.com/en-us/library/system.uri.aspx
Also check out the following (see DontUnescapePathDotsAndSlashes):
http:// msdn.microsoft.com/en-us/library/system.genericuriparseroptions.aspx
Does this work?
public class MyUriParser : UriParser
{
private string actualScheme;
public MyUriParser(string actualScheme)
{
Type type = this.GetType();
FieldInfo fInfo = type.BaseType.GetField("m_Flags", BindingFlags.Instance | BindingFlags.NonPublic);
fInfo.SetValue(this, GenericUriParserOptions.DontCompressPath);
this.actualScheme = actualScheme.ToLowerInvariant();
}
protected override string GetComponents(Uri uri, UriComponents components, UriFormat format)
{
string result = base.GetComponents(uri, components, format);
// Substitute our actual desired scheme in the string if it's in there.
if ((components & UriComponents.Scheme) != 0)
{
string registeredScheme = base.GetComponents(uri, UriComponents.Scheme, format);
result = this.actualScheme + result.Substring(registeredScheme.Length);
}
return result;
}}
I need to request the following URL inside my application:
http://feedbooks.com/type/Crime%2FMystery/books/top
When I run the following code:
Uri myUri = new Uri("http://feedbooks.com/type/Crime%2FMystery/books/top");
The Uri constructor decodes the %2F into a literal /, and I get a 404 error because it has changed the URL to:
http://feedbooks.com/type/Crime/Mystery/books/top
The Uri class has a constructor that takes a parameter dontEscape, but that constructor is deprecated and setting it to true has no effect.
My first thought was to do something like:
Uri myUri = new Uri("http://feedbooks.com/type/Crime%252FMystery/books/top");
With the hopes that it would convert %25 into a literal %, but that didn't work either.
Any ideas how to create a correct Uri object for this particular URL in .NET?
It's a bit easier in .NET 4.0. You can put a setting in your config file like this:
<uri>
<schemeSettings>
<add name="http" genericUriParserOptions="DontUnescapePathDotsAndSlashes" />
</schemeSettings>
</uri>
It only works for the 'http' and 'https' schemes.
Or here's a new version of the LeaveDotsAndSlashesEscaped method. It doesn't need a particular Uri instance, just call it when your application starts up:
private void LeaveDotsAndSlashesEscaped()
{
var getSyntaxMethod =
typeof (UriParser).GetMethod("GetSyntax", BindingFlags.Static | BindingFlags.NonPublic);
if (getSyntaxMethod == null)
{
throw new MissingMethodException("UriParser", "GetSyntax");
}
var uriParser = getSyntaxMethod.Invoke(null, new object[] { "http" });
var setUpdatableFlagsMethod =
uriParser.GetType().GetMethod("SetUpdatableFlags", BindingFlags.Instance | BindingFlags.NonPublic);
if (setUpdatableFlagsMethod == null)
{
throw new MissingMethodException("UriParser", "SetUpdatableFlags");
}
setUpdatableFlagsMethod.Invoke(uriParser, new object[] {0});
}
I ran into the same problem using 2.0...
I discovered a workaround posted at this blog:
// System.UriSyntaxFlags is internal, so let's duplicate the flag privately
private const int UnEscapeDotsAndSlashes = 0x2000000;
public static void LeaveDotsAndSlashesEscaped(Uri uri)
{
if (uri == null)
{
throw new ArgumentNullException("uri");
}
FieldInfo fieldInfo = uri.GetType().GetField("m_Syntax", BindingFlags.Instance | BindingFlags.NonPublic);
if (fieldInfo == null)
{
throw new MissingFieldException("'m_Syntax' field not found");
}
object uriParser = fieldInfo.GetValue(uri);
fieldInfo = typeof(UriParser).GetField("m_Flags", BindingFlags.Instance | BindingFlags.NonPublic);
if (fieldInfo == null)
{
throw new MissingFieldException("'m_Flags' field not found");
}
object uriSyntaxFlags = fieldInfo.GetValue(uriParser);
// Clear the flag that we don't want
uriSyntaxFlags = (int)uriSyntaxFlags & ~UnEscapeDotsAndSlashes;
fieldInfo.SetValue(uriParser, uriSyntaxFlags);
}
It works perfectly.
Hope this helps (better late than never!)
This is a bug I filed a while back. It's supposed to be fixed in 4.0, but I'm not holding my breath. Apparently it's still a problem in the RC.
By combining the 2 previous answers you can have a method you only need to call once per process that works both on .net 4 and .net 3.5.
// System.UriSyntaxFlags is internal, so let's duplicate the flag privately
private const int UnEscapeDotsAndSlashes = 0x2000000;
private void LeaveDotsAndSlashesEscaped()
{
var getSyntaxMethod =
typeof (UriParser).GetMethod("GetSyntax", BindingFlags.Static | BindingFlags.NonPublic);
if (getSyntaxMethod == null)
{
throw new MissingMethodException("UriParser", "GetSyntax");
}
var uriParser = getSyntaxMethod.Invoke(null, new object[] { "http" });
FieldInfo flagsFieldInfo = typeof(UriParser).GetField("m_Flags", BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.Instance);
if (flagsFieldInfo == null)
{
throw new MissingFieldException("UriParser", "m_Flags");
}
int flags = (int) flagsFieldInfo.GetValue(uriParser);
// unset UnEscapeDotsAndSlashes flag and leave the others untouched
flags = flags & ~UnEscapeDotsAndSlashes;
flagsFieldInfo.SetValue(uriParser, flags);
}
Given an absolute URI/URL, I want to get a URI/URL which doesn't contain the leaf portion. For example: given http://foo.com/bar/baz.html, I should get http://foo.com/bar/.
The code which I could come up with seems a bit lengthy, so I'm wondering if there is a better way.
static string GetParentUriString(Uri uri)
{
StringBuilder parentName = new StringBuilder();
// Append the scheme: http, ftp etc.
parentName.Append(uri.Scheme);
// Appned the '://' after the http, ftp etc.
parentName.Append("://");
// Append the host name www.foo.com
parentName.Append(uri.Host);
// Append each segment except the last one. The last one is the
// leaf and we will ignore it.
for (int i = 0; i < uri.Segments.Length - 1; i++)
{
parentName.Append(uri.Segments[i]);
}
return parentName.ToString();
}
One would use the function something like this:
static void Main(string[] args)
{
Uri uri = new Uri("http://foo.com/bar/baz.html");
// Should return http://foo.com/bar/
string parentName = GetParentUriString(uri);
}
Thanks,
Rohit
Did you try this? Seems simple enough.
Uri parent = new Uri(uri, "..");
This is the shortest I can come up with:
static string GetParentUriString(Uri uri)
{
return uri.AbsoluteUri.Remove(uri.AbsoluteUri.Length - uri.Segments.Last().Length);
}
If you want to use the Last() method, you will have to include System.Linq.
There must be an easier way to do this with the built in uri methods but here is my twist on #unknown (yahoo)'s suggestion.
In this version you don't need System.Linq and it also handles URIs with query strings:
private static string GetParentUriString(Uri uri)
{
return uri.AbsoluteUri.Remove(uri.AbsoluteUri.Length - uri.Segments[uri.Segments.Length -1].Length - uri.Query.Length);
}
Quick and dirty
int pos = uriString.LastIndexOf('/');
if (pos > 0) { uriString = uriString.Substring(0, pos); }
Shortest way I found:
static Uri GetParent(Uri uri) {
return new Uri(uri, Path.GetDirectoryName(uri.LocalPath) + "/");
}
PapyRef's answer is incorrect, UriPartial.Path includes the filename.
new Uri(uri, ".").ToString()
seems to be cleanest/simplest implementation of the function requested.
I read many answers here but didn't find one that I liked because they break in some cases.
So, I am using this:
public Uri GetParentUri(Uri uri) {
var withoutQuery = new Uri(uri.GetComponents(UriComponents.Scheme |
UriComponents.UserInfo |
UriComponents.Host |
UriComponents.Port |
UriComponents.Path, UriFormat.UriEscaped));
var trimmed = new Uri(withoutQuery.AbsoluteUri.TrimEnd('/'));
var result = new Uri(trimmed, ".");
return result;
}
Note: It removes the Query and the Fragment intentionally.
new Uri(uri.AbsoluteUri + "/../")
Get segmenation of url
url="http://localhost:9572/School/Common/Admin/Default.aspx"
Dim name() As String = HttpContext.Current.Request.Url.Segments
now simply using for loop or by index, get parent directory name
code = name(2).Remove(name(2).IndexOf("/"))
This returns me, "Common"
Thought I'd chime in; despite it being almost 10 years, with the advent of the cloud, getting the parent Uri is a fairly common (and IMO more valuable) scenario, so combining some of the answers here you would simply use (extended) Uri semantics:
public static Uri Parent(this Uri uri)
{
return new Uri(uri.AbsoluteUri.Remove(uri.AbsoluteUri.Length - uri.Segments.Last().Length - uri.Query.Length).TrimEnd('/'));
}
var source = new Uri("https://foo.azure.com/bar/source/baz.html?q=1");
var parent = source.Parent(); // https://foo.azure.com/bar/source
var folder = parent.Segments.Last(); // source
I can't say I've tested every scenario, so caution advised.