Passing a Dictionary through Encrypted Querystring - c#

I have a dictionary object which i would like to encrypt, then put it in a querystring, then decrypt it on the other side.
I'm using JavaScriptSerializer for this. Now i've tried this on the same page onload, and it worked. So the encrypt/decrypt extension methods im using are working. This leads me to believe there's some issue going on with the querystring.
e.g.
var js = new JavaScriptSerializer();
var d = new Dictionary<string, string>();
d.Add("ID", "123456");
d.Add("Name", "HELLO TEST");
d.Add("Email", "test#email.com");
var s = js.Serialize(d).EncryptString();
var ds = js.Deserialize<Dictionary<string, string>>(s.DecryptString());
#ViewBag.Test = ds["Name"];
In the above example, EncryptString() and DecryptString() are the extension methods i'm using. This works as intended, so it pulls the correct value for "Name".
I run into problems when I put the serialized encrypted string into the querystring then try and decode it.
So on the first page, i have something like this:
var js = new JavaScriptSerializer();
var d = new Dictionary<string, string>();
d.Add("ID", "123456");
d.Add("Name", "HELLO TEST");
d.Add("Email", "test#email.com");
var s = HttpUtility.UrlEncode(js.Serialize(d).EncryptString());
s is then used as the querystring.
On the receiving page, i have this:
public ActionResult Display(string r)
{
var js = new JavaScriptSerializer();
var decryptedString = HttpUtility.UrlDecode(r).DecryptString();
var s = js.Deserialize<Dictionary<string, string>>(decryptedString);
return View();
}
This throws an error: System.FormatException: Invalid length for a Base-64 char array or string. This errors on the decryptstring line.
I don't get what's going on... I'm urlencoding the text before it goes into the querystring, then urldecoding it before it's deserialized..
EDIT
Figured it out.. I was encrypting it twice...

Chances are that you don't need to UrlDecode your string, because MVC will have done that before assigning the value of your r parameter. Try decrypting r directly.
And of course, I have to issue the warning: what you're doing here seems like a very bad idea. Whatever you're trying to accomplish by sending this encrypted dictionary in the URL, there is almost certainly a better way to accomplish it.

Most likely some characters don't roundtrip the way you expect (i.e. "+" tends to become space in this case).
Check with Fiddler (or any other HTTP debugging tool) what is actually send to/from your server. Than check if string that comes to you "Display" action - cood chance that you see what is wrong.

Related

Any way to add arrays into HTTP request URI by using C#?

I want to send a HTTP request that looks like this:
http://api.com/main?id=1234&id=5678, the id will be GUID in string eventually.
I tried the below piece of code:
var idString = string.Join(",", listOfIds);
var queryString = new Dictionary<string, string>
{
{"id", idString}
};
requestUri = QueryHelpers.AddQueryString(requestUri, queryString);
This will give me like: http://api.com/main?id=1234,5678 but I want the style like above.
Is there anyway to achieve this without using for loop?
Thanks!
QueryHelpers doesn't work with arrays because there's no standard way to pass an array of values in a query string. Some applications accept id=1,2,3 others id=1&id=2&id=3 while others id[0]=1&id[1]=2&id[2]=3.
.NET (Core) 5 and later
AddQueryString now works with lists of KeyValuePair<string,string>or KeyValuePair<string,StringValues>
var parameters=new []{
new KeyValuePair("id",new StringValues(arrayOfIds)),
new KeyValuePair("other","value"),
...
};
var finalUri=QueryHelpers.AddQueryString(requestUri, parameters);
The StringValues constructors accept either a single string or an array of strings
Before .NET (Core) 5
String.Join itself uses a loop and a StringBuilder to create a new string without allocating temporary strings. Strings are immutable, so any string modification operation results in a new temporary string.
You could use the source code as a guide to build your own loop. A quick solution could be something like this:
string ArrayToQueryString_DONT_USE(string name,string[] values)
{
var result=new StringBuilder();
result.AppendFormat("{0}={1}",name,value);
for(int i=1;i<values.Length;i++)
{
result.AppendFormat("&{0}={1}',name,values[i]);
}
return result.ToString();
}
Unfortunately, that won't work if the parameter names or values need encoding. That's what AddQueryString does, using, once again, a StringBuilder to avoid allocating temporary strings. We can borrow that code as well:
string ArrayToQueryString(string name,string[] values)
{
var result=new StringBuilder();
result.AppendFormat("{0}={1}",name,value);
for(int i=1;i<values.Length;i++)
{
result.Append('&');
result.Append(UrlEncoder.Default.Encode(name));
result.Append('=');
result.Append(UrlEncoder.Default.Encode(values[i]));
}
return result.ToString();
}

How can I deserialize a Yaml object containing strings into a List<string>?

I created a Yaml with filenames, so I can make my program check if every file of the list exists. I haven"t done much with yaml yet, and the documentations don't really help me.
This is my Yaml (It's pretty small):
DLLs:
- Filename1
- Filename2
- Filename3
At the moment, this is my code:
using (var reader = new StringReader(File.ReadAllText("./Libraries/DLLList.yml")))
{
/*
* List<string> allDllsList = deserialized yaml.getting all values of the "DLLs"-list
*/
var deserializer = new Deserializer();
var dlls = deserializer.Deserialize<dynamic>(reader)["DLLs"] as List<Object>;
/*This gives me the Error "Object System.Collections.Generic.Dictionary`2[System.Object,System.Object] cannot be converted into "System.String""*/
List<string> allDllsList = dlls.Cast<String>().ToList();
}
Can someone explain to me how I can get the values out of the Yaml file, and why it works in the way you do it?
Edit: Now it works, I used the wrong yaml, I had 2 versions
First, take the return value from deserializer.Deserialize<dynamic>(reader) and inspect it in the debugger. It's a Dictionary<String, Object>, and it's got an entry named "DLLs" that contains a List<Object>. The objects in that list are all strings. There you go:
var dlls = deserializer.Deserialize<dynamic>(reader)["DLLs"] as List<Object>;
// Use .Cast<String>() as shown if you want to throw an exception when there's something
// that does not belong there. If you're serious about validation though, that's a bit
// rough and ready.
// Use .OfType<String>() instead if you want to be permissive about additional stuff
// under that key.
List<string> allDllsList = dlls.Cast<String>().ToList();

Disable URL Encoding of Equals sign in a Parameter Value

I have this code below that creates the query parameter collection for a restful web service call
NameValueCollection outgoingQueryString = HttpUtility.ParseQueryString(String.Empty);
outgoingQueryString.Add("SessionID", _sessionId);
outgoingQueryString.Add("LoanNumberID", loanId.ToString());
outgoingQueryString.Add("Nonce", _nonce);
outgoingQueryString.Add("OtherParams", "Enable_Filter_Show_on_Action_Report=0");
The problem is that the last parameter value Enable_Filter_Show_on_Action_Report=0 get's it's '=' encoded to %3d SessionID=319A561B6D&LoanNumberID=351591&Nonce=3262383361&OtherParams=Enable_Filter_Show_on_Action_Report%3d0
when it should be
SessionID=319A561B6D&LoanNumberID=351591&Nonce=3262383361&OtherParams=Enable_Filter_Show_on_Action_Report=0
short of doing a rewrite after the fact is there a way to prevent this from happening? The service does not return the proper results set because it interprets the %3d as something it needs to filter.
What I did to fix the issue was the following. I just didn't know if there was a way to prevent this in the first place.
string queryString = outgoingQueryString.ToString().Replace("%3d", "=");
I don't know of a way to get NameValueCollection to do what you want; you're probably stuck with a workaround of some sort.
I do see a potential problem in your workaround implementation:
[Fact]
public void ProblemWithOriginalSolution()
{
NameValueCollection outgoingQueryString = HttpUtility.ParseQueryString(String.Empty);
outgoingQueryString.Add("Param1", "Value1");
outgoingQueryString.Add("Param2", "Value2=Something"); // this '=' needs to remain URL-encoded
outgoingQueryString.Add("OtherParams", "Enable_Filter_Show_on_Action_Report=0");
var queryString = outgoingQueryString.ToString().Replace("%3d", "=");
Assert.Contains("Value2=Something", queryString); // Passes, but not what we want
Assert.Contains("Value2%3dSomething", queryString); // Actually what we want, but fails
}
That might not matter for your needs, but if it does, I have two suggestions.
The first is to just use string concatentation. Depending on your use, this might need extra logic to handle the case where OtherParams is the only query string parameter (the ampersand should be omitted in that case). String concatenation is also a bad idea of OtherParams might contain characters that need to be URL encoded.
[Fact]
public void Concatentation()
{
NameValueCollection outgoingQueryString = HttpUtility.ParseQueryString(String.Empty);
outgoingQueryString.Add("Param1", "Value1");
var queryString = outgoingQueryString.ToString() + "&OtherParams=Enable_Filter_Show_on_Action_Report=0";
Assert.Contains("&OtherParams=Enable_Filter_Show_on_Action_Report=0", queryString);
}
The second is to do a double-substitution. This is a bit heavy-handed, and not terribly efficient, but should be reliable.
[Fact]
public void DoubleSubstitution()
{
// Make sure the placeholder doesn't have any characters that will get URL encoded!
// Also make sure it's not something that could appear in your input.
const string equalsPlaceholder = "__Equals__";
NameValueCollection outgoingQueryString = HttpUtility.ParseQueryString(String.Empty);
outgoingQueryString.Add("Param1", "Value1");
// First, remove the equals signs from the OtherParams value
outgoingQueryString.Add("OtherParams", "Enable_Filter_Show_on_Action_Report=0".Replace("=", equalsPlaceholder));
// Then, build the query string, and substitute the equals signs back in
var queryString = outgoingQueryString.ToString().Replace(equalsPlaceholder, "=");
Assert.Contains("&OtherParams=Enable_Filter_Show_on_Action_Report=0", queryString);
}

How do i convert a JSON string to a native C# array using a namespace compatible with Windows Store Apps?

I am trying to make a windows 8 Store app that gets results from a MySQL database from a PHP page as a REST service.
I'm looking for the PHP to return a JSON representation of an array of strings and have done that happily when dong the same between Javascript and PHP.
I need to take that same JSON string and use it in my C# Windows 8 store App, is there a way to take the return of that PHP page and convert it into a normal C# array, not a dictionary or more complex collection.
The database does have four fields so if i have to use a special object made for this i will, but I'd rather I didn't as this function doesn't require that amount of data.
The PHP page is like so - $search_text is passed in via a GET:
$databaseConnection = new mysqli(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
if ($databaseConnection->connect_error)
{
echo "Database connection failed: $databaseConnection->connect_error";
}
else
{
$search_text = $search_text."%";
$query = "SELECT DISTINCT street FROM gritroutes WHERE street LIKE ? LIMIT 5";
$statement = $databaseConnection->prepare($query);
$statement->bind_param('s', $search_text);
$statement->execute();
$statement->store_result();
$statement->bind_result($street);
$autonumber = 1;
while ($statement->fetch())
{
$resultarr[] = $street;
}
$statement->close();
echo json_encode($resultarr);
}
Just to be clear. I am writing a Windows Store App, the System.Web Namespace is unavailable so i can't use JavaScriptSerializer.
Just to add to Matthew's answer, you can deserialize using Json.NET (you can get it from NuGet), you'd do something like:
List<string> myStrings = JsonConvert.DeserializeObject<List<string>>(myJson);
This is in:
using Newtonsoft.Json;
Check out this article for practical example.
EDIT
- I'd also like to throw in this link, since it's just awesome.
I hope this helps.
Take a look at the JavaScriptSerializer class.
string myJson = "{blablabla I'm json}";
var serializer = new JavaScriptSerializer();
var myStrings = serializer.Deserialize<List<string>>(myJson);
foreach (var str in myString)
{
Console.WriteLine(str);
}
You could also use native Windows.Data.Json classes to do the parsing:
string json = #"[""item1"", ""item2"", ""item3""]";
var array = JsonArray.Parse(json).Select(i => i.GetString()).ToArray();

Converting JSON variables to lowercase in C#

I'm using the JSONPEncoderFactory,JSONPBehavior solution to enable JSONP in WCF. That's all fine, it's all set up and working well, my service returns the data correctly, no problems there.
However, I need to be able to force the JSON variable names into lowercase due to the way they are being used in JS, and this is something I haven't been able to figure out as yet.
Here is an example of my service output (the variable names and values have been changed to benign elements for this example)
{"Animals":["dog","cat","mouse"],"Owner":"Greg","Permanent":"y","ID":1,"DaysToStay":"1"}
Pretty simple right? I want the "Animals" to be "animals", and so on...
Do I need to use a json parser for this, or is it easy enough just to use a regular expression? I'd be grateful if someone could let me know how they've done this before.
Thanks!
You can use this function on JavaScript:
FN = function (obj)
{
var ret = null;
if (typeof(obj) == "string" || typeof(obj) == "number")
return obj;
else if (obj.push)
ret = [];
else
ret = {};
for (var key in obj)
ret[String(key).toLowerCase()] = FN(obj[key]);
return ret;
};
EDIT:
Deserialize a json string in a Dictionary with C#:
using System.Web.Script.Serialization;
var serializer = new JavaScriptSerializer();
var dic = serializer.Deserialize<Dictionary<string,dynamic>>(yourJSONString);
The complex fields will be deserialized into Dictionary. So you will ned a recursive function for inspect the matherialized dic.

Categories