C# building a string for JSON using variables - c#

I'm relatively new to C# and trying to deserialize a string from JSON for this value; ["format"]["tags"]["ENCODER"]
// Manually building the string works fine
string test = (dict["format"]["tags"]["ENCODER"]);
string found_value = "";
const char quote = '\u0022';
string encoder = "[" + quote + "format" + quote + "][" + quote + "tags" + quote + "][" + quote + "ENCODER" + quote + "]";
// Just as a test
encoder = encoder.Replace("\u005c\u0022", "\u0022");
// This Fails
found_value = (dict[encoder]);
It throws an exception of type 'System.Collections.Generic.KeyNotFoundException' occurred in mscorlib.dll but was not handled in user code
Additional information: The given key was not present in the dictionary.
So I'm sure it's the way I'm passing the encoder string. Probably something really simple but I've spent hours trying various things and become blind to it now.
Thanks in advance

Basically, C# isn't a scripting language, but is a compiled language. This means that there is no equivalent of a javascript eval() function, and strings don't perform the same as the equivalent code string. So the second lookup, you're trying to do this:
dict["[\"format\"][\"tags\"][\"eval\"]")
And it is rightly complaining that your first dictionary there doesn't have a key of the name
"[\"format\"][\"tags\"][\"eval\"]"
Why are you trying to do this in the second way, when the first one works?

Related

Get substring in between two other strings?

I am trying to get a string in between two sub strings, but I am running into an issue.
I am trying to use Selenium to automate a web test, and extract the profile ID from the javascript in the page source. I am running into an ArgumentOutOfRangeException?
It doesn't matter with I'm searching for the correct or wrong values and passing them to GetInbetween, it throws this exception. I cannot see anything wrong with my code, so here I am.
Code:
var source = GetSource();
var username = "username1";
Console.WriteLine("Here: " + source.GetInbetween("window.__additionalDataLoaded('/" + username + "/',{\"logging_page_id\":\"", "\","));
Source (truncated for readability):
window.__additionalDataLoaded('/username1/',{"logging_page_id":"profilePage_10216","logging_page_username": "username1"})
Exception:
ArgumentOutOfRangeException
Length cannot be less than zero. (Parameter 'length')
It throws the exception in this method
public static string GetInbetween(this string s, string start, string end)
{
return s[(s.IndexOf(start) + start.Length)..s.IndexOf(end)];
}
LinqPad test:
void Main()
{
var source = "window.__additionalDataLoaded('/username1/',{\"logging_page_id\":\"profilePage_10216\",\"logging_page_username\":\"username1\"})";
var username = "username1";
Console.WriteLine(source.IndexOf("window.__additionalDataLoaded('/" + username + "/',{\"logging_page_id\":\""));
Console.WriteLine(source.IndexOf("\","));
Console.WriteLine($"[{source}]");
Console.WriteLine($"[{"window.__additionalDataLoaded('/" + username + "/',{\"logging_page_id\":\""}]");
Console.WriteLine("Here: " + source.GetInbetween("window.__additionalDataLoaded('/" + username + "/',{\"logging_page_id\":\"", "\"."));
}
You might get this error if end exists in s before start. So try using s.LastIndexOf(end).
It says 'Length cannot be less than zero.' which means IndexOf is returning -1, which it does if the substring is not found in the search string... So you are looking for a substring which doesn't exist in the string. Make sure you have case-sensitivity correct, or use an IndexOf overload which ignores case.
Edit -- Your GetSource() method must not be returning the string you think it is returning... See, works fine explicitly searching that string:
Passing a start index to IndexOf(end) like this seems to fix it.
return s[(s.IndexOf(start) + start.Length)..s.IndexOf(end, s.IndexOf(start))];
The final method looks like this:
public static string GetInbetween(this string s, string start, string end)
{
return s[(s.IndexOf(start) + start.Length)..s.IndexOf(end, s.IndexOf(start))];
}

Encoding with APNS Push in C#

I'm using PushSharp to handle push notifications for iOS.
Everything went well until I realized the way I'm handling the push isn't too powerful:
apnsBroker.QueueNotification(new ApnsNotification
{
DeviceToken = device.DeviceIdentifier,
Payload = JObject.Parse("{\"aps\":{\"alert\" : {\"title\" : \"" + title
+ "\", \"body\" : \"" + body + "\"}, \"badge\":" + badgeCount + "}, " +
"\"entity_id\" : \"" + entityId + "\", \"category_id\" : \"" + categoryId + "\", \"sub_id\" : \"" + subId
+ "\"}")
});
Edit / Update One of the parameters I am trying is \t\ud83d\uddbc️\ (basically I wanted to pass in the unicode character of the picture frame emoji, so it can be rendered in the APNS alert). It is breaking currently.
I am sending that in C# like this: #"\t\ud83d\uddbc️\"
So as you can see, I'm rendering out the JSON Payload and this framework takes in a JObject. The problem, as I immediately assumed during my code review, is that if any of those parameters above (title, body, etc) end up being strings such as { or " or { etc that it will "break" the JSON because JObject can't parse that as valid JSON.
What do you think I should do in this case? Do I have to encode it and I suppose the only drawback would be I have backslashes or something in the encoding? Any recommendations to permit the user input (title and body can be free form text so anything is possible).
Thank you in advance for any advice!
EDIT
Thank you again Zero for your help.
var escapedString = JsonConvert.ToString(normalString);
saved the day. It's important to note that if you are using this, then escapedString should not be wrapped in ""'s since it will already be escaped (as he mentioned below).
As long as your variables are quoted (inside ") there's no need to escape braces ({ and })
As for breaking the quote (having ") inside variables, you could do something like this:
//Escapes quotes
param = param.Replace(#"""", #"\""");
You also need to escape the escape char itself \
//Escapes backslash
param = param.Replace(#"\", #"\\");
Also, here are all valid escapes.
If you're using Newtonsoft.Json they have a method to do this for you.
Example usage below or take a look here. Be aware this will add quotes to the string for you.
//Or use the return value inline with interpolation "$" or concatenation "+"
var escapedString = JsonConvert.ToString(normalString);

What is the difference between {0} and +?

Is there any difference between the use of {0} and + as they both are doing the same work of printing the length on the screen:
Console.WriteLine("Length={0}", length);
Console.WriteLine("Length=" + length);
In your trivial example there's no difference. But there are very good reasons to prefer the formatted ({0}) option: it makes localization of international software much, much easier, and it makes editing your existing strings by third parties much easier.
Imagine for example you're writing a compiler that produces this error message:
"Cannot implicitly convert type 'int' to 'short'"
Do you really want to write the code
Console.WriteLine("Cannot implicitly convert type '" + sourceType + "' to '" + targetType + "'");
? Good heavens no. You want to put this string into a resource:
"Cannot implicitly convert type '{0}' to '{1}'"
and then write
Console.WriteLine(FormatError(Resources.NoImplicitConversion, sourceType, targetType));
Because then you have the freedom to decide that you want to change that to:
"Cannot implicitly convert from an expression of type '{0}' to the type '{1}'"
Or
"Conversion to '{1}' is not legal with a source expression of type '{0}'"
These choices can be made later, by English majors, without requiring changes to the code.
You can also translate those resources into other languages, again without changing the code.
Start always using formatting strings now; when you need to write localizable software that uses string resources properly, you'll already be in the habit.
The second line will create a string and print the string out.
The first line will use composite formatting, like string.Format.
Here are some good reasons to use composite formatting.
There is a difference.
ex:
Console.WriteLine("the length is {0} which is the length", length);
Console.WriteLine("the length is "+length+" which is the length");
+ concatenates two strings, {0} is a placeholder for a string to be inserted.
{n} is a placeholder which can be used with multiple options. where n is a number
In your example it would make a difference and the end result would be same that is concatenation of two string. However in something like
var firstName = "babba";
var lastName ="abba";
var dataOfBirth = new Date();
Console
.Write(" Person First Name : {0} | Last Name {1} }| Last Login : {2:d/M/yyyy HH:mm:ss}",
firstName,
secondName,
dateOfBirth);
it provides a easy to read interface with easy formatting
{n} where n >= 0 allows you to substitute values in order of occurrence in the string.
string demo = "demo", example = "example";
Console.WriteLine("This is a {0} string used as an {1}", demo, example);
+ allows you to concatenate two or more strings together.
Console.WriteLine("This is a " + demo + " string used as an " + example);

Issue with forming a string with double quotes

I want to form a string as <repeat><daily dayFrequency="10" /></repeat>
Wherein the value in "" comes from a textboxe.g in above string 10. I formed the string in C# as
#"<repeat><daily dayFrequency=""+ txt_daily.Text + "" /></repeat>" but i get the output as
<repeat><daily dayFrequency="+ txt_daily.Text+ " /></repeat>. How to form a string which includes the input from a textbox and also double quotes to be included in that string.
To insert the value of one string inside another you could consider string.Format:
string.Format("foo {0} bar", txt_daily.Text)
This is more readable than string concatenation.
However I would strongly advise against building the XML string yourself. With your code if the user enters text containing a < symbol it will result in invalid XML.
Create the XML using an XML library.
Related
How can I build XML in C#?
Escape it with \ Back slash. putting # in front wont do it for you
string str = "<repeat><daily dayFrequency=\"\"+ txt_daily.Text + \"\" /></repeat>";
Console.Write(str);
Output would be:
<repeat><daily dayFrequency=""+ txt_daily.Text + "" /></repeat>
You could do it like this:
var str = String.Format(#"<repeat><daily dayFrequency="{0}" /></repeat>",
txt_daily.Text);
But it would be best to have an object that mapped to this format, and serialize it to xml
string test = #"<repeat><daily dayFrequency=" + "\"" + txt_daily.Text + "\"" + "/></repeat>";

String escaping issue with Roslyn statement creation

I've the following code, which builds up a Roslyn statement which calls Roslyn code inside, but I've a problem with string escaping.
Here is the code:
var parseStatementArgument = "var statement = Syntax.ParseStatement(\\\"Console.WriteLine (\\\"Hello {0}\\\", parameter1);\\\");";
var st = Syntax.InvocationExpression(
Syntax.MemberAccessExpression(SyntaxKind.MemberAccessExpression, Syntax.IdentifierName("Syntax"), Syntax.IdentifierName("ParseStatement")))
.AddArgumentListArguments(
Syntax.Argument(Syntax.LiteralExpression(
SyntaxKind.StringLiteralExpression,
Syntax.Literal(
text: "\"" + parseStatementArgument + "\"",
value: parseStatementArgument)
)));
var variableDeclarator = Syntax.VariableDeclarator(Syntax.Identifier("statement"))
.WithInitializer(Syntax.EqualsValueClause(st));
var varStatement = Syntax.VariableDeclaration(Syntax.IdentifierName("var"), Syntax.SeparatedList(variableDeclarator));
var varStatementText = varStatement.Format().GetFormattedRoot().GetFullText() + ";";
var scriptEngine = new ScriptEngine(
new [] {
MetadataReference.Create("Roslyn.Compilers"),
MetadataReference.Create("Roslyn.Compilers.CSharp"),
MetadataReference.Create("Roslyn.Services"),
MetadataReference.Create("Roslyn.Services.CSharp")
},
new [] {
"System",
"Roslyn.Compilers.CSharp",
"Roslyn.Scripting",
"Roslyn.Scripting.CSharp",
"Roslyn.Services"
});
var session = Session.Create();
scriptEngine.Execute(varStatementText, session);
scriptEngine.Execute("Console.WriteLine (statement.Format().GetFormattedRoot().GetFullText());", session);
The problem is that the "statement" printed to the console windows via the script engine execution will miss the backslashed around the "Hello {0}" string. If I add double escaping (additional \ into the parameter, Roslyn will raise compile errors about missing commas.
How may I update this code to get a syntactically correct version of what I want into the statement variable?
How about switching to using verbatim string levels, and just add another level of escaping as you add the node.
Something like:
var parseStatementArgument = #"var statement = Syntax.ParseStatement(#""Console.WriteLine (""""Hello {0}"""", parameter1);"");";
var st = Syntax.InvocationExpression(
Syntax.MemberAccessExpression(SyntaxKind.MemberAccessExpression, Syntax.IdentifierName("Syntax"), Syntax.IdentifierName("ParseStatement")))
.AddArgumentListArguments(
Syntax.Argument(Syntax.LiteralExpression(
SyntaxKind.StringLiteralExpression,
Syntax.Literal(
text: "#\"" + parseStatementArgument.Replace("\"", "\"\"") + "\"",
value: parseStatementArgument)
)));
Based on Kevin's tip on how to replace string for literals I played around and found this as a solution that works, but it raised another problem.
The solution:
var parseStatementArgument = "var statement = Syntax.ParseStatement(\\\"Console.WriteLine (\\\\\\\"Hello {0}\\\\\\\", parameter1);\\\");";
var st = Syntax.InvocationExpression(
Syntax.MemberAccessExpression(SyntaxKind.MemberAccessExpression, Syntax.IdentifierName("Syntax"), Syntax.IdentifierName("ParseStatement")))
.AddArgumentListArguments(
Syntax.Argument(Syntax.LiteralExpression(
SyntaxKind.StringLiteralExpression,
Syntax.Literal(
text: "\"" + parseStatementArgument + "\"",
value: parseStatementArgument.Replace ("\\\\\\", "\\"))
)));
Now it correctly outputs a code snippet which is syntactically correct and compiles well.
The problem it raises is that I had to modify the source string and not the derived string to get the correct result. When rewriting code or generating code with Roslyn it can not be a requirement to double or triple escape string literals to make Roslyn able to deal with that correctly, maybe its a Roslyn issue, I hope that someone will shed some light on an elegant solution which works for all kind of strings.

Categories

Resources