After reviewing the code below, I noticed that the call to Context.RewritePath is somehow not losing the query string, even though it is being called without a query string. Is there any documentation explaining why the query string is being maintained?
//URL relative path to ashx files is wrong to to path rewriting.
if (Request.Url.LocalPath.EndsWith(".ashx")) {
Context.RewritePath(Request.Url.LocalPath
.Substring(Request.Url.LocalPath.LastIndexOf("/") + 1));
}
Edit: I am not asking how to fix this; the code behaves correctly. I am just asking for documentation of this behavior.
You're essentially doing a Rewrite of the path, and in most cases, the query needs to be maintained to pass to the new Path.
Take for example a new document retrieval page named "getDocumentWithEnhancements.aspx" as opposed to the old "getDocument.aspx". Both need a parameter to be useful, but you want the new one to be used. A RewritePath would do the job, as it takes the query passed to the old, and passes to the new. If you want to show some sort of error page or something, then instead you'd either use a redirect, or whatever page you're rewriting to will just ignore the querystring.
Why would you not want the query to be passed through? What exactly are you using this for? Maybe it's not the right function for what you need.
edit: There's an overloaded function taking 3 parameters, one of which is a querystring, which you could pass in as null to not use the querystring.
Related
Our webform (ProcessStudent.aspx) is designed to receive three parameters in the QueryString: Name, Grade, Class. Page_Load retrieves these three parameters and sends it to a method SaveStudent (ie. SaveStudent(name, grade, class);).
I need to process several three-parameter combinations for one page. I basically copied/pasted ProcessStudent.aspx, but I need to modify the way I read the parameters. I can change the URL structure, but everything else needs to stay the same.
So my initial thought was to include these combinations in the URL; for example, each value would be separated by a char and each combination by another char. Something like this, which I would then parse :
ProcessStudent.aspx?Students=Joe|5|Science,Bob|6|Math,Mary|5|English
Would something like this work? Is there a better way?
Yes it would work. As far as better... You could post a json string, which would be much cleaner. I personally would use a rest service with just JSON(or XML if you like).
Hope this helps.
The thing you'll need to watch out for is that the query string has a length limit in some browsers (https://stackoverflow.com/a/812962/97382) so depending how many you mean by "several" and which browser(s) you're using you could run into those limitations.
You would be better off to POST the data as you do not run into the size limitations.
What I'm trying to do is use an UriBuilder and HttpUtility.ParseQueryString to get the last page the user visited and then parse the URL to get just the productID. (The product ID is different on each page if that matters)
example URL: website.com/stuff/?referrerPage=1&productID=1234567&tab=Tile
and what I want is just the 1234567
Page_Load is where I parse the URL:
protected void Page_Load(object sender, EventArgs e)
{
NameValueCollection query = HttpUtility.ParseQueryString(uriBuilder.Query);
//I want to take the parse string and get productID here, how?
}
grabURL is where I get the last URL visited:
public grabUrl(string Uri)
{
UriBuilder uriBuilder = new UriBuilder(Request.UrlReferrer);
return uriBuilder.Uri;
}
Am I on the right track with my code? How do I put the productID number in something so I can work with it? I'm very new to c# and this type of coding in general... when I say new I mean I've been doing it for about a week. So any detailed explanations or examples will be very much appriciated. Thanks everyone for being so helpful, I'm learning a lot from this site to get me on the right track.
From a NameValueCollection you can then do:
var id = query["ProductID"];
You can use int.TryParse to turn it into an integer proper.
int id = 0;
if (!string.IsNullOrEmpty(query["ProductID"]) &&
int.TryParse(query["ProductID"], out id)) {
// use id here..
}
Or you could just request the querystring value from your URL using Request.QueryString()
protected void Page_Load()
{
//save yourself the conversion to int and just save it as Int if you know for sure
// it will always be int
int _prodID= Request.Querystring["productID"];
//validate _prodID
if (!string.IsNullOrEmpty(_prodID.toString())) {//do something }
}
Could you use a regex to parse it instead?
string uri = "website.com/stuff/?referrerPage=1&productID=1234567&tab=Tile";
var rgx = new Regex("productID=(?<pid>[0-9]+)", RegexOptions.IgnoreCase);
string pid = rgx.Match(uri).Groups[1].Value;
Edit: Providing context as it has been suggested I should do:
The reason for mentioning this option is that while it doesn't use HttpUtility.ParseQueryString, your original question was very specific:
get just the productID
from
the last page the user visited
(which I understand to not be the uri of the current request). Additionally you provided the Uri was provided in a string format.
The approach in your question does this:
Takes Uri (a string variable)
Passes it to UriBuilder; UriBuilder in its constructor initialises a Uri, which itself does a ton of work to validate the uri, populate properties etc. by creating more strings, among other things
Then, from the Uri object generated, you now work with the Query property - this is one of the new strings that Uri has allocated
Passes that to HttpUtility.ParseQueryString. This creates a HttpValueCollection, which itself iterates character-by-character over the string you pass in to parse out the key-value pairs in the query string, and sticks them into a NameValueCollection, which ultimately stores your values in an ArrayList - one of the least efficient collections in .NET (see various references including this one - What's Wrong with an ArrayList?) as it stores everything in an object array, requiring casting every time you get things back out.
finally you then go and search that collection by a key to get your product id back out.
That's a whole lot of string and character allocations, casting to and from objects, putting things into indexed arrays which you then scan, etc. just to get:
a string which is identifiable by a pattern from another string.
While I admit that memory is cheap, it seems that there might be an equally good, or better, alternative. This is what regex was made for - find a pattern in a string, and allow you to get parts of that pattern back out.
So, your options:
If you just want to get productID out of a uri in an exact form, and the uri is originally in a string, then I maintain that a regex is a very good, efficient choice. This will also work if you want to extract other patterns from your uri.
If you want to know all the keys in your query string as well as values for specific keys, then use your HttpUtility.ParseQueryString approach; NameValueCollection allows you to get access to the keys through the AllKeys property.
If you want to get the value of a query string parameter for the uri of your current request then Marcianin's answer is the simplest choice, and you can forget the first 2 options.
In all cases, once you have the string you can parse it using the parse methods on int, but if you use 2. or 3. your extracted id may not be a number (in the case of a malicious request) so make sure you use int.TryParse not int.Parse to convert from a string, and be careful to catch exceptions. You should always take care when taking input from query strings so as not to fall foul of malicious data in the query string (which will hit your website frequently once it is online).
The choice is personal preference.
The actual code you write is about the same - each approach takes up very few lines.
Code should never prematurely optimise, but it should also not be deliberately wasteful if it can help it. You could performance test one against the other, but that would be a waste of your time at this stage.
However, code should also convey intent. The Regex approach, even I would argue, doesn't convey your intent as well as the ParseQueryString approach.
Footnote: I would change the regex slightly to "[?&]productID=(?<pid>[0-9]+)" to ensure you pick up only "productID" and not "fooProductID"
Most importantly, you asked
Am I on the right track with my code?
I would say you are. Always weigh up different options as you proceed. Don't be afraid to try different things out. You say you are new to C#. The one thing you may have missed, in this case, is writing a test to help you on your way before you wrote your code: if the test passes, the code is correct, and the approach you chose is secondary to that. Visual Studio makes testing easy for you if you are using the latest version. If you get into good habits early on, it will pay dividends later on in your C# career.
How do I put the productID number in something so I can work with it?
Grant Thomas answered this perfectly - int.TryParse turns the string into a number.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How to parse a query string into a NameValueCollection in .NET
I have input as
https://localhost:8181/PortalSite/View/CommissionStatement.aspx?status=commission&quarter=1;
Output needed
status=commission
How to do in C#(preferably regular expression or something else)..
My solution
var res = src.Split('?')[1].Split('=')[1].Split["&"][0];
but failing in Split["&"]
If what you're going for is guaranteed to be a URL with a query string, I would recommend the HttpUtility.ParseQueryStringMethod.
var result = HttpUtility.ParseQueryString(new Uri(src).Query);
Note that in cases like this, the common fallacy is to just put together some string handling function that cannot deal with the full possible spec of input. In your case, there are a lot of valid URLs that are actually rather hard to handle/parse correctly. So you should stick to the already implemented, proven classes.
Thus, I would use the System.Uri class to consume the URL string. The part of the URL you're actually trying to access is the so called "query", which is also a property of the Uri instance. The query itself can easily and correctly be accessed as its individual key-value parts using the System.Web.HttpUtility.ParseQueryStringMethod() (you need to add System.Web.dll to your project's references and make sure you're not using the .NET 4 client profile for your application, as that will not include this assembly).
Example:
Uri u = new Uri("https://localhost:8181/PortalSite/View/CommissionStatement.aspx?status=commission&quarter=1;");
Console.WriteLine(u.Query); // Prints "status=commission&quarter=1;"
var parameters = HttpUtility.ParseQueryString(u.Query);
Console.WriteLine(parameters["status"]); // Prints "commission"
Once you have the "parameters" you could also iterate over them, search them, etc. YMMV.
If you require the output you show in your question, thus know that you always need the first parameter of the query string (and are not able to look it up by name as I show above), then you could use the following:
string key = parameters.GetKey(0);
Console.WriteLine(key + "=" + parameters[key]); // Prints "status=commission"
You could use the following regex: status=(\w*)
But I think there are better alternatives like using HttpUtility.ParseQueryStringMethod.
I want to pass 3 parameters to ashx file to handle the image, for that i used ImageUrl=ImageHandler.ashx?uid=1&iid=1&pid=1 but the image get not bound..
Help with correct syntax..
You may forget " for the code plus the correct location:
ImageUrl="~/ProjectLocationPathToTheImage/ImageHandler.ashx?uid=1&iid=1&pid=1"
If ImageUrl=ImageHandler.ashx?uid=1&iid=1&pid=1 is a part of your URL, then it appears that ImageUrl=ImageHandler.ashx is a query string parameter. If so, you need to change ?uid= to &uid=. What is the full URL that you are having issues with?
I'm posting to a web page which I was told took XML as it's body. Turns out that what it really requires is what looks like a URL encoded CGI query string:
<FIRST>
<ELEMENT1>Value1</ELEMENT1>
<ELEMENT2>Value1</ELEMENT2>
<ELEMENT3>Value1</ELEMENT3>
</FIRST>
<SECOND>
<ELEMENT1>Value1</ELEMENT1>
<ELEMENT2>Value1</ELEMENT2>
</SECOND>
Needs to be transmitted as
FIRST_ELEMENT1=VALUE1&FIRST_ELEMENT2=VALUE2&FIRST_ELEMENT3=VALUE3&SECOND_ELEMENT1=VALUE1&SECOND_ELEMENT2=VALUE2
The third party tells me this is a common usage, although I've not seen it before (as a method of submitting XML) it's obvious that the service was designed to take an HTML POST with a form as the source of data.
While I can see how I could write a transform I'm wondering if there is a mthod in the .Net framwork which achieves this translation. Upto and including .Net 3.5 is available on this project.
Thanks in advance
Dave
I've never seen that usage, but something like:
var query = string.Join("&",(
from parent in XElement.Parse(xml).Elements()
from child in parent.Elements()
select HttpUtility.UrlEncode(parent.Name.LocalName) + "_"
+ HttpUtility.UrlEncode(child.Name.LocalName) + "="
+ HttpUtility.UrlEncode(child.Value)).ToArray());
I strongly doubt there's anything built-in to achieve this, but coding it up shouldn't be hard. I'd use a recursive method that examines the children of a node, calling itself with a string prefix that represents the position of the node in the tree. Maintain a List or a Dictionary or whatever best suits your needs outside of the method and when you encounter a node with text data, append the prefix+tag and the value to your list. Then it'll be trivial to go through that list and join them in the querystring format. Take care to escape ampersands and other reserved characters, though.
That seems pretty crazy, I hope your XML data isn't very long... you're likely to run into issues if the querystring ends up too long.
I don't understand why you can't do an HTTP-POST , set the content-type to 'text/xml', and simply post the raw XML data.