Outputting a manipulated QueryString in C# - c#

Using the following code I get a nice formatted string:
Request.QueryString.ToString
Gives me something like: &hello=world&microsoft=sucks
But when I use this code to clone the collection to another object (of the same type) I get the Type() back from the ToString() method instead.
System.Collections.Specialized.NameValueCollection variables = new System.Collections.Specialized.NameValueCollection(Request.QueryString);
if (!string.IsNullOrEmpty(variables["sid"]))
variables.Remove("sid");
Response.Write(variables.ToString());
Is there a tidier way to output it rather than looking and building the string manually?

HttpValueCollection is internal, but you can use "var" to declare it without extract it with reflector.
var query = HttpUtility.ParseQueryString(Request.Url.Query);
query["Lang"] = myLanguage; // Add or replace param
string myNewUrl = Request.Url.AbsolutePath + "?" + query;

You can also use Reflector to extract the HttpValueCollection class into your own, and use it then.

Because it is actually a special NVC that is of type HTTPValueCollection.
So when you call .ToString on it, it knows how to format it correctly.

Why do you want to copy the QueryString collection into a new NameValueCollection?
if (!string.IsNullOrEmpty(Request.QueryString["sid"]))
Request.QueryString.Remove("sid");
Yes indeed, i am wrong, it is read only. So the essence is to use the Remove Method on your NameValuecollection:
System.Collections.Specialized.NameValueCollection variables = new System.Collections.Specialized.NameValueCollection(Request.QueryString);
if (!string.IsNullOrEmpty(variables["sid"]))
variables.Remove("sid");

If you don't absolutely need a NameValueCollection, A dictionary offers a lot of the same semantics:
var variables = Request.QueryString.OfType<DictionaryEntry>()
.Where(entry => entry.Key != "sid")
.ToDictionary(entry => entry.Key, entry => entry.Value);

Request.QueryString actually return a HttpValueCollection object (which unfortuately, is internal to System.Web so you can't you it).
Nevertheless, HttpValueCollection is derived from NameValueCollection, and it's Remove() method remains intact, so you should be able to call Request.QueryString.Remove("sid");

Related

Any .NET class that makes a query string given key value pairs or the like

Is there a class in the .NET framework which, if given a sequence/enumerable of key value pairs (or anything else I am not rigid on the format of this) can create a query string like this:
?foo=bar&gar=har&print=1
I could do this trivial task myself but I thought I'd ask to save myself from re-inventing the wheel. Why do all those string gymnastics when a single line of code can do it?
You can use System.Web.HttpUtility.ParseQueryString to create an empty System.Web.HttpValueCollection, and use it like a NameValueCollection.
Example:
var query = System.Web.HttpUtility.ParseQueryString(string.Empty);
query ["foo"] = "bar";
query ["gar"] = "har";
query ["print"] = "1";
var queryString = query.ToString(); // queryString is 'foo=bar&gar=har&print=1'
There's nothing built in to the .NET framework, as far as I know, though there are a lot of almosts.
System.Web.HttpRequest.QueryString is a pre-parsed NameValueCollection, not something that can output a querystring. System.NetHttpWebRequest expects you to pass a pre-formed URI, and System.UriBuilder has a Query property, but again, expects a pre-formed string for the entire query string.
However, running a quick search for "querystringbuilder" shows a couple of implementations for this out in the web that could serve. One such is this one by Brad Vincent, which gives you a simple fluent interface:
//take an existing string and replace the 'id' value if it exists (which it does)
//output : "?id=5678&user=tony"
strQuery = new QueryString("id=1234&user=tony").Add("id", "5678", true).ToString();
And, though not exactly very elegant, I found a method in RestSharp, as suggested by #sasfrog in the comment to my question. Here's the method.
From RestSharp-master\RestSharp\Http.cs
private string EncodeParameters()
{
var querystring = new StringBuilder();
foreach (var p in Parameters)
{
if (querystring.Length > 0)
querystring.Append("&");
querystring.AppendFormat("{0}={1}", p.Name.UrlEncode(), p.Value.UrlEncode());
}
return querystring.ToString();
}
And again, not very elegant and not really what I would have been expecting, but hey, it gets the job done and saves me some typing.
I was really looking for something like Xi Huan's answer (marked the correct answer) but this works as well.
There's nothing built into the .NET Framework that preserves the order of the query parameters, AFAIK. The following helper does that, skips null values, and converts values to invariant strings. When combined with a KeyValueList, it makes building URIs pretty easy.
public static string ToUrlQuery(IEnumerable<KeyValuePair<string, object>> pairs)
{
var q = new StringBuilder();
foreach (var pair in pairs)
if (pair.Value != null) {
if (q.Length > 0) q.Append('&');
q.Append(pair.Key).Append('=').Append(WebUtility.UrlEncode(Convert.ToString(pair.Value, CultureInfo.InvariantCulture)));
}
return q.ToString();
}

Convert Array to Type Array

I'm creating a generic object from DB data:
object[] data = new object[dataReader.FieldCount];
dataReader.GetValues(data);
T t = (T)Activator.CreateInstance(typeof(T), data);
But, types with no constructor error on the third line. I want to add an if:
if (typeof(T).GetConstructor(data.TypesOf()) != null)
data.TypesOf() is actually an array - Type[] - that contains all types of the objects in data.
What is the equivalent to data.TypesOf() that really works?
Or do I need to iterate data and build it myself?
I'm assuming your object[] is containing values that are, for example, an int, a string and a float, and you are trying to resolve a constructor of the form public T(int,string,float). To get the types, you could use:
var types = Array.ConvertAll(data, x => x.GetType());
But that won't actually help you much here, since that is pretty-much what Activator.CreateInstance(typeof(T), data) has already tried to do - so if Activator failed, I don't see that it is obvious that you're going to do any better - unless the key difference is that the constructor is non-public and you are going to supply some BindingFlags.
Personally, though, I would suggest that it is easier to bind by name than by position; there are tools like dapper that will do all of that for you, allowing you to use simply:
var data = conn.Query<SomeType>(sql, args).ToList();
for example:
int userId = 12345;
var users = conn.Query<User>("select * from Users where Id = #userId",
new {userId}).SingleOrDefault();
As far as I understood you are trying to get types of elememnts of an object array. So you can do something like:
var ctorArgsTypes = data.Select(d => d.GetType()).ToArray()
var ctor = typeof(T).GetConstructor(ctorArgsType);
// check if appropriate ctor exists
if (ctor == null)
throw something
T t = (T)Activator.CreateInstance(typeof(T), data);
When you look at the Activator.CreateInstance(Type, Object[]) method, for the Object[] paramter :
An array of arguments that match in number, order, and type the
parameters of the constructor to invoke. If args is an empty array or
null, the constructor that takes no parameters (the default
constructor) is invoked.
So maybe in your case, your data object is not typed for each value (if getting from a DB or a file). You need to find a way to "type" your objects in your data array.
Just use Type.GetTypeArray(object[]).
https://msdn.microsoft.com/en-us/library/system.type.gettypearray(v=vs.110).aspx

Formatting XElement values

Is there any way I can control the formatting of this statement?
var element = new XElement("Element", true);
So that I can get this output, for example:
<Element>True</Element>
I'm looking for a pluggable formatter, not something like true ? "True": "False"
I have tried to go through elements afterwards, but it seems like the constructor of XElement calls ToString() on the value which means I have a hard time evaluating types.
Totally revamped answer:
Previously I recommended XmlWriter, but as it turns out that is not possible.
I'm editing this answer since XElement did not preserve types the way I thought, ie in
var x = new XElement("element", true);
x.WriteTo(new XmlTextWriter(Console.Out)); // Write stuff to console using XmlTextWriter
WriteValue(Boolean) is never called, the value is stored as XText in the XElement.
For those interested, XElement.WriteTo calls XmlWriter.WriteElement (an extension method) which in turn calls XmlWriter.WriteString.
It is possible to change the behavior of XmlWriter.WriteString but that also changes the output of
var x = new XElement("element", "true"); // String instead of bool
since the types are not stored.
My solution would be to create a factory and through it control how XElements are created. IE:
class XElementFactory {
public static XElement CreateXElement(string name, object value) {
var type = obj.GetType();
if (typeof(boolean).Equals(type))
// Format the XText accordig to specification, use the XText ctor for clarification and readability
return new XElement(name, (bool) obj ? new XText("True") : XText("False"));
// Maybe add additional if clauses if there are just a few special cases
return new XElement(name, obj); // Let it through
}
}
The reflection seriously hurts performance, but since we are dealing with XML my guess is that performance is not that important to begin with. If needed use a builder pattern where the correct builder gets called depending on type, ie something along the lines of:
Builders.First(b => b.Types.Contains(objToBuild.GetType())).BuildXElement(objToBuild); // Builders could maybe be filled by MEF?
This answer got kinda long (but I had something do during a long conference call =P), and in essence the issue turned out not to be a formatting problem but a creation problem.

return a List< Id:int, Name:string>

I am having a function which return a list of type: List< Id:Name, Name:string >
how do you do specify in C# to return this List Type ?
Here is the code:
public ?????? GetDepartements( int idRegion )
{
var a = (from o in _meilleurPrestaEntities.Departements
where o.de_id_region == idRegion
select new {Id = o.id_departement, Name = o.nom}).ToList();
return a;
}
the return is used as Json result.
thanks
I'd suggest using a key value pair
return List<KeyValuePair<int,string>>()
[Edit] You'll need to modify your code slightly - it should look something like this:
var a = (from o in _meilleurPrestaEntities.Departements
where o.de_id_region == idRegion
select new KeyValuePair<int,string>(o.id_departement,o.nom}).ToList();
You can't. You have a list of anonymous type and you can't specify anonymous type as part of a method return type (or pretty much anywhere else, unless you can use var).
To fix this, you have several options:
Create normal class to represent the return type and use that in your return type.
Use something like List<Tuple<int, string>>.
Return List<dynamic>. This way, you will be able to treat the returned value as usual, but you will get no compile-time checking or IntelliSense.
Return List<object>. This can be useful if you don't need to access the properties in the usual way, but you will only pass the result to something that uses reflection.
I think you have to specify a type and then use that type for your return value and in your select statement.
I don't have VisualStudio open to try it, but I think you can actually return dynamic in this case. Or you could use ExpandoObject.
However, as others have mentioned, the "better" way is to use something like Tuple or KeyValuePair, or don't be lazy and just make an actual model for what you will return to the view (in other words, a "View Model").

How can I remove item from querystring in asp.net using c#?

I want remove "Language" querystring from my url. How can I do this? (using Asp.net 3.5 , c#)
Default.aspx?Agent=10&Language=2
I want to remove "Language=2", but language would be the first,middle or last. So I will have this
Default.aspx?Agent=20
If it's the HttpRequest.QueryString then you can copy the collection into a writable collection and have your way with it.
NameValueCollection filtered = new NameValueCollection(request.QueryString);
filtered.Remove("Language");
Here is a simple way. Reflector is not needed.
public static string GetQueryStringWithOutParameter(string parameter)
{
var nameValueCollection = System.Web.HttpUtility.ParseQueryString(HttpContext.Current.Request.QueryString.ToString());
nameValueCollection.Remove(parameter);
string url = HttpContext.Current.Request.Path + "?" + nameValueCollection;
return url;
}
Here QueryString.ToString() is required because Request.QueryString collection is read only.
Finally,
hmemcpy answer was totally for me and thanks to other friends who answered.
I grab the HttpValueCollection using Reflector and wrote the following code
var hebe = new HttpValueCollection();
hebe.Add(HttpUtility.ParseQueryString(Request.Url.Query));
if (!string.IsNullOrEmpty(hebe["Language"]))
hebe.Remove("Language");
Response.Redirect(Request.Url.AbsolutePath + "?" + hebe );
My personal preference here is rewriting the query or working with a namevaluecollection at a lower point, but there are times where the business logic makes neither of those very helpful and sometimes reflection really is what you need. In those circumstances you can just turn off the readonly flag for a moment like so:
// reflect to readonly property
PropertyInfo isreadonly = typeof(System.Collections.Specialized.NameValueCollection).GetProperty("IsReadOnly", BindingFlags.Instance | BindingFlags.NonPublic);
// make collection editable
isreadonly.SetValue(this.Request.QueryString, false, null);
// remove
this.Request.QueryString.Remove("foo");
// modify
this.Request.QueryString.Set("bar", "123");
// make collection readonly again
isreadonly.SetValue(this.Request.QueryString, true, null);
I answered a similar question a while ago. Basically, the best way would be to use the class HttpValueCollection, which the QueryString property actually is, unfortunately it is internal in the .NET framework.
You could use Reflector to grab it (and place it into your Utils class). This way you could manipulate the query string like a NameValueCollection, but with all the url encoding/decoding issues taken care for you.
HttpValueCollection extends NameValueCollection, and has a constructor that takes an encoded query string (ampersands and question marks included), and it overrides a ToString() method to later rebuild the query string from the underlying collection.
Try this ...
PropertyInfo isreadonly =typeof(System.Collections.Specialized.NameValueCollection).GetProperty("IsReadOnly", BindingFlags.Instance | BindingFlags.NonPublic);
isreadonly.SetValue(this.Request.QueryString, false, null);
this.Request.QueryString.Remove("foo");
Gather your query string by using HttpContext.Request.QueryString. It defaults as a NameValueCollection type.
Cast it as a string and use System.Web.HttpUtility.ParseQueryString() to parse the query string (which returns a NameValueCollection again).
You can then use the Remove() function to remove the specific parameter (using the key to reference that parameter to remove).
Use case the query parameters back to a string and use string.Join() to format the query string as something readable by your URL as valid query parameters.
See below for a working example, where param_to_remove is the parameter you want to remove.
Let's say your query parameters are param1=1&param_to_remove=stuff&param2=2. Run the following lines:
var queryParams = System.Web.HttpUtility.ParseQueryString(HttpContext.Request.QueryString.ToString());
queryParams.Remove("param_to_remove");
string queryString = string.Join("&", queryParams.Cast<string>().Select(e => e + "=" + queryParams[e]));
Now your query string should be param1=1&param2=2.
You don't make it clear whether you're trying to modify the Querystring in place in the Request object. Since that property is read-only, I guess we'll assume you just want to mess with the string.
... In which case, it's borderline trivial.
grab the querystring off the Request
.split() it on '&'
put it back together into a new string, while sniffing for and tossing out anything starting with "language"
Get the querystring collection, parse it into a (name=value pair) string, excluding the one you want to REMOVE, and name it newQueryString
Then call Response.Redirect(known_path?newqueryString);
You're probably going to want use a Regular Expression to find the parameter you want to remove from the querystring, then remove it and redirect the browser to the same file with your new querystring.
Yes, there are no classes built into .NET to edit query strings. You'll have to either use Regex or some other method of altering the string itself.
If you have already the Query String as a string, you can also use simple string manipulation:
int pos = queryString.ToLower().IndexOf("parameter=");
if (pos >= 0)
{
int pos_end = queryString.IndexOf("&", pos);
if (pos_end >= 0) // there are additional parameters after this one
queryString = queryString.Substring(0, pos) + queryString.Substring(pos_end + 1);
else
if (pos == 0) // this one is the only parameter
queryString = "";
else // this one is the last parameter
queryString=queryString.Substring(0, pos - 1);
}
well I have a simple solution , but there is a little javascript involve.
assuming the Query String is "ok=1"
string url = Request.Url.AbsoluteUri.Replace("&ok=1", "");
url = Request.Url.AbsoluteUri.Replace("?ok=1", "");
Response.Write("<script>window.location = '"+url+"';</script>");
string queryString = "Default.aspx?Agent=10&Language=2"; //Request.QueryString.ToString();
string parameterToRemove="Language"; //parameter which we want to remove
string regex=string.Format("(&{0}=[^&\s]+|{0}=[^&\s]+&?)",parameterToRemove);
string finalQS = Regex.Replace(queryString, regex, "");
https://regexr.com/3i9vj
Parse Querystring into a NameValueCollection. Remove an item. And use the toString to convert it back to a querystring.
using System.Collections.Specialized;
NameValueCollection filteredQueryString = System.Web.HttpUtility.ParseQueryString(Request.QueryString.ToString());
filteredQueryString.Remove("appKey");
var queryString = '?'+ filteredQueryString.ToString();
ASP .NET Core (native, don't have to reference any additional libraries)
Within an ASP .NET Core Controller you would have access to an instance of Request
Request.Query is a query collection representing the query parameters, cast it to a list
From which you can filter and remove the params you want
Use QueryString.Create, which can take the list you just filtered as an input & generate a query string directly
var removeTheseParams = new List<string> {"removeMe1", "removeMe2"}.AsReadOnly();
var filteredQueryParams = Request.Query.ToList().Where(filterKvp => !removeTheseParams.Contains(filterKvp.Key));
var filteredQueryString = QueryString.Create(queryParamsFilteredList).ToString();
//Example: Console.Writeline(filteredQueryString) will give you "?q1=v1&q2=v2"
Optional Part Below: Can also encode those values if they are unsafe,
so in addition to the Where() above UrlEncode the query parameter keys and values using a Select() as shown below:
//Optional
.Select(cleanKvp => new KeyValuePair<string, string?>(UrlEncoder.Default.Encode(cleanKvp.Key),UrlEncoder.Default.Encode(cleanKvp.Value)))

Categories

Resources