void ReadContent(string path)
{
Contract.Requires(path!=null);
string contentofileasstring = filehelperobj.GetContent(path);
if(String.IsNullOrEmpty(contentofileasstring ))
{
throw new FileContentException(path + "No content found");
}
m_xmlobj = contentofileasstring ;
}
Is my assumption of the usage of code contracts and exceptions right in this case. Do you think it is logical to replace the exception with a code contract(or vice versa)?
code not tested.Just an example scenario
I would probably go for an implementation which looks like the following:
private void ReadContent(string path)
{
Contract.Requires<FileMissingException>(File.Exists(path));
string content = filehelperobj.GetContent(path);
m_xmlobj = content;
}
Post Edit
As it's the content you want to validate, I would put a Contract.Ensures(!String.IsNullOrEmpty(Contract.Result<string>())); inside the filehelperobj.GetContent(string) method. Then if the content being read was null or empty, I would throw an exception. e.g.
public string GetContent(string path)
{
Contract.Requires<FileMissingException>(File.Exists(path));
Contract.Ensures(!String.IsNullOrEmpty(Contract.Result<string>()));
using(var reader = new StreamReader(File.OpenRead(path)))
{
var content = reader.ReadToEnd();
if(String.IsNullOrEmpty(content))
throw new FileContentException("No content found at file: " + path);
return content;
}
}
Well assuming you had the lines the wrong way round (ie, test the path for null before trying to use it) then yes, it is a valid pre-condition and therefore should be a code contract.
Related
e.g. I want to select a character and save his number
private Storage storage;
void Awake()
{
storage = new Storage();
}
public void SelectChar1()
{
numberChar = 1;//byte
storage.Save(DataPlayerSave);//save works fine
}
on awakening, the number is loaded
private DataPlayerSave dataPlayer;
private byte numberChar;
private void Awake()
{
dataPlayer = (DataPlayerSave)storage.Load(new DataPlayerSave());
numberChar = dataPlayer.numerChar;
}
I tried to divide the data into several parts and one large file, the result is almost always the same (sometimes everything works)
public class Storage()
{
public object Load(object saveDataByDefault)
{
filePath = Application.persistentDataPath + "/saves/GameSave.save";
if (!File.Exists(filePath))
{
if (saveDataByDefault != null)
{
Save(saveDataByDefault);
return saveDataByDefault;
}
}
var file = File.Open(filePath, FileMode.Open);
var saveData = formatter.Deserialize(file);
file.Close();
return saveData;
}
}
There are also similar classes that load data at the beginning of the scene. If there are 2 or more of them, then it gives an error, if 1, then everything works. I tried to set the sequence using the Coroutine did not help.
When loading data it gives an error "InvalidCastException: Specified cast is not valid."
dataPlayer = (DataPlayerSave)storage.Load(new DataPlayerSave());
if formatter is BinaryFormatter: please don't do that - it will hurt you; as for the exception: fundamentally, use a debugger and step through the code. In particular, if you say that the exception is coming from:
dataPlayer = (DataPlayerSave)storage.Load(new DataPlayerSave());
then we can assume that Load is not returning a DataPlayerSave. So: what is it? We can't tell you, but: you can find out:
var obj = storage.Load(new DataPlayerSave());
var type = obj.GetType(); // put a break-point here
Log(type.FullName); // or just log it
dataPlayer = (DataPlayerSave)obj;
and investigate what exactly obj is. Note that BinaryFormatter is very brittle as you change types (rename, move, refactor, etc) - but that isn't even the top reason not to use it.
I am trying to basically create config files. A text file will hold something like:
Name::Adam
Location::Washington
I am trying to grab the first part as the field name (i.e. Name.Text would update the TextBox) then put the second part to that Text. Just not sure where to go or what the best way to build this is. The code below is incomplete because I can't figure out how to update the textboxes.
Thanks for the help!
private void clickImportConfig_ItemClick(object sender, DevExpress.Xpf.Bars.ItemClickEventArgs e)
{
Stream myStream = null;
string fieldUpdate = string.Empty;
string fieldUpdateTo = string.Empty;
try
{
using (myStream)
{
string[] lines = File.ReadAllLines(#"c:\\config.txt");
foreach (string s in lines)
{
var splitted = Regex.Split(s, "::");
fieldUpdate = splitted[0].ToString();
fieldUpdateTo = splitted[1].ToString();
}
}
}
catch (Exception ex)
{
MessageBox.Show("Error: Could not read file from disk. Original error: " + ex.Message);
}
}
I think this is what you're looking for:
private void clickImportConfig_ItemClick(object sender, DevExpress.Xpf.Bars.ItemClickEventArgs e)
{
Stream myStream = null;
string fieldUpdate = string.Empty;
string fieldUpdateTo = string.Empty;
try
{
using (myStream)
{
string[] lines = File.ReadAllLines(#"c:\\config.txt");
foreach (string s in lines)
{
string[] splitted = s.Split(new string[] { "::" }, StringSplitOptions.RemoveEmptyEntries);
fieldUpdate = splitted[0].ToString();
fieldUpdateTo = splitted[1].ToString();
// TextBox textBox = (TextBox)this.FindName(fieldUpdate);
// Or
TextBox textBox = this.FindName(fieldUpdate) as TextBox;
// See below for an explanation
if (textBox != null) // FindName returns null if nothing is found with that name
{
textBox.Text = fieldUpdateTo;
}
}
}
}
catch (Exception ex)
{
MessageBox.Show("Error: Could not read file from disk. Original error: " + ex.Message);
}
}
As insane_developer pointed out, you will be better off using the String.Split method (s being the string in this case so written as s.Split()) instead of Regex.Split. It will give you the benefit of removing any empty results from the array. It may also have better performance as Regex is capable of a lot more complicated things, but I haven't tested that so I could be wrong.
You can use the FindName(string name) method to find an element with the specified name. This method returns null if nothing is found and an object if the element is found. This object will need to be cast to the type you are expecting (I.e. TextBox). You can do this in one of the following ways:
TextBox textBox = (TextBox)this.FindName(fieldUpdate);
or
TextBox textBox = this.FindName(fieldUpdate) as TextBox;
The first option will throw an InvalidCastException if FindName returns an object which is not a TextBox. The second option will instead just set the value of textBox to null which will be checked by the if statement and the exception will be avoided. As you are only catching all generic exceptions in this code, an InvalidCastException would show your "Could not read file from disk" message which is not true. So you may want to add an additional catch block to handle any invalid casting.
If you're wondering why you don't just stick to the second option as it solves this problem, then consider this scenario as an example. Lets say in the future you decide for some reason that you want to change all of your TextBox to TextBlock or something else, but forget to come back to change this code, or accidently end up with the name of another type of control in your text file. The second option will set the value of textBox to null and your field(s) won't be updated. But there will be absolutely no errors, leaving you scratching your head and having to debug the problem. The first option would throw an InvalidCastException showing you exactly where the problem is. You could then choose how to handle this problem by either showing another message box or silently writing the error to a log file etc.
You don't need a regular expression, just:
var splitted = s.Split("::", StringSplitOptions.RemoveEmptyEntries);
fieldUpdate = splitted[0];
fieldUpdateTo = splitted[1];
For the rest you have to be more explicit
I have an XML that's obtained from a web service, i'm using an HttpClient for it. This is what the XML looks like:
<respuesta>
<entrada>
<rut>7059099</rut>
<dv>9</dv>
</entrada>
<status>
<code>OK</code>
<descrip>Persona tiene ficha, ok</descrip>
</status>
<ficha>
<folio>3204525</folio>
<ptje>7714</ptje>
<fec_aplic>20080714</fec_aplic>
<num_integ>2</num_integ>
<comuna>08205</comuna>
<parentesco>1</parentesco>
<fec_puntaje>20070101</fec_puntaje>
<personas>
<persona>
<run>7059099</run>
<dv>9</dv>
<nombres>JOSE SANTOS</nombres>
<ape1>ONATE</ape1>
<ape2>FERNANDEZ</ape2>
<fec_nac>19521101</fec_nac>
<sexo>M</sexo>
<parentesco>1</parentesco>
</persona>
<persona>
<run>8353907</run>
<dv>0</dv>
<nombres>JUANA DEL TRANSITO</nombres>
<ape1>MEDINA</ape1>
<ape2>ROA</ape2>
<fec_nac>19560815</fec_nac>
<sexo>F</sexo>
<parentesco>2</parentesco>
</persona>
</personas>
</ficha>
I'm trying to make a function that can parse this and, right now (just for the purpose of testing my understanding of the language since i'm new to it) i just need it to find the VALUE inside an "rut" tag, the first one, or something like that. More precisely I need to find a value inside the XML and return it, so i can show it on a label that's on my .aspx page. The code of my parsing function looks like this:
public static String parseXml(String xmlStr, String tag)
{
String valor;
using (XmlReader r = XmlReader.Create(new StringReader(xmlStr)))
{
try
{
r.ReadToFollowing(tag);
r.MoveToContent();
valor = r.Value;
}
catch (Exception ex)
{
throw new Exception(ex.Message, ex.InnerException);
}
}
return valor;
}
This code is based on an example I found on youtube made by the guys from microsoft where they "explain" how to use the parser.
Also, this function is being called from inside one of the tasks of the HttpClient, this is it:
protected void rutBTN_Click(object sender, EventArgs e)
{
if (rutTB.Text != "")
{
HttpClient client = new HttpClient();
String xmlString = "";
String text = "";
var byteArray = Encoding.ASCII.GetBytes("*******:*******"); //WebService's server authentication
client.BaseAddress = new Uri("http://wschsol.mideplan.cl");
var par = "mod_perl/xml/fps-by-rut?rut=" + rutTB.Text;
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));
client.GetAsync(par).ContinueWith(
(requestTask) =>
{
HttpResponseMessage resp = requestTask.Result;
try
{
resp.EnsureSuccessStatusCode();
XmlDocument xmlResp = new XmlDocument();
requestTask.Result.Content.ReadAsStreamAsync().ContinueWith(
(streamTask) =>
{
xmlResp.Load(streamTask.Result);
text = xmlResp.InnerXml.ToString();
xmlString = parseXml(text, "rut"); //HERE I'm calling the parsing function, and i'm passing the whole innerXml to it, and the string "rut", so it searches for this tag.
Console.WriteLine("BP");
}).Wait();
}
catch (Exception ex)
{
throw new Exception(ex.Message, ex.InnerException);
}
}).Wait();
testLBL.Text = xmlString; //Finally THIS is the label i want to show the "rut" tag's value to be shown.
testLBL.Visible = true;
}
else
{
testLBL.Text = "You must enter an RUT number";
testLBL.Visible = true;
}
}
The problem is that when i put some breakpoints into the parsing function i can see that it's receiving correctly the innerxml string (as a string) but it's not finding the tag called "rut", or rather not finding anything at all, since it's returning an empty string ("").
I know that maybe this is not the correct way to parse an xmlDocument, so if someone can help me out i'd be really really thankful.
EDIT:
Ok, so i won't ask for any tutorial or such (I requested that to avoid asking noob questions). But anyway, please, instead of just answering "you better do it like this", I'd appreciate if you could explain me things like "THIS is what you're doing wrong and THAT'S why your code isn't working", and THEN tell me how you guys would do it instead.
Thanks in advance!
As you only want to retrieve a single field value I would recommend using Xpath.
Basically you create a XpathNavigator from a XpathDocument or xmlDocument and then use Select to get the content of the rut node:
XPathNavigator navigator = xmlResp.CreateNavigator();
XPathNodeIterator rutNode = navigator.SelectSingleNode("/respuesta/entrada/rut");
string rut = rutNode.Value
I have had this problem for the last day. I have created a SOAP Extension following the MSDN articles and a load of blog posts but I just can't get it to work. Ok Some code:
public class EncryptionExtension : SoapExtension
{
Stream _stream;
public override object GetInitializer(Type serviceType)
{
return typeof(EncryptionExtension);
}
public override object GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attribute)
{
return attribute;
}
public override void Initialize(object initializer)
{
}
public override void ProcessMessage(SoapMessage message)
{
switch (message.Stage)
{
case SoapMessageStage.BeforeSerialize:
break;
case SoapMessageStage.AfterSerialize:
break;
case SoapMessageStage.BeforeDeserialize:
break;
case SoapMessageStage.AfterDeserialize:
break;
default:
throw new Exception("invalid stage");
}
}
public override Stream ChainStream(Stream stream)
{
_stream = stream;
return stream;
}
}
There is also an attribute class:
[AttributeUsage(AttributeTargets.Method)]
public class EncryptionExtensionAttribute : SoapExtensionAttribute
{
public override Type ExtensionType
{
get { return typeof(EncryptionExtension); }
}
public override int Priority
{
get;
set;
}
}
So when the message comes in I can see the inbound SOAP request when I debug at the BeforeDeserialization and AfterDeserialization, which is great. My web service method is then called. Which is simply:
[WebMethod()]
[EncryptionExtension]
public string HelloWorld()
{
return "Hello world";
}
The process then hops back into my SoapExtension. Putting break points at BeforeSerialization and AfterSerialization I see that the outbound stream contains nothing. I am not surprised that it is empty on the BeforeSerialization but i am surprised that it is empty at AfterSerialization. This creates a problem because I need to get hold of the outbound stream so I can encrypt it.
Can someone tell me why the outbound stream is empty? I have followed this MSDN article which indiciates it shouldn't be http://msdn.microsoft.com/en-us/library/ms972410.aspx.
Am I missing some configuration or something else?
I found this question among the top hits for a google search on "SoapExtension MSDN" (which also finds the doc with example code as the top hit), so here are some helpful suggestions to anyone else trying to make sense of the sometimes confusing or contradictory docs on coding Soap extensions.
If you are modifying the serialized message (as a stream) you need to create and return a different stream from the ChainStream override. Otherwise, you're saying that your extension doesn't modify the stream and just lets it pass through. The example uses a MemoryStream, and that's probably what you have to use because of the weird design: When ChainStream is called you don't know if you are sending or receiving, so you have to be prepared to handle it either way. I think even if you only process it in one direction you still have to handle the other direction and copy the data from one stream to the other anyway because you are inserting yourself in the chain without knowing which way it is.
private Stream _transportStream; // The stream closer to the network transport.
private MemoryStream _accessStream; // The stream closer to the message access.
public override Stream ChainStream(Stream stream)
{
// You have to save these streams for later.
_transportStream = stream;
_accessStream = new MemoryStream();
return _accessStream;
}
Then you have to handle the AfterSerialize and BeforeDeserialize cases in ProcessMessage. I have them calling ProcessTransmitStream(message) and ProcessReceivedStream(message) respectively to help keep the process clear.
ProcessTransmitStream takes its input from _accessStream (after first resetting the Postion of this MemoryStream to 0) and writes its output to _transportStream--which may allow very limited access (no seek, etc), so I suggest processing first into a local MemoryStream buffer and then copying that (after resetting its Postion to 0) into the _transportStream. (Or if you process it into a byte array or string you can just write from that directly into the _transportStream. My use case was compression/decompression so I'm biased towards handling it all as streams.)
ProcessReceivedStream takes its input from _transportStream and writes its output to _accessStream. In this case you should probably first copy the _transportStream into a local MemoryStream buffer (and then reset the buffer's Position to 0) which you can access more conveniently. (Or you can just read the entire _transportStream directly into a byte array or other form if that's how you need it.) Make sure you reset the _accessStream.Position = 0 before returning so that it is ready for the next link in the chain to read from it.
That's for changing the serialized stream. If you aren't changing the stream then you should not override ChainStream (thus taking your extension out of the chain of stream processing). Instead you would do your processing in the BeforeSerialize and/or AfterDeserialize stages. In those stages you don't modify or access the streams but instead work on the message object itself such as adding a custom SoapHeader to the message.Headers collection in the BeforeSerialize stage.
The SoapMessage class itself is abstract, so what you really get is either a SoapClientMessage or a SoapServerMessage. The docs say you get a SoapClientMessage on the client side and a SoapServerMessage on the server side (experimenting in the debugger should be able to confirm or correct that). They seem pretty similar in terms of what you can access, but you have to cast to the right one to access it properly; using the wrong one would fail, and the base SoapMessage type declared for the parameter to ProcessMessage doesn't give you access to everything.
I haven't looked at the attribute stuff yet (it won't be a part of what I'm coding), so I can't help with how to use that part.
I ran into this post while trying to write a SoapExtension that would log my web service activity at the soap level. This script is tested and works to log activity to a text file when used on the server side. The client side is not supported.
To use just replace 'C:\Your Destination Directory' with the actual directory you want to use for log file writes.
This work cost me an entire day so I am posting it in hopes that others won't have to do the same.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.IO;
using System.Net;
using System.Reflection;
public class WebServiceActivityLogger : SoapExtension
{
string fileName = null;
public override object GetInitializer(Type serviceType)
{
return Path.Combine(#"C:\Your Destination Directory", serviceType.Name + " - " + DateTime.Now.ToString("yyyy-MM-dd HH.mm") + ".txt");
}
public override object GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attribute)
{
return Path.Combine(#"C:\Your Destination Directory", methodInfo.DeclaringType.Name + " - " + DateTime.Now.ToString("yyyy-MM-dd HH.mm") + ".txt");
}
public override void Initialize(object initializer)
{
fileName = initializer as string;
}
Dictionary<int, ActivityLogData> logDataDictionary = new Dictionary<int, ActivityLogData>();
private ActivityLogData LogData
{
get
{
ActivityLogData rtn;
if (!logDataDictionary.TryGetValue(System.Threading.Thread.CurrentThread.ManagedThreadId, out rtn))
return null;
else
return rtn;
}
set
{
int threadId = System.Threading.Thread.CurrentThread.ManagedThreadId;
if(logDataDictionary.ContainsKey(threadId))
{
if (value != null)
logDataDictionary[threadId] = value;
else
logDataDictionary.Remove(threadId);
}
else if(value != null)
logDataDictionary.Add(threadId, value);
}
}
private class ActivityLogData
{
public string methodName;
public DateTime startTime;
public DateTime endTime;
public Stream transportStream;
public Stream accessStream;
public string inputSoap;
public string outputSoap;
public bool endedInError;
}
public override Stream ChainStream(Stream stream)
{
if (LogData == null)
LogData = new ActivityLogData();
var logData = LogData;
logData.transportStream = stream;
logData.accessStream = new MemoryStream();
return logData.accessStream;
}
public override void ProcessMessage(SoapMessage message)
{
if (LogData == null)
LogData = new ActivityLogData();
var logData = LogData;
if (message is SoapServerMessage)
{
switch (message.Stage)
{
case SoapMessageStage.BeforeDeserialize:
//Take the data from the transport stream coming in from the client
//and copy it into inputSoap log. Then reset the transport to the beginning
//copy it to the access stream that the server will use to read the incoming message.
logData.startTime = DateTime.Now;
logData.inputSoap = GetSoapMessage(logData.transportStream);
Copy(logData.transportStream, logData.accessStream);
logData.accessStream.Position = 0;
break;
case SoapMessageStage.AfterDeserialize:
//Capture the method name after deserialization and it is now known. (was buried in the incoming soap)
logData.methodName = GetMethodName(message);
break;
case SoapMessageStage.BeforeSerialize:
//Do nothing here because we are not modifying the soap
break;
case SoapMessageStage.AfterSerialize:
//Take the serialized soap data captured by the access stream and
//write it into the log file. But if an error has occurred write the exception details.
logData.endTime = DateTime.Now;
logData.accessStream.Position = 0;
if (message.Exception != null)
{
logData.endedInError = true;
if (message.Exception.InnerException != null && message.Exception is System.Web.Services.Protocols.SoapException)
logData.outputSoap = GetFullExceptionMessage(message.Exception.InnerException);
else
logData.outputSoap = GetFullExceptionMessage(message.Exception);
}
else
logData.outputSoap = GetSoapMessage(logData.accessStream);
//Transfer the soap data as it was created by the service
//to the transport stream so it is received the client unmodified.
Copy(logData.accessStream, logData.transportStream);
LogRequest(logData);
break;
}
}
else if (message is SoapClientMessage)
{
throw new NotSupportedException("This extension must be ran on the server side");
}
}
private void LogRequest(ActivityLogData logData)
{
try
{
//Create the directory if it doesn't exist
var directoryName = Path.GetDirectoryName(fileName);
if (!Directory.Exists(directoryName))
Directory.CreateDirectory(directoryName);
using (var fs = new FileStream(fileName, FileMode.Append, FileAccess.Write))
{
var sw = new StreamWriter(fs);
sw.WriteLine("--------------------------------------------------------------");
sw.WriteLine("- " + logData.methodName + " executed in " + (logData.endTime - logData.startTime).TotalMilliseconds.ToString("#,###,##0") + " ms");
sw.WriteLine("--------------------------------------------------------------");
sw.WriteLine("* Input received at " + logData.startTime.ToString("HH:mm:ss.fff"));
sw.WriteLine();
sw.WriteLine("\t" + logData.inputSoap.Replace("\r\n", "\r\n\t"));
sw.WriteLine();
if (!logData.endedInError)
sw.WriteLine("* Output sent at " + logData.endTime.ToString("HH:mm:ss.fff"));
else
sw.WriteLine("* Output ended in Error at " + logData.endTime.ToString("HH:mm:ss.fff"));
sw.WriteLine();
sw.WriteLine("\t" + logData.outputSoap.Replace("\r\n", "\r\n\t"));
sw.WriteLine();
sw.Flush();
sw.Close();
}
}
finally
{
LogData = null;
}
}
private void Copy(Stream from, Stream to)
{
TextReader reader = new StreamReader(from);
TextWriter writer = new StreamWriter(to);
writer.WriteLine(reader.ReadToEnd());
writer.Flush();
}
private string GetMethodName(SoapMessage message)
{
try
{
return message.MethodInfo.Name;
}
catch
{
return "[Method Name Unavilable]";
}
}
private string GetSoapMessage(Stream message)
{
if(message == null || message.CanRead == false)
return "[Message Soap was Unreadable]";
var rtn = new StreamReader(message).ReadToEnd();
message.Position = 0;
return rtn;
}
private string GetFullExceptionMessage(System.Exception ex)
{
Assembly entryAssembly = System.Reflection.Assembly.GetEntryAssembly();
string Rtn = ex.Message.Trim() + "\r\n\r\n" +
"Exception Type: " + ex.GetType().ToString().Trim() + "\r\n\r\n" +
ex.StackTrace.TrimEnd() + "\r\n\r\n";
if (ex.InnerException != null)
Rtn += "Inner Exception\r\n\r\n" + GetFullExceptionMessage(ex.InnerException);
return Rtn.Trim();
}
}
Add this to the web.config of your server.
<system.web>
<webServices>
<soapExtensionTypes>
<add type="[Your Namespace].WebServiceActivityLogger, [Assembly Namespace], Version=1.0.0.0, Culture=neutral" priority="1" group="0" />
</soapExtensionTypes>
</webServices>
</system.web>
In order to be able to manipulate output, you'll need to do more in the ChainStream method than just just returning the same stream.
You'll also have to actually DO something in the ProcessMessage method. There is nothing happening there in your provided code.
This is a good read on SOAP Extensions: http://hyperthink.net/blog/inside-of-chainstream/. Be sure to also read the comments about better naming than oldStream and NewStream. Personally, calling them wireStream and appStream, make things much clearer to me.
The only way I've ever gotten a SOAP Extension to work is to start with the MSDN example, and get the example to work. Only once it's working, I then change it, little by little, testing each step along the way, until it does what I want.
That may even tell me what I did wrong, but it's never been enough for me to remember for next time. Usually something to do with Streams, though.
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.