Uri.PathAndQuery doesnt include hash Query - c#

Is this expected? For example:
https://google.com/hello?w=orld#hi
Uri.PathAndQuery would result:
/hello?w=orld
Fully excluding the # bit even though I require it.
What should I do here?
Should I manually do a PathAndQuery like operation perhaps:
string fullUri = Uri.ToString();
Uri.Host + "/" + fullUri .Substring(fullUri.indexOf(Uri.Host)+Uri.Host.Length)
Essentially it compiles google.com, /, hello?w=orld#hi which would be an expected result
Im retrieving this specifically for a stream write request related operation:
{0} {1} HTTP/1.1\r\n {0} = Method {1} = pathandquery

The #hi part is called "fragment", you can access it through .Fragment. Since the property is called PathAndQuery, not PathAndQueryAndFragment, I assume this works as intended. As far as I know there is no method or property available which includes the fragment, but you can easily attach it:
var uri = new Uri("https://google.com/hello?w=orld#hi");
var pathAndQueryAndFragment = $"{uri.PathAndQuery}{uri.Fragment}";
But be aware that the fragment part is usually not submitted to the server.

Related

HttpWebRequest sometimes incorrectly decoding parts of a query parameter

I have spotted something which seems off in the HttpWebRequest object.
If I run the following:
var q = "кот (";
(Note here 'кот' is written in Russian, apparently it means cat.)
var encoded = Uri.EscapeDataString(q);
var url = $"https://api.twitter.com/1.1/search/tweets.json?count=100&include_entities=true&q={encoded}";
I get the following value in url:
https://api.twitter.com/1.1/search/tweets.json?count=100&include_entities=true&q=%D0%BA%D0%BE%D1%82%20%28
If I then run this:
var r = (HttpWebRequest)WebRequest.Create(url);
r.GetResponse();
In Fiddler, the above is observed to actually make a request:
https://api.twitter.com/1.1/search/tweets.json?count=100&include_entities=true&q=%D0%BA%D0%BE%D1%82%20(
Note that the ( is not encoded as %28 as it was when I constructed the HttpWebRequest.
If instead I use:
q = "CAT ("
i.e. no Russian characters, only latin(?), I get this as the URL:
https://api.twitter.com/1.1/search/tweets.json?count=100&include_entities=true&q=CAT%20%28
And this is also the request observed in Fiddler.
To summarise, it seems when mixing latin and non latin characters, the ( is not being sent encoded.
Does anybody have any suggestions how to solve this?
UPDATE:
This is important because as far as I can tell it is the reason I can't successfully make these API queries to Twitter as it appears to be breaking our OAuth1 signing, we are getting:
HTTP/1.1 401 Authorization Required
{"errors":[{"code":32,"message":"Could not authenticate you."}]}
I can even edit the failing request in Fiddler and replace the ( with a %28 in the GET request, and it then succeeds on replaying it with this single change.
This may help... it appears that the behaviour of the Uri class is as follows:
var q = "кот (";
var encoded = Uri.EscapeDataString(q);
// encoded = %D0%BA%D0%BE%D1%82%20%28
var uri = new Uri("https://api.twitter.com/1.1/search/tweets.json?count=100&include_entities=true&q=" + encoded);
// uri.AbsoluteUri = https://api.twitter.com/1.1/search/tweets.json?count=100&include_entities=true&q=%D0%BA%D0%BE%D1%82%20(
var uri2 = new Uri("https://api.twitter.com/1.1/search/tweets.json?count=100&include_entities=true&q=CAT (");
// uri2.AbsoluteUri = https://api.twitter.com/1.1/search/tweets.json?count=100&include_entities=true&q=CAT%20(
var uri3 = new Uri("https://api.twitter.com/1.1/search/tweets.json?count=100&include_entities=true&q=кот (");
// uri3.AbsoluteUri = https://api.twitter.com/1.1/search/tweets.json?count=100&include_entities=true&q=%D0%BA%D0%BE%D1%82%20(
I cannot debug into the .NET Framework code at the moment, but I suspect use of Uri.EscapeDataString might be incorrect WRT non-Latin chars and brackets?
Does the request with the unencoded bracket actually work? If so I would suggest the bracket does not need encoding...
UPDATE: I actually think this might be a bug in Uri?

How can I get a part/subdomain of my URL in C#?

I have a URL like the following
http://yellowcpd.testpace.net
How can I get yellowcpd from this? I know I can do that with string parsing, but is there a builtin way in C#?
Assuming your URLs will always be testpace.net, try this:
var subdomain = Request.Url.Host.Replace("testpace.net", "").TrimEnd('.');
It'll just give you the non-testpace.net part of the Host. If you don't have Request.Url.Host, you can do new Uri(myString).Host instead.
try this
string url = Request.Url.AbsolutePath;
var myvalues= url.Split('.');
How can I get yellowcpd from this? I know I can do that with string
parsing, but is there a builtin way in C#?
.Net doesn't provide a built-in feature to extract specific parts from Uri.Host. You will have to use string manipulation or a regular expression yourself.
The only constant part of the domain string is the TLD. The TLD is the very last bit of the domain string, eg .com, .net, .uk etc. Everything else under that depends on the particular TLD for its position (so you can't assume the next to last part is the "domain name" as, for .co.uk it would be .co
This fits the bill.
Split over two lines:
string rawURL = Request.Url.Host;
string domainName = rawURL .Split(new char[] { '.', '.' })[1];
Or over one:
string rawURL = Request.Url.Host.Split(new char[] { '.', '.' })[1];
The simple answer to your question is no there isn't a built in method to extract JUST the sub-domain. With that said this is the solution that I use...
public enum GetSubDomainOption
{
ExcludeWWW,
IncludeWWW
};
public static class Extentions
{
public static string GetSubDomain(this Uri uri,
GetSubDomainOption getSubDomainOption = GetSubDomainOption.IncludeWWW)
{
var subdomain = new StringBuilder();
for (var i = 0; i < uri.Host.Split(new char[]{'.'}).Length - 2; i++)
{
//Ignore any www values of ExcludeWWW option is set
if(getSubDomainOption == GetSubDomainOption.ExcludeWWW && uri.Host.Split(new char[]{'.'})[i].ToLowerInvariant() == "www") continue;
//I use a ternary operator here...this could easily be converted to an if/else if you are of the ternary operators are evil crowd
subdomain.Append((i < uri.Host.Split(new char[]{'.'}).Length - 3 &&
uri.Host.Split(new char[]{'.'})[i+1].ToLowerInvariant() != "www") ?
uri.Host.Split(new char[]{'.'})[i] + "." :
uri.Host.Split(new char[]{'.'})[i]);
}
return subdomain.ToString();
}
}
USAGE:
var subDomain = Request.Url.GetSubDomain(GetSubDomainOption.ExcludeWWW);
or
var subDomain = Request.Url.GetSubDomain();
I currently have the default set to include the WWW. You could easilly reverse this by switching the optional parameter value in the GetSubDomain() method.
In my opinion this allows for an option that looks nice in code and without digging in appears to be 'built-in' to c#. Just to confirm your expectations...I tested three values and this method will always return just the "yellowcpd" if the exclude flag is used.
www.yellowcpd.testpace.net
yellowcpd.testpace.net
www.yellowcpd.www.testpace.net
One assumption that I use is that...splitting the hostname on a . will always result in the last two values being the domain (i.e. something.com)
As others have pointed out, you can do something like this:
var req = new HttpRequest(filename: "search", url: "http://www.yellowcpd.testpace.net", queryString: "q=alaska");
var host = req.Url.Host;
var yellow = host.Split('.')[1];
The portion of the URL you want is part of the hostname. You may hope to find some method that directly addresses that portion of the name, e.g. "the subdomain (yellowcpd) within TestSpace", but this is probably not possible, because the rules for valid host names allow for any number of labels (see Valid Host Names). The host name can have any number of labels, separated by periods. You will have to add additional restrictions to get what you want, e.g. "Separate the host name into labels, discard www if present and take the next label".

C# - customizing image name converted to string

I have a method that copies selected image from an OpenFileDialog to a defined location, and I want to check if an image with the same name exists, and if so to change the name on the fly.
Here is my method:
public void SaveImage(IList<AppConfig> AppConfigs, string ImageNameFilter)
{
string imgPath = AppConfigs[0].ConfigValue.ToString();
Int32 i = 0;
StringBuilder sb = new StringBuilder(selectedFileName);
while (File.Exists(imgPath + "\\" + ImageNameFilter + selectedFileName))
{
sb.Insert(i, 0);
i++;
//ImageNameFilter += (i++).ToString();
}
File.Copy(selectedFile, imgPath + "\\" + ImageNameFilter + selectedFileName);
}
ImageNameFilter is a custom filter that is added at the beginning of each image and the users need this prefix to be able to recognize what the image is used for, only by seeing the prefix. selectedFileName is the name of the image taken with SafeFileName, which means it looks like this - imageName.jpeg.
There are several problems that I have with this code. Firstly, I wanted to change the name like this - imageName1.jpeg, imageName2.jpeg, imageName3.jpeg...imageName14.jpeg.., but if I'm using selectedFileName with the += everything is added, even after the .jpeg, which is not what I want. The only solution that I can think of is to use regex, but I really want to find another way.
Also, incrementing i++ and adding it with += leads to unwanted result which is :
imageName1.jpeg, imageName12.jpeg, imageName123.jpeg...imageName1234567.jpeg.
So, how can I get the result I want and the compromise I see here is to add underscore _ right after the ImageNameFilter and then add i at the beginning of selectedFileName rather in the end as it is by default. But adding something to the beginning of the string is also something I don't know how to do. As you may see I tried StringBuiledr + Insert, but I don't get the expected result.
Basically you need to separate the base file name from the extension (use the helpful methods on Path to do this) before starting the loop, and then keep producing filenames. Each candidate will not be produced based on the last one (it's just based on fixed information and the current iteration count), so you don't need to involve a StringBuilder at all.
Here's one neat way to do it in two steps. First, set up the bookkeeping:
var canonicalFileName = ImageNameFilter + selectedFileName;
var baseFileName = Path.GetFileNameWithoutExtension(canonicalFileName);
var extension = Path.GetExtension(canonicalFileName);
Then do the loop -- here I 'm using LINQ instead of a loop statement because I can, but there's no essential difference from a stock while loop:
var targetFileName = Enumerable.Range(1, int.MaxValue - 1)
.Select(i => Path.Combine(imgPath, baseFileName + i + extension))
.First(file => !File.Exists(file));
File.Copy(selectedFile, targetFileName);
Use Path.GetFileNameWithoutExtension or String.TrimEnd('.') to get the FileName without extension. You can use FileInfo to get the extension as well.

find string using c#?

I am trying find a string in below string.
http://example.com/TIGS/SIM/Lists/Team Discussion/DispForm.aspx?ID=1779
by using http://example.com/TIGS/SIM/Lists string. How can I get Team Discussion word from it?
Some times strings will be
http://example.com/TIGS/SIM/Lists/Team Discussion/DispForm.aspx?ID=1779
I need `Team Discussion`
http://example.com/TIGS/ALIF/Lists/Artifical Lift Discussion Forum 2/DispForm.aspx?ID=8
I need `Artifical Lift Discussion Forum 2`
If you're always following that pattern, I recommend #Justin's answer. However, if you want a more robust method, you can always couple the System.Uri and Path.GetDirectoryName methods, then perform a String.Split. Like this example:
String url = #"http://example.com/TIGS/SIM/Lists/Team Discussion/DispForm.aspx?ID=1779";
System.Uri uri = new System.Uri(url);
String dir = Path.GetDirectoryName(uri.AbsolutePath);
String[] parts = dir.Split(new[]{ Path.DirectorySeparatorChar });
Console.WriteLine(parts[parts.Length - 1]);
The only major problem, however, is you're going to wind up with a path that's been "encoded" (i.e. your space is now going to be represented by a %20)
This solution will get you the last directory of your URL regardless of how many directories are in your URL.
string[] arr = s.Split('/');
string lastPart = arr[arr.Length - 2];
You could combine this solution into one line, however it would require splitting the string twice, once for the values, the second for the length.
If you wanted to see a regular expression example:
string input = "http://example.com/TIGS/SIM/Lists/Team Discussion/DispForm.aspx?ID=1779";
string given = "http://example.com/TIGS/SIM/Lists";
System.Text.RegularExpressions.Regex regex = new System.Text.RegularExpressions.Regex(given + #"\/(.+)\/");
System.Text.RegularExpressions.Match match = regex.Match(input);
Console.WriteLine(match.Groups[1]); // Team Discussion
Here's a simple approach, assuming that your URL always has the same number of slashes before the are you want:
var value = url.Split(new[]{'/'}, StringSplitOptions.RemoveEmptyEntries)[5];
Here is another solution that provides the following advantages:
Does not require the use of regular expressions.
Does not require a certain 'count' of slashes be present (indexing based of a specific number). I consider this a key benefit because it makes the code less likely to fail if some part of the URL changes. Ultimately it is best to base your parsing logic off which part of the text's structure you consider least likely to change.
This method, however, DOES rely on the following assumptions, which I consider to be the least likely to change:
URL must have "/Lists/" right before target text.
URL must have "/" right after target text.
Basically, I just split the string twice, using text that I expect to be surrounding the area I am interested in.
String urlToSearch = "http://example.com/TIGS/SIM/Lists/Team Discussion/DispForm.aspx";
String result = "";
// First, get everthing after "/Lists/"
string[] temp1 = urlToSearch.Split(new String[] { "/Lists/" }, StringSplitOptions.RemoveEmptyEntries);
if (temp1.Length > 1)
{
// Next, get everything before the first "/"
string[] temp2 = temp1[1].Split(new String[] { "/" }, StringSplitOptions.RemoveEmptyEntries);
result = temp2[0];
}
Your answer will then be stored in the 'result' variable.

extract query string from a URL string

I am reading from history, and I want that when i come across a google query, I can extract the query string. I am not using request or httputility since i am simply parsing a string. however, when i come across URLs like this, my program fails to parse it properly:
http://www.google.com.mt/search?client=firefox-a&rls=org.mozilla%3Aen-US%3Aofficial&channel=s&hl=mt&source=hp&biw=986&bih=663&q=hotmail&meta=&btnG=Fittex+bil-Google
what i was trying to do is get the index of q= and the index of & and take the words in between but in this case the index of & will be smaller than q= and it will give me errors.
any suggestions?
thanks for your answers, all seem good :) p.s. i couldn't use httputility, not I don't want to. when i add a reference to system.web, httputility isn't included! it's only included in an asp.net application. Thanks again
It's not clear why you don't want to use HttpUtility. You could always add a reference to System.Web and use it:
var parsedQuery = HttpUtility.ParseQueryString(input);
Console.WriteLine(parsedQuery["q"]);
If that's not an option then perhaps this approach will help:
var query = input.Split('&')
.Single(s => s.StartsWith("q="))
.Substring(2);
Console.WriteLine(query);
It splits on & and looks for the single split result that begins with "q=" and takes the substring at position 2 to return everything after the = sign. The assumption is that there will be a single match, which seems reasonable for this case, otherwise an exception will be thrown. If that's not the case then replace Single with Where, loop over the results and perform the same substring operation in the loop.
EDIT: to cover the scenario mentioned in the comments this updated version can be used:
int index = input.IndexOf('?');
var query = input.Substring(index + 1)
.Split('&')
.SingleOrDefault(s => s.StartsWith("q="));
if (query != null)
Console.WriteLine(query.Substring(2));
If you don't want to use System.Web.HttpUtility (thus be able to use the client profile), you can still use Mono HttpUtility.cs which is only an independent .cs file that you can embed in your application. Then you can simply use the ParseQueryString method inside the class to parse the query string properly.
here is the solution -
string GetQueryString(string url, string key)
{
string query_string = string.Empty;
var uri = new Uri(url);
var newQueryString = HttpUtility.ParseQueryString(uri.Query);
query_string = newQueryString[key].ToString();
return query_string;
}
Why don't you create a code which returns the string from the q= onwards till the next &?
For example:
string s = historyString.Substring(url.IndexOf("q="));
int newIndex = s.IndexOf("&");
string newString = s.Substring(0, newIndex);
Cheers
Use the tools available:
String UrlStr = "http://www.google.com.mt/search?client=firefox-a&rls=org.mozilla%3Aen-US%3Aofficial&channel=s&hl=mt&source=hp&biw=986&bih=663&q=hotmail&meta=&btnG=Fittex+bil-Google";
NameValueCollection Items = HttpUtility.ParseQueryString(UrlStr);
String QValue = Items["q"];
If you really need to do the parsing yourself, and are only interested in the value for 'q' then the following would work:
string url = #"http://www.google.com.mt/search?" +
"client=firefoxa&rls=org.mozilla%3Aen-" +
"US%3Aofficial&channel=s&hl=mt&source=hp&" +
"biw=986&bih=663&q=hotmail&meta=&btnG=Fittex+bil-Google";
int question = url.IndexOf("?");
if(question>-1)
{
int qindex = url.IndexOf("q=", question);
if (qindex > -1)
{
int ampersand = url.IndexOf('&', qindex);
string token = null;
if (ampersand > -1)
token = url.Substring(qindex+2, ampersand - qindex - 2);
else
token = url.Substring(qindex+2);
Console.WriteLine(token);
}
}
But do try to look at using a proper URL parser, it will save you a lot of hassle in the future.
(amended this question to include a check for the '?' token, and support 'q' values at the end of the query string (without the '&' at the end) )
And that's why you should use Uri and HttpUtility.ParseQueryString.
HttpUtility is fine for the .Net Framework. However that class is not available for WinRT apps. If you want to get the parameters from a url in a Windows Store App you need to use WwwFromUrlDecoder. You create an object from this class with the query string you want to get the parameters from, the object has an enumerator and supports also lambda expressions.
Here's an example
var stringUrl = "http://localhost/?name=Jonathan&lastName=Morales";
var decoder = new WwwFormUrlDecoder(stringUrl);
//Using GetFirstByName method
string nameValue = decoder.GetFirstByName("name");
//nameValue has "Jonathan"
//Using Lambda Expressions
var parameter = decoder.FirstOrDefault(p => p.Name.Contains("last")); //IWwwFormUrlDecoderEntry variable type
string parameterName = parameter.Name; //lastName
string parameterValue = parameter.Value; //Morales
You can also see http://www.dzhang.com/blog/2012/08/21/parsing-uri-query-strings-in-windows-8-metro-style-apps

Categories