At the moment I'm using all sorts of if statements and substrings in order to manipulate the query string parameters and wanted to know if there was a more efficient way of doing it.
To be precise - I'm needing to add a query string parameter to the current url but if it already exists - I need to just amend it.
To clarify - I CAN achieve this using standard string manipulation methods, and I know how to retrieve the current url etc. I'm just wondering if these wheels are already in place and I'm re-inventing them.
HttpUtility.ParseQueryString(queryString);
For more: http://msdn.microsoft.com/en-us/library/system.web.httputility.parsequerystring.aspx
Probably you are looking for HttpUtility.ParseQueryString().
You could parse the query string as a Dictionary<string,string> and use this to manipulate and then simply format the key value pairs as appropriate when outputting as a query string once more:
public Dictionary<string, string> ToDictionary(string queryString)
{
return queryString.TrimStart('?').Split('&').Select(qp => qp.Split(',')).ToDictionary(a => a[0], a=> a[1]);
}
public Dictionary<string, string> ToString(Dictionary<string, string> queryString)
{
return '?' + string.Join('&', queryString.Select(kvp => kvp.Key + '=' + kvp.Value));
}
Related
I have a dictionary like the below:
private readonly Dictionary<string, string> _packetData;
I try and convert a dictionary to json, I do json2dictionary also which just converts it to a flat dictionary, but this is in reverse, converting from dictionary2json.
public string GetJson()
{
var entries = _packetData.Select(d => string.Format("\"{0}\": [{1}]", d.Key, string.Join(",", d.Value)));
return "{" + string.Join(",", entries) + "}";
}
I've noticed that it doesn't wrap strings with double quotes each end, instead it does this.
{"test":test123}
What am I doing wrong?
There are no quotes in your output, because you haven't included quotes in your format string, just as you have with the key. I have removed your brackets ([ and ]), because they indicate an array value in JSON, and your dictionary has string values, so no need for string.Join().
var entries = _packetData.Select(d => string.Format("\"{0}\": \"{1}\"", d.Key, d.Value));
I would also recommend that you use the Newtonsoft's excellent Json.NET library, which you can find on nuget. Using a library instead of rolling your own implementation is more reliable and often more secure, and often means that you don't need to write as much code. In this case, it would be as simple as:
JsonConvert.SerializeObject(_packetData);
https://www.newtonsoft.com/json/help/html/SerializeDictionary.htm
var entries = _packetData.Select(d => string.Format("\"{0}\": [\"{1}\"]", d.Key, string.Join(",", d.Value)));
This is probably a very simple question but google has let me down sofar and keeps pointing me towards python solutions.
I have a webpage where applciations/users can supply querystringparameters.To Retrieve the querystring parameters I use the following code:
IDictionary<string, string> qStrings = HtmlPage.Document.QueryString;
to check the presence of a specified key, I use the following code:
if (!String.IsNullOrEmpty(qStrings["PARAM1"]))
{}
Knowing our users, i'm expecting them to give parameterkeys as follows: "Param1", "param1", "pArAm1"
How can simply cast every key in a dictionary to uppercase without iterating each key-valuepair?
Or how can i alter the qStrings["PARAM1"] so it ignores the case?
You can use StringComparer to find keys ignoring their case:
var qStrings = new Dictionary<string, string>(
HtmlPage.Document.QueryString,
StringComparer.OrdinalIgnoreCase)
Simplest Way
qStrings = qStrings .ToDictionary(k => k.Key.ToUpper(), k => k.Value.ToUpper());
Maybe you can do it like below:
Dictionary<string, string> qStrings = new Dictionary<string, string>();
foreach (var a in qStrings.Keys)
{
switch (a.ToUpper())
{
case "PARAM1":
break;
}
}
Without iterating is not possible. No matter what approach you use there is going to be some sort of iteration. The this is you need to limit the insertion of the data to a single unified casing rather than allowing users to input all sorts of casing.
Taking your example: "Param1", "param1", "pArAm1", a key will be created for each single one of these as they are treated as separate entities. The best way to handle that is to force the casing at the insertion rather than when querying for values.
For example:
void AddToDictionary(string key, string value)
{
qStrings[key.ToUpper()] = value;
}
I have text documents like the following which contain single and multiple variables:
title:: Report #3
description:: This is the description.
note:: more information is available from marketing
note:: time limit for this project is 18 hours
todo:: expand the outline
todo:: work on the introduction
todo:: lookup footnotes
I need to iterate through the lines of this text document and fill a collection with these variables, currently I'm using a Dictionary:
public Dictionary<string, string> VariableNamesAndValues { get; set; }
But this doesn't work on multiple, identical keys such as "note" and "todo" in the above example since keys have to be unique in a Dictionary.
What is the best collection so that I can not only get single values like this:
string variableValue = "";
if (VariableNamesAndValues.TryGetValue("title", out variableValue))
return variableValue;
else
return "";
but that I can also get multiple values out like this:
//PSEUDO-CODE:
List<string> variableValues = new List<string>();
if (VariableNamesAndValues.TryGetValues("note", out variableValues))
return variableValues;
else
return null;
If your keys and values are strings then use a NameValueCollection. It supports multiple values for a given key.
It's not the most efficient collection in the world. Particularly because it's a non-generic class, uses a lot of virtual method calls, and the GetValues method will allocate arrays for its return values. But unless you require the best performing collection, this is certainly the most convenient collection that does what you ask.
You can make a Dictionary of key: string and value: List of String
Dictionary<string,List<string>>
EDIT 1 & 2:
I've thought of a better solution if you can use .NET 3.0 or higher.
Here's a LINQ example (I typed it without Visual Studio, so I hope it compiles ;)):
string[] lines = File.ReadAllLines("content.txt");
string[] separator = {":: "};
var splitOptions = StringSplitOptions.RemoveEmptyEntries;
var items = from line in lines
let parts = line.Split(separator, splitOptions)
group parts by parts[0] into partGroups
select partGroups;
A short explanation of the example above:
Get all lines from the file in a String array
Define some Split options (to keep the example readable)
For each line in the lines array, split it on the ":: "
Group the results of the split on the first split part (e.g. title, description, note, ...)
Store the grouped items in the items variable
The result of the LINQ query is a IQueryable<IGrouping<string, IEnumberable<string>>>.
Each item in the result has a Key property containing the key of the line (title, description, note, ...).
Each item can be enumerated containing all of values.
You could use a Lookup<TKey, TElement> :
ILookup<string, string> lookup = lines.Select(line => line.Split(new string[] { ":: " })
.ToLookup(arr => arr[0], arr => arr[1]);
IEnumerable<string> notes = lookup["note"];
Note that this collection is read-only
You may use PowerCollections which is an open source project that has a MultiDictionary data structure which solves your problem.
Here is a sample of how to use it.
Note: Jon Skeet suggested it before in his answer to this question.
I'm not a c# expert, but I think Dictionary<string, List<string>>
or some kind of HashMap<string, List<string>> might work.
For example (Java pseudocode):
aKey aValue
aKey anotherValue
if(map.get(aKey) == null)
{
map.put(aKey, new ArrayList(){{add(aValue);}});
}
else
{
map.put(aKey, map.get(aKey).add(anotherValue));
}
or something similar.
(or, the shortest way:
map.put(aKey, map.get(aKey) != null ? map.get(aKey).add(value) : new ArrayList(){{add(value);}});
I have used Dictionary<string, HashSet<string>> for getting multiple values in the past. I would love to know if there is something better though.
Here is how you can emulate getting only one value.
public static bool TryGetValue(this Dictionary<string, HashSet<string>> map, string key, out string result)
{
var set = default(HashSet<string>);
if (map.TryGetValue(key, out set))
{
result = set.FirstOrDefault();
return result == default(string);
}
result = default(string);
return false;
}
Is there a way to get all the querystring name/value pairs into a collection?
I'm looking for a built in way in .net, if not I can just split on the & and load a collection.
Yes, use the HttpRequest.QueryString collection:
Gets the collection of HTTP query string variables.
You can use it like this:
foreach (String key in Request.QueryString.AllKeys)
{
Response.Write("Key: " + key + " Value: " + Request.QueryString[key]);
}
Well, Request.QueryString already IS a collection. Specifically, it's a NameValueCollection. If your code is running in ASP.NET, that's all you need.
So to answer your question: Yes, there is.
You can use LINQ to create a List of anonymous objects that you can access within an array:
var qsArray = Request.QueryString.AllKeys
.Select(key => new { Name=key.ToString(), Value=Request.QueryString[key.ToString()]})
.ToArray();
If you have a querystring ONLY represented as a string, use HttpUtility.ParseQueryString to parse it into a NameValueCollection.
However, if this is part of a HttpRequest, then use the already parsed QueryString-property of your HttpRequest.
QueryString property in HttpRequest class is actually NameValueCollection class. All you need to do is
NameValueCollection col =
Request.QueryString;
Create dictionary of parameters
Dictionary<string, string> parameters = new Dictionary<string, string>();
parameters = Request.QueryString.Keys.Cast<string>().ToDictionary(k => k, v => Request.QueryString[v]);
For instance:
String login = String.Format("computer={0}&ver={1}.{2}.{3}&from={4}&realcomputername={5}&type={6}&Channels={7}&Hotkeys={8}&ID={9}\r\n",
serviceConfig.Computer,
serviceConfig.Version.Major,
serviceConfig.Version.Minor,
serviceConfig.Version.Build,
userName,
Environment.MachineName,
type,
serviceConfig.ChannelsString,
serviceConfig.HotKeysString,
serviceConfig.AlarmGroupName);
This does not make for very readable code, and as more and more parameters get added, it looks uglier and is more confusing to find which parameter goes in which slot.
I know this is a noob question, and I think I'm only asking for how to format the text to be more readable, but if there's a better way to do this, I'd like to know that too.
You could look at the StringBuilder class and split the assembly of the string over several lines.
The AppendFormat method (thanks Joel) is what you want in this case.
String login = String.Format(
"computer={0}"+
"&ver={1}.{2}.{3}"+
"&from={4}"+
"&realcomputername={5}"+
"&type={6}"+
"&Channels={7}"+
"&Hotkeys={8}"+
"&ID={9}\r\n",
serviceConfig.Computer,
serviceConfig.Version.Major,
serviceConfig.Version.Minor,
serviceConfig.Version.Build,
userName,
Environment.MachineName,
type,
serviceConfig.ChannelsString,
serviceConfig.HotKeysString,
serviceConfig.AlarmGroupName);
Assuming you can use LINQ, you can shove your arguments into a Dictionary<string, string>, then join the arguments together:
Dictionary<string, string> args = new Dictionary<string, string>
{
{"computer", serviceConfig.Computer},
{"ver", string.Format("{0}.{1}.{2}",
serviceConfig.Version.Major,
serviceConfig.Version.Minor,
serviceConfig.Version.Build)},
{"from", userName},
{"realcomputername", Environment.MachineName},
{"type", type},
{"Channels", serviceConfig.ChannelsString},
{"Hotkeys", serviceConfig.HotKeysString},
{"ID", serviceConfig.AlarmGroupName},
};
string login = string.Join("&", args.Select(arg =>
string.Format("{0}={1}", arg.Key, arg.Value)).ToArray());
This will be some miniscule amount slower and more memory-intensive than a simple string.Format, but it looks like you're about to make an HTTP request, so I can almost guarantee that it won't be the bottleneck.
That final line can also be pulled out into an extension method that you can use anytime you want to build a query string like this.
Also, it's important to note that since Dictionary does not preserve insertion order, you aren't guaranteed that the parameters in the query string will be in that exact order. That shouldn't matter, but in case it does you can replace the Dictionary with a List<KeyValuePair<string, string>> (OrderedDictionary should also work).