How to retrieve query string value which contains Hash character - c#

In my Asp.net (C#) application, I need to read three parameters from the query string (Item, Code and Location). Url is given below.
http://localhost/Reports?ITEM=A#1234&CODE=0013&LOCATION=LOCA#001
I am reading it like this.
_code = Request["CODE"]; //value should be 0013
_item = Request["ITEM"]; //value should be A#1234
_location = Request["LOCATION"]; //value should be LOCA#001
But after # character, nothing retrievable to the variables.
Our database contains lots of data items with hash(#) character. Any idea how to read with # ?

Use URL encoding for the param values urlencode
To encode or decode values outside of a web application, use the WebUtility class.
using System;
using System.Net;
public class Program
{
public static void Main()
{
string urlValue = "ITEM="+WebUtility.UrlEncode("A#1234") + "&CODE=0013&LOCATION=" + WebUtility.UrlEncode("LOCA#001");
Console.WriteLine(urlValue);
Console.WriteLine(WebUtility.UrlDecode(urlValue));
}
}

Related

How to parse a guid from a string containing backslashes?

I need to create guids from their string equivalents from a text dump that I get from the Mailchimp 1.0 export api.
The guids are all strings that contain the backslash \ character, for example here is (truncated) one of them:
"\"9ffd2c3-6er456ds\""
When I pass the guid to the following methods, nothing works when I then attempt Guid.TryParse.
string[] values = sub.Split(',');
string rawguid = values[3];
var guid = rawguid.Replace("\\", "");
var tguid = rawguid.Trim();
var sguid = rawguid.Normalize().ToString();
How can I properly parse these guid strings into guids?
There are no backslashes in your guid - those are escaped doublequotes inside the string : the backslash is escaping the " inside it. Use .Replace("\"","") to remove them.
Beside that - you do not have a valid GUID - there are r and a s inside - guids consist of 32 digits using only 0-9a-fA-F.
Example using Guid.ParseExact:
using System;
public class Program
{
public static void Main()
{
var guid = Guid.ParseExact(
"\"ab9ffd2c3-6e456daaaaaaaaaaaaaaaaa\"" // guid with masked " inside
.Replace("-","") // remove all - for N
.Replace("\"",""), "N"); // remove all \" as well
Console.WriteLine( guid );
}
}
to get a parsed guid:
ab9ffd2c-36e4-56da-aaaa-aaaaaaaaaaaa

UriBuilder().Query will wrongly encode non-ASCII characters

I am working on an asp.net mvc 4 web application. and i am using .net 4.5. now i have the following WebClient() class:
using (var client = new WebClient())
{
var query = HttpUtility.ParseQueryString(string.Empty);
query["model"] = Model;
//code goes here for other parameters....
string apiurl = System.Web.Configuration.WebConfigurationManager.AppSettings["ApiURL"];
var url = new UriBuilder(apiurl);
url.Query = query.ToString();
string xml = client.DownloadString(url.ToString());
XmlDocument doc = new XmlDocument();
//code goes here ....
}
now i have noted a problem when one of the parameters contain non-ASCII charterers such as £, ¬, etc....
now the final query will have any non-ASCII characters (such as £) encoded wrongly (as %u00a3). i read about this problem and seems i can replace :-
url.Query = query.ToString();
with
url.Query = ri.EscapeUriString(HttpUtility.UrlDecode(query.ToString()));
now using the later approach will encode £ as %C2%A3 which is the correct encoded value.
but the problem i am facing with url.Query = Uri.EscapeUriString(HttpUtility.UrlDecode(query.ToString())); in that case one of the parameters contains & then the url will have the following format &operation=AddAsset&assetName=&.... so it will assume that I am passing empty assetName parameter not value =&??
EDIT
Let me summarize my problem again. I want to be able to pass the following 3 things inside my URL to a third part API :
Standard characters such as A,B ,a ,b ,1, 2, 3 ...
Non-ASCII characters such as £,¬ .
and also special characters that are used in url encoding such as & , + .
now i tried the following 2 approaches :
Approach A:
using (var client = new WebClient())
{
var query = HttpUtility.ParseQueryString(string.Empty);
query["model"] = Model;
//code goes here for other parameters....
string apiurl = System.Web.Configuration.WebConfigurationManager.AppSettings["ApiURL"];
var url = new UriBuilder(apiurl);
url.Query = query.ToString();
string xml = client.DownloadString(url.ToString());
XmlDocument doc = new XmlDocument();
//code goes here ....
}
In this approach i can pass values such as & ,+ since they are going to be url encoded ,,but if i want to pass non-ASCII characters they will be encoded using ISO-8859-1 ... so if i have £ value , my above code will encoded as %u00a3 and it will be saved inside the 3rd party API as %u00a3 instead of £.
Approach B :
I use :
url.Query = Uri.EscapeUriString(HttpUtility.UrlDecode(query.ToString()));
instead of
url.Query = query.ToString();
now I can pass non-ASCII characters such as £ since they will be encoded correctly using UTF8 instead of ISO-8859-1. but i can not pass values such as & because my url will be read wrongly by the 3rd party API.. for example if I want to pass assetName=& my url will look as follow:
&operation=Add&assetName=&
so the third part API will assume I am passing empty assetName, while I am trying to pass its value as &...
so not sure how I can pass both non-ASCII characters + characters such as &, + ????
You could use System.Net.Http.FormUrlEncodedContent instead.
This works with a Dictionary for the Name/Value pairing and the Dictionary, unlike the NameValueCollection, does not "incorrectly" map characters such as £ to an unhelpful escaping (%u00a3, in your case).
Instead, the FormUrlEncodedContent can take a dictionary in its constructor. When you read the string out of it, it will have properly urlencoded the dictionary values.
It will correctly and uniformly handle both of the cases you were having trouble with:
£ (which exceeds the character value range of urlencoding and needs to be encoded into a hexadecimal value in order to transport)
& (which, as you say, has meaning in the url as a parameter separator, so that values cannot contain it--so that it has to be encoded as well).
Here's a code example, that shows that the various kinds of example items you mentioned (represented by item1, item2 and item3) now end up correctly urlencoded:
String item1 = "£";
String item2 = "&";
String item3 = "xyz";
Dictionary<string,string> queryDictionary = new Dictionary<string, string>()
{
{"item1", item1},
{"item2", item2},
{"item3", item3}
};
var queryString = new System.Net.Http.FormUrlEncodedContent(queryDictionary)
.ReadAsStringAsync().Result;
queryString will contain item1=%C2%A3&item2=%26&item3=xyz.
Maybe you could try to use an Extension method on the NameValueCollection class. Something like this:
using System.Collections.Specialized;
using System.Text;
using System.Web;
namespace Testing
{
public static class NameValueCollectionExtension
{
public static string ToUtf8UrlEncodedQuery(this NameValueCollection nv)
{
StringBuilder sb = new StringBuilder();
bool firstIteration = true;
foreach (var key in nv.AllKeys)
{
if (!firstIteration)
sb.Append("&");
sb.Append(HttpUtility.UrlEncode(key, Encoding.UTF8))
.Append("=")
.Append(HttpUtility.UrlEncode(nv[key], Encoding.UTF8));
firstIteration = false;
}
return sb.ToString();
}
}
}
Then, in your code you can do this:
url.Query = query.ToUtf8UrlEncodedQuery();
Remember to add a using directive for the namespace where you put the NameValueCollectionExtension class.
The problem here isn't UriBuilder.Query, it's UriBuilder.ToString(). Read the documentation here: https://msdn.microsoft.com/en-us/library/system.uribuilder.tostring(v=vs.110).aspx. The property is defined as returning the "display string" of the builder, not a validly encoded string. Uri.ToString() has a similar problem, in that it doesn't perform proper encoding.
Use the following instead: url.Uri.AbsoluteUri, that will always be a properly encoded string. You shouldn't have to do any encoding on the way into the builder (that's part of it's purpose, after all, to properly encode things).
You need to use:
System.Web.HttpUtility.UrlEncode(key)
Change your code to this:
using (var client = new WebClient())
{
var query = HttpUtility.ParseQueryString(string.Empty);
query["model"] = Model;
//code goes here for other parameters....
string apiurl = System.Web.Configuration.WebConfigurationManager.AppSettings["ApiURL"];
var url = new UriBuilder(apiurl);
url.Query = HttpUtility.UrlEncode(query.ToString());
string xml = client.DownloadString(url.ToString());
XmlDocument doc = new XmlDocument();
//code goes here ....
}
If nothing helps, then just manually convert those problematic chars inside values of parameters
& to %26
+ to %2B
? to %3F

Including control characters in a .txt file to be read by C#

I'm working on a project that uses a plain ASCII .txt file as a key/value configuration file. The current format for ConfigFile.txt is something like
FirstName=Elmer|LastName=Fudd|UserId=EFudd|Password=fubar|Date=7/29/2016
This is easy to read into the program and create a dictionary with KeyValuePairs with code something like:
using (FileStream fs = new FileStream("ConfigFile.txt", FileMode.Open))
{
using (StreamReader sr = new StreamReader(fs))
{
string fileText = sr.ReadToEnd();
// Tokenize the entire file string into separate key=value strings.
string[] tokens = fileText.Split('|');
// Iterate through all of the key=value strings, tokenize each one into a key=Value
// pair and add the key and value as separate strings into the dictionary.
foreach (string token in tokens)
{
string[] keyValuePair = token.Split('=');
configDict.Add(keyValuePair[0], keyValuePair[1]);
}
}
}
It first splits out each key/value as a separate string using the '|' as the delimiter.
FirstName=Elmer
LastName=Fudd
UserId=EFudd
Password=foobar
Date=7/29/2016
Then, for each key/value string, it separates the key and value on the '=' delimiter, creates a KeyValuePair, and inserts it into a dictionary for later lookups in the program.
So far so good. Users are instructed not to create passwords with either delimiter. However, I now have to encrypt the password before including it in the file and the encryption routine can produce any printable character from 0x20 through 0x7F. So, an encrypted password can end up with either or both of the delimiters. I can end up with 'foobar' (or whatever) being encrypted by the encryption engine into P#|=g%. This messes up the ability of the split function to work properly.
So, I want to change the delimiters typed into the Notepad .txt file to control characters so that, instead of the '|' delimiter, I am using 0x1E (Record Separator) and replace the '=' sign with 0x1F (Unit Separator).
I can escape and code this directly in C# with no problems, but how would I modify the original .txt disk file so that it will read in the delimiters as single (non-printable) characters correctly?
So, Instead of having plain text like that, What I would do is use a proper serialization format, such as JSON.
There are tools out there that do the hard work for you.
The built-in System.Web.Script.Serialization namespace has some tools that you can use, but I prefer to use Json.Net. If you have Visual Studio, you can install it with nuGet(let me know in the comments if you need more help than that).
But once you add it to your project, you can do something like this
using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;
namespace ConsoleApplication1
{
public class Program
{
static void Main(string[] args)
{
var dict = new Dictionary<string, string>();
dict.Add("FirstName", "Elmer");
dict.Add("LastName", "Fudd");
dict.Add("Password", #"\a\ansld\sb\b8d95nj");
var json = JsonConvert.SerializeObject(dict);
File.WriteAllText("ConfigFile.txt, json);
var txt = File.ReadAllText("ConfigFile.txt");
var newDict = JsonConvert.DeserializeObject<Dictionary<string, string>>(txt);
}
}
}
and ConfigFile.txt will look like this
{"FirstName":"Elmer","LastName":"Fudd","Password":"\\a\\ansld\\sb\\b8d95nj"}
If you want it more human-readable, use
var json = JsonConvert.SerializeObject(dict, Formatting.Indented);
and you'll get
{
"FirstName": "Elmer",
"LastName": "Fudd",
"Password": "\\a\\ansld\\sb\\b8d95nj"
}
You can convert integers to chars so just do this...
string[] tokens = fileText.Split((char)0x1e);
// ...
string[] keyValuePair = token.Split((char)0x1f);
... but encoding your passwords as base64 would be easier and cleaner...
string base64 = Convert.ToBase64String(passwordHash);
byte[] passwordHash = Convert.FromBase64String(base64);
... NOTE:
it is possible that the hashes/encrypted data will contain these characters so I wouldn't just dump the hases into the text file.
The following class extract the string segments using Regular Expressions and support password with non-printable characters : 0x00 .. 0xFF
The class include properties to the segments of the configuration
you can run Demo Example at .NEt Fiddle
using System;
using System.Text.RegularExpressions;
class ConfigParser
{
public string Text { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string UserId { get; set; }
public string Password { get; set; }
public string Date { get; set; }
public ConfigParser(string text)
{
Text =text;
Parse(text);
}
private static string pattern = #"
^FirstName=(?<firstname>\w+) \|
LastName=(?<lastname>\w+) \|
UserId=(?<userid>\w+) \|
Password=(?<pasword>.+)
Date=(?<date>.+)
$
";
private Regex regex = new Regex(pattern,
RegexOptions.Singleline
| RegexOptions.ExplicitCapture
| RegexOptions.CultureInvariant
| RegexOptions.IgnorePatternWhitespace
| RegexOptions.Compiled
);
private void Parse(string text)
{
Console.WriteLine("text: {0}",text);
Match m = regex.Match(text);
FirstName = m.Groups["firstname"].ToString();
LastName = m.Groups["lastname"].ToString();
UserId = m.Groups["userid"].ToString();
Password = m.Groups["pasword"].ToString();
Date = m.Groups["date"].ToString();
}
}
How to use:
var text ="your text here";
var c = new ConfigParser(text );
you can access the properties of the class: FirstName, LastName,....
Console.WriteLine("firstname: {0}", c.FirstName);
Console.WriteLine("lastname: {0}", c.LastName);
Console.WriteLine("UserId: {0}", c.UserId);
Console.WriteLine("Password: {0}", c.Password);
Console.WriteLine("date {0}", c.Date);
Sample output:
The password include non-printable characters | separator and symbols
text: FirstName=Elmer|LastName=Fudd|UserId=EFudd|Password=fg%|uy|◄¶|hj↑khg|Date=7/29/2016
firstname: Elmer
lastname: Fudd
UserId: EFudd
Password: fg%|uy|◄¶|hj↑khg
date: 7/29/2016
Easiest Answer:
Insert the special characters into the string using the ALT-numberpad value trick. Record Group ALT-31 (▼) to delimit the end of a Key/Value pair and Item Group ALT-30 (▲) to delimit the key from the value. Save the string as UTF-8.
Code for delimiters is
private static char tokenDelimiter = ('▲');
private static char keyValuePairDelimiter = ('▼');
using the same ALT-numberpad trick to put in the up and down triangles. Include instructions that the black triangles are NEVER to be edited or removed and explain their meaning.
It takes me back to my old DOS days. Simple, and took 5 minutes to implement - and it doesn't require that the existing code base be materially changed - just the two delimiter characters changed.

How to initialize an object from a string containing key value pairs in C#

The object has 139 fields; the string initializer may have some or all of these fields. It is formatted like this: "FirstName":"Bart","LastName":"Simpson","Company":"Fat Tony's","Address":"55 Maple Drive" etc. I could just look for the fields like this:
if (initializerString.contains("FirstName:")
FirstName="get the next series of chars until the ", or end of string
and so forth. But is there a more compact way to do this?
Seeing as your format is incredibly similar to JSON (except for the lack of braces, actually), as people commented you'll fare better by using JSON.NET.
If you have complete control over this string, just transform it into a json and deserialize it:
JsonConvert.DeserializeObject<YourClass>(yourString);
It will automatically set the correct properties while deserializing your data.
In case you don't have control of this format, and you need to parse it anyway, just put up the braces and you're good:
JsonConvert.DeserializeObject<YourClass>("{" + yourString + "}");
And if you don't have a specific class for this, you can also replace YourClass for a Dictionary<string,object>
You'll find this library as Newtonsoft.Json, and I believe it's the most popular library for dealing with JSON data.
I've made a working example so you can see it in action (note that I kept your string format, but please try to use straight json):
using System;
using System.Linq;
using System.Collections.Generic;
using Newtonsoft.Json;
public class Program
{
public class Information
{
public string FirstName{get;set;}
public string LastName{get;set;}
public string Company{get;set;}
public string Address{get;set;}
}
public static void Main()
{
string myObject = "\"FirstName\":\"Bart\",\"LastName\":\"Simpson\",\"Company\":\"Fat Tony's\",\"Address\":\"55 Maple Drive\"";
var converted = JsonConvert.DeserializeObject<Dictionary<string, object>>("{"+myObject+"}");
var converted2 = JsonConvert.DeserializeObject<Information>("{"+myObject+"}");
Console.WriteLine(String.Join("\n", converted.Select(c=> c.Key + ": " + c.Value)));
Console.WriteLine(converted2.FirstName);
}
}
And here's a bonus fiddle:
https://dotnetfiddle.net/fudUYZ
Using regex you could do:
string firstName = Regex.Match(yourstring,#"(?<=""FirstName"":"").*?(?="")").Value;
However this really looks like a json string and there are easier ways to get your data.
You could create a Dictionary<string,object> dict in which there is the name of the property and the property.
You can then split the string,
//Remove the "
initializerString = initializerString.Replace('"', '');
//Split by ,
var tmp = initializerString.Split(",");
//Foreach pair key/value split by :
foreach( var x in tmp){
var tmp2=x.Split(":");
//Assign the value to the property in the Dictionary
dict[tmp2[0]]=tmp2[1];
}
Warning. Since I don't actually know what you're using this code for, this is more of a general idea than working code.

C# 2.0 function which will return the formatted string

I am using C# 2.0 and I have got below type of strings:
string id = "tcm:481-191820"; or "tcm:481-191820-32"; or "tcm:481-191820-8"; or "tcm:481-191820-128";
The last part of string doesn't matter i.e. (-32,-8,-128), whatever the string is it will render below result.
Now, I need to write one function which will take above string as input. something like below and will output as "tcm:0-481-1"
public static string GetPublicationID(string id)
{
//this function will return as below output
return "tcm:0-481-1"
}
Please suggest!!
If final "-1" is static you could use:
public static string GetPublicationID(string id)
{
int a = 1 + id.IndexOf(':');
string first = id.Substring(0, a);
string second = id.Substring(a, id.IndexOf('-') - a);
return String.Format("{0}0-{1}-1", first, second);
}
or if "-1" is first part of next token, try this
public static string GetPublicationID(string id)
{
int a = 1 + id.IndexOf(':');
string first = id.Substring(0, a);
string second = id.Substring(a, id.IndexOf('-') - a + 2);
return String.Format("{0}0-{1}", first, second);
}
This syntax works even for different length patterns, assuming that your string is
first_part:second_part-anything_else
All you need is:
string.Format("{0}0-{1}", id.Substring(0,4), id.Substring(4,5));
This just uses substring to get the first four characters and then the next five and put them into the format with the 0- in there.
This does assume that your format is a fixed number of characters in each position (which it is in your example). If the string might be abcd:4812... then you will have to modify it slightly to pick up the right length of strings. See Marco's answer for that technique. I'd advise using his if you need the variable length and mine if the lengths stay the same.
Also as an additional note your original function of returning a static string does work for all of those examples you provided. I have assumed there are other numbers visible but if it is only the suffix that changes then you could happily use a static string (at which point declaring a constant or something rather than using a method would probably work better).
Obligatory Regular Expression Answer:
using System.Text.RegularExpressions;
public static string GetPublicationID(string id)
{
Match m = RegEx.Match(#"tcm:([\d]+-[\d]{1})", id);
if(m.Success)
return string.Format("tcm:0-{0}", m.Groups[1].Captures[0].Value.ToString());
else
return string.Empty;
}
Regex regxMatch = new Regex("(?<prefix>tcm:)(?<id>\\d+-\\d)(?<suffix>.)*",RegexOptions.Singleline|RegexOptions.Compiled);
string regxReplace = "${prefix}0-${id}";
string GetPublicationID(string input) {
return regxMatch.Replace(input, regxReplace);
}
string test = "tcm:481-191820-128";
stirng result = GetPublicationID(test);
//result: tcm:0-481-1

Categories

Resources