public static string DictToQueryString(Dictionary<string, string> data)
{
string querystring = "";
foreach (string key, string val in data)
querystring += key + "=" + val + "&";
return querystring;
}
How i foreach?
Your "code" would have an extraneous "&" on the end. Do you want this? It's likely that you don't want this but please correct if you do. Assuming not, the simplest approach is to let String.Join do its job:
public static string DictToQueryString(Dictionary<string, string> data) {
return String.Join(
"&",
data.Select(kvp => String.Format("{0}={1}", kvp.Key, kvp.Value))
.ToArray()
);
In C# 4.0 the call to ToArray will be obviated.
Like this:
public static string DictToQueryString(Dictionary<string, string> data)
{
StringBuilder queryString = new StringBuilder();
foreach(var pair in data)
{
if (queryString.Length > 0)
queryString.AppendFormat("&{0}={1}", pair.Key, pair.Value);
else
queryString.AppendFormat("{0}={1}", pair.Key, pair.Value);
}
return queryString.ToString();
}
I believe this is what you're looking for?
public static string DictToQueryString(Dictionary<string, string> data)
{
string querystring = "";
foreach (string key in data.Keys)
{
string val = data[key];
querystring += key + "=" + val + "&";
}
return querystring;
}
Related
I'm working with a dictionary of type <string,string> like this:
Dictionary<string, string> parameters = new Dictionary<string, string>()
{
{"llave1", "valor1"},
{"llave2", "valor2"},
{"llave3", "valor3"},
{"llave4", "valor4"}
};
I want to get a string like this:
"llave1=valor1&llave2=valor2&llave3=valor3&llave4=valor4"
to solve this problem I made this:
foreach (var element in parameters)
{
strParameters += element.Key + "=" + element.Value;
if (index < parameters.Count)
{
strParameters += "&";
index++;
}
}
I wanted to know any way to get the same string result but using linq or String.Join I'm trying to refactory my code
I have a HttpContext context and I iterate through some of its Request properties to collect info. Currently I do it this way:
if (context.Request.Headers?.Keys != null)
{
var items = new StringBuilder();
foreach (var key in context.Request.Headers.Keys)
{
items.AppendLine(key + " = " + context.Request.Headers[key]);
}
result.Headers = items.ToString();
}
if (context.Request.Form?.Keys != null)
{
var items = new StringBuilder();
foreach (var key in context.Request.Form.Keys)
{
items.AppendLine(key + " = " + context.Request.Form[key]);
}
result.Form = items.ToString();
}
if (context.Request.Query?.Keys != null)
{
var items = new StringBuilder();
foreach (var key in context.Request.Query.Keys)
{
items.AppendLine(key + " = " + context.Request.Query[key]);
}
result.Query = items.ToString();
}
I want to convert this repetitive code to a generic method (if you can suggest any other ways, I would be fine with them, too). I tried writing a generic method:
private static string ParseKeys<T>(IDictionary<object, object> dict)
{
var sb = new StringBuilder();
foreach (var key in dict.Keys)
{
sb.AppendLine(key + " = " + dict[key]);
}
return sb.ToString();
}
and calling it like this:
result.Headers = ParseKeys<IHeaderDictionary>(context.Request.Headers);
result.Form = ParseKeys<IFormCollection>(context.Request.Form);
result.Query = ParseKeys<IQueryCollection>(context.Request.Query);
But I get such errors: cannot convert from 'Microsoft.AspNetCore.Http.IHeaderDictionary' to 'System.Collections.Generic.IDictionary<object, object>'
I tried various combinations but I still couldn't manage to avoid errors. Am I trying to do impossible here, or is there a simple to do what I want?
Those collections you mention (IHeaderDictionary, IFormCollection and IQueryCollection) all implement the same interface: IEnumerable<KeyValuePair<string, StringValues>> so here you don't need a generic method. Instead, you can do something like this:
private static string ParseKeys(IEnumerable<KeyValuePair<string, StringValues>> values)
{
var sb = new StringBuilder();
foreach (var value in values)
{
sb.AppendLine(value.Key + " = " + string.Join(", ", value.Value));
}
return sb.ToString();
}
And call it as you were previously:
result.Headers = ParseKeys(context.Request.Headers);
result.Form = ParseKeys(context.Request.Form);
result.Query = ParseKeys(context.Request.Query);
You are using a generic method, but you are not using the generic type parameter T. As far as the IHeaderDictionary and the IFormCollection, it is enough to accept an IEnumerable<KeyValuePair<string, string[]>>, since both interfaces inherit it:
private static string ParseKeys(IEnumerable<KeyValuePair<string, string[]>> dict)
{
var sb = new StringBuilder();
foreach (var keyValuePair in dict)
{
sb.AppendLine(keyValuePair.Key + " = " + String.Join(", ", keyValuePair.Value));
}
return sb.ToString();
}
As far as the IQueryCollection is concerned, it is an IEnumerable<KeyValuePair<string, StringValues>>. You can easily transform this to the required type with an iterator:
private static IEnumerable<KeyValuePair<string, string[]>> Transform(IEnumerable<KeyValuePair<string, StringValues>> source) {
foreach(var item in source) {
yield return new KeyValuePair<string, string[]>(item.Key, item.Value.ToArray());
}
}
Eventually, you can call the method like:
result.Headers = ParseKeys(context.Request.Headers);
result.Form = ParseKeys(context.Request.Form);
result.Query = ParseKeys(Transform(context.Request.Query));
I'm trying to replace text. I'm using a dictionary for the task.
public static string cleanString(this String str) {
Dictionary<string, string> dict = new Dictionary<string,string>();
dict.Add("JR", "Junior");
dict.Add("SR", "Senior");
foreach (KeyValuePair<string,string> d in dict) {
if (str.BlindContains(p.Key)) {
str = str.BlindReplace(str, p.Value);
}
}
return str;
}
BlindContains and BlindReplace just ignore the case of the replacement (and BC ensures the string is not part of another word):
public static bool BlindContains(this String str, string toCheck)
{
if (Regex.IsMatch(str, #"\b" + toCheck + #"\b", RegexOptions.IgnoreCase))
return str.IndexOf(toCheck, StringComparison.OrdinalIgnoreCase) >= 0;
return false;
}
public static string BlindReplace(this String str, string oldStr, string newStr)
{
return Regex.Replace(str, oldStr, newStr, RegexOptions.IgnoreCase);
}
The problem
If I call my method on a a string, the following occurs:
string mystring = "The jr. is less than the sr."
mystring.cleanString()
returns "Junior"
However, when I print
Console.WriteLine(Regex.Replace(mystring, "jr.", "junior", Regex.IgnoreCase));
I get the output: "The junior is less than the sr."
Why does the loop compromise the task?
You should be passing the key in your dictionary (Which contains the text to search for), rather than the actual string you are searching in.
It should be:
str = str.BlindReplace(p.Key, p.Value);
As opposed to:
str = str.BlindReplace(str, p.Value);
You are currently replacing your string with the value "Junior" because you specified your string as the text to search for. (Which will make it replace the entire string instead of just the keyword)
In cleanString implementation, I think you made an error in your call to BlindReplace. Instead of:
str = str.BlindReplace(str, p.Value);
I believe you should have called:
str = str.BlindReplace(d.Key, d.Value);
I have this code:
NameValueCollection nv = HttpUtility.ParseQueryString(queryString);
foreach (KeyValuePair<String,String> pr in nv) {
//process KeyValuePair
}
This compiles, but when I try to run it I get an InvalidCastException.
Why is this? Why can't I use KeyValuePair to iterate over a NameValueCollection, and what should I use instead?
First of all, NameValueCollection doesn't use KeyValuePair<String,String>. Also, foreach only exposes the key:
NameValueCollection nv = HttpUtility.ParseQueryString(queryString);
foreach (string key in nv) {
var value = nv[key];
}
You can't do that directly, but you can create an extension method like so:
public static IEnumerable<KeyValuePair<string, string>> AsKVP(
this NameValueCollection source
)
{
return source.AllKeys.SelectMany(
source.GetValues,
(k, v) => new KeyValuePair<string, string>(k, v));
}
Then you can do:
NameValueCollection nv = HttpUtility.ParseQueryString(queryString);
foreach (KeyValuePair<String,String> pr in nv.AsKVP()) {
//process KeyValuePair
}
Note: inspired by this. SelectMany is required to handle duplicate keys.
vb.net version:
<Extension>
Public Function AsKVP(
source As Specialized.NameValueCollection
) As IEnumerable(Of KeyValuePair(Of String, String))
Dim result = source.AllKeys.SelectMany(
AddressOf source.GetValues,
Function(k, v) New KeyValuePair(Of String, String)(k, v))
Return result
End Function
For future reference, you could also use this syntax:
foreach(string key in Request.QueryString)
{
var value = Request.QueryString[key];
}
ANother extension method, for learning purposes:
public static IEnumerable<KeyValuePair<string, string>> ToIEnumerable(this NameValueCollection nvc)
{
foreach (string key in nvc.AllKeys)
{
yield return new KeyValuePair<string, string>(key, nvc[key]);
}
}
NameValueCollection uses the old-skool enumerator:
var enu = ConfigurationManager.AppSettings.GetEnumerator();
while(enu.MoveNext())
{
string key = (string)enu.Current;
string value = ConfigurationManager.AppSettings[key];
}
I did like this and it works:
foreach (string akey in request.Query.Keys.Cast<string>())
writer.WriteLine(akey + " = " + request.Query[akey]);
Be aware that the key name might appear more than once in the query string and that the comparison is usually case sensitive.
If you want to just get the value of the first matching key and not bothered about case then use this:
public string GetQueryValue(string queryKey)
{
foreach (string key in QueryItems)
{
if(queryKey.Equals(key, StringComparison.OrdinalIgnoreCase))
return QueryItems.GetValues(key).First(); // There might be multiple keys of the same name, but just return the first match
}
return null;
}
To convert nameValueCollection from QueryString to List you can use extension like this:
public static List<KeyValuePair<string, string>> GetParams(this HttpRequest request)
{
var nameValueCollection = HttpUtility.ParseQueryString(request.QueryString.Value);
List<KeyValuePair<string, string>> keyValueCollections = new List<KeyValuePair<string, string>>();
if (!nameValueCollection.IsNullOrEmpty())
{
foreach (var key in nameValueCollection.AllKeys)
{
keyValueCollections.Add(new KeyValuePair<string, string>(key, nameValueCollection[key]));
}
}
return keyValueCollections;
}
public static void PrintKeysAndValues2( NameValueCollection myCol )
{
Console.WriteLine( " [INDEX] KEY VALUE" );
for ( int i = 0; i < myCol.Count; i++ )
Console.WriteLine( " [{0}] {1,-10} {2}", i, myCol.GetKey(i), myCol.Get(i) );
Console.WriteLine();
}
http://msdn.microsoft.com/en-us/library/system.collections.specialized.namevaluecollection.aspx
Given this code:
private ObjectQuery<E> GetEntity()
{ // Pluralization concern. Table and Type need to be consistently named.
// TODO: Don't get cute with database table names. XXX and XXXs for pluralization
return _dc.CreateQuery<E>("[" + typeof(E).Name + "s]");
}
Is there any way to determine an Entity type's plural name so I can access the table, rather than just adding an 's' to the name?
For example, Medium is singular and Media is plural.
You can also use the PluralizationService provided by EF 4. Here is a blog post that covers the service in good detail.
http://web.archive.org/web/20130521044050/http://www.danrigsby.com/blog/index.php/2009/05/19/entity-framework-40-pluralization
I'm not sure how entity framework does this, but I use the pluralizer from Ruby on Rails. You can find this at http://dev.rubyonrails.org/browser/trunk/activesupport/lib/active_support/inflector.rb#L106. This is easy enough to implement in C#.
The entire source for a translation to C# is:
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
public static class Inflector
{
private static List<KeyValuePair<Regex, string>> _pluralRules = new List<KeyValuePair<Regex, string>>();
private static List<KeyValuePair<Regex, string>> _singularRules = new List<KeyValuePair<Regex, string>>();
private static List<KeyValuePair<string, string>> _irregulars = new List<KeyValuePair<string, string>>();
private static List<string> _uncountables = new List<string>();
static Inflector()
{
_uncountables.Add("equipment");
_uncountables.Add("information");
_uncountables.Add("rice");
_uncountables.Add("money");
_uncountables.Add("species");
_uncountables.Add("series");
_uncountables.Add("fish");
_uncountables.Add("sheep");
AddPlural("$", "s", true);
AddPlural("s$", "s");
AddPlural("(ax|test)is$", "$1es");
AddPlural("(octop|vir)us$", "$1i");
AddPlural("(alias|status)$", "$1es");
AddPlural("(bu)s$", "$1ses");
AddPlural("(buffal|tomat)o$", "$1oes");
AddPlural("([ti])um$", "$1a");
AddPlural("sis$", "ses");
AddPlural("(?:([^f])fe|([lr])f)$", "$1$2ves");
AddPlural("(hive)$", "$1s");
AddPlural("([^aeiouy]|qu)y$", "$1ies");
AddPlural("(x|ch|ss|sh)$", "$1es");
AddPlural("(matr|vert|ind)(?:ix|ex)$", "$1ices");
AddPlural("([m|l])ouse$", "$1ice");
AddPlural("^(ox)$", "$1en");
AddPlural("(quiz)$", "$1zes");
AddSingular("s$", "");
AddSingular("(n)ews$", "$1ews");
AddSingular("([ti])a$", "$1um");
AddSingular("((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$", "$1$2sis");
AddSingular("(^analy)ses$", "$1sis");
AddSingular("([^f])ves$", "$1fe");
AddSingular("(hive)s$", "$1");
AddSingular("(tive)s$", "$1");
AddSingular("([lr])ves$", "$1f");
AddSingular("([^aeiouy]|qu)ies$", "$1y");
AddSingular("(s)eries$", "$1eries");
AddSingular("(m)ovies$", "$1ovie");
AddSingular("(x|ch|ss|sh)es$", "$1");
AddSingular("([m|l])ice$", "$1ouse");
AddSingular("(bus)es$", "$1");
AddSingular("(o)es$", "$1");
AddSingular("(shoe)s$", "$1");
AddSingular("(cris|ax|test)es$", "$1is");
AddSingular("(octop|vir)i$", "$1us");
AddSingular("(alias|status)es$", "$1");
AddSingular("^(ox)en", "$1");
AddSingular("(vert|ind)ices$", "$1ex");
AddSingular("(matr)ices$", "$1ix");
AddSingular("(quiz)zes$", "$1");
AddIrregular("person", "people");
AddIrregular("man", "men");
AddIrregular("child", "children");
AddIrregular("sex", "sexes");
AddIrregular("move", "moves");
AddIrregular("cow", "kine");
}
private static void AddIrregular(string singular, string plural)
{
AddPlural(singular.Substring(0, 1).ToLower() + singular.Substring(1) + "$", plural.Substring(0, 1).ToLower() + plural.Substring(1));
AddPlural(singular.Substring(0, 1).ToUpper() + singular.Substring(1) + "$", plural.Substring(0, 1).ToUpper() + plural.Substring(1));
AddSingular(plural.Substring(0, 1).ToLower() + plural.Substring(1) + "$", singular.Substring(0, 1).ToLower() + singular.Substring(1));
AddSingular(plural.Substring(0, 1).ToUpper() + plural.Substring(1) + "$", singular.Substring(0, 1).ToUpper() + singular.Substring(1));
}
private static void AddPlural(string expression, string replacement)
{
AddPlural(expression, replacement, false);
}
private static void AddPlural(string expression, string replacement, bool caseSensitive)
{
var re = caseSensitive ? new Regex(expression) : new Regex(expression, RegexOptions.IgnoreCase);
_pluralRules.Insert(0, new KeyValuePair<Regex, string>(re, replacement));
}
private static void AddSingular(string expression, string replacement)
{
AddSingular(expression, replacement, false);
}
private static void AddSingular(string expression, string replacement, bool caseSensitive)
{
var re = caseSensitive ? new Regex(expression) : new Regex(expression, RegexOptions.IgnoreCase);
_singularRules.Insert(0, new KeyValuePair<Regex, string>(re, replacement));
}
public static string Pluralize(string value)
{
if (_uncountables.Contains(value))
return value;
foreach (var rule in _pluralRules)
{
if (rule.Key.Match(value).Success)
{
return rule.Key.Replace(value, rule.Value);
}
}
return value;
}
public static string Singularize(string value)
{
if (_uncountables.Contains(value))
return value;
foreach (var rule in _singularRules)
{
if (rule.Key.Match(value).Success)
{
return rule.Key.Replace(value, rule.Value);
}
}
return value;
}
public static string Camelize(string value, bool firstLetterUppercase = true)
{
if (firstLetterUppercase)
{
return
Regex.Replace(
Regex.Replace(value, "/(.?)", p => "::" + p.Groups[1].Value.ToUpperInvariant()),
"(?:^|_)(.)", p => p.Groups[1].Value.ToUpperInvariant()
);
}
else
{
return
value.Substring(0, 1).ToLowerInvariant() +
Camelize(value.Substring(1));
}
}
public static string Underscore(string value)
{
value = value.Replace("::", "/");
value = Regex.Replace(value, "([A-Z]+)([A-Z][a-z])", p => p.Groups[1].Value + "_" + p.Groups[2].Value);
value = Regex.Replace(value, "([a-z\\d])([A-Z])", p => p.Groups[1].Value + "_" + p.Groups[2].Value);
value = value.Replace("-", "_");
return value.ToLowerInvariant();
}
}
Have you tried
YourEntityObject.EntityKey.EntitySetName
Assuming your table names are plural.
If the generic method you have takes an entity (that inherits from EntityObject), then you can access the EntityKey from it.
private ObjectQuery<E> GetEntity()
{ // Pluralization concern. Table and Type need to be consistently named.
// TODO: Don't get cute with database table names. XXX and XXXs for pluralization
return _dc.CreateQuery<E>("[" + e.EntityKey.EntitySetName + "]");
}