I'm trying to deserialize a JSON string into an object. I am using the System.JSON library within Xamarin and this is what I have so far:
ServerConnection.Receive (bb);
data = Encoding.ASCII.GetString (bb);
try{
MemoryStream stream = new MemoryStream(bb);
JsonValue jsonCounters = JsonObject.Load(stream);
}
catch(Exception error){
Console.WriteLine ("ERROR: " + error.Message);
}
The problem I am having is that jsonCounters is always null. I understand that JSON.NET is a better library, but using it would require upgrading my account, and that's something I'm not really ready to do just yet.
EDIT:
I followed the link supplied by JamesMontemagno. I then wrote the following into my application:
ServerConnection.Receive (bb);
data = Encoding.ASCII.GetString (bb);
try{
JsonValue value = JsonValue.Parse(data);
JsonObject jsonCounters = value as JsonObject;
}
catch(Exception error){
Console.WriteLine ("ERROR: " + error.Message);
}
The only problem is that when I create the byte array that I receive on I do:
byte[] bb = new byte[1024]
and the issue is then when I receive and try to parse the JSON it seems that the difference between the JSON length and the length of the byte array isn't lost, it's just converted to white space at the end of the JSON, which causes JsonValue.Parse to fail with ERROR: extra characters in JSON input. At line 1, column 642. I tried data = data.Trim(), but that did a whole lot of nothing.
JamesMontemagno was right with his link. It showed me the correct usage of JsonObject. After I was able to get the Json to atleast atempt to parse I needed to remove the trailing white space. I did that by using the following code to create a new byte array that would parse.
ServerConnection.Receive (rawRecieve);
int i = rawRecieve.Length - 1;
while (rawRecieve [i] == 0) {
--i;
}
byte[] cleanRecieve = new byte[i+1];
Array.Copy(rawRecieve, cleanRecieve, i+1);
I stole that bit of code from: Removing trailing nulls from byte array in C#
Related
I plan on answering my own question as there is a shortage of support for Global Payments.
I'm following this guide: https://developer.globalpay.com/docs/browser-auth-3DS and when working on the challenge notification url and following the example code verbatim it's ultimately resulting in an error being displayed in the ThreeDSecure iframe:
Invalid Base64 string
Here's the example from their documentation:
var cres = Request.Form["cres"];
try
{
byte[] data = Convert.FromBase64String(cres); <-- THIS FAILS
string challengeUrlResponseString = Encoding.UTF8.GetString(data);
...
}
catch (Exception exce)
{
...
}
The reason for this issue is because it's not a valid base64 string. There are potentially invalid characters that will need to be replaced as well as proper padding:
var cres = payload["cres"].ToString();
var padded = cres.Replace("-", "+").Replace("_", "/").PadRight(cres.Length + (4 - cres.Length % 4) % 4, '=');
var data = Convert.FromBase64String(padded);
While I'm at it, in case you get stumped on the next portion... which is returning the result, you literally have to write the script in the response:
HttpContext.Current.Response.Write($"<script src=\"actual-path-to/globalpayments-3ds.min.js\"></script><script>GlobalPayments.ThreeDSecure.handleChallengeNotification({challengeUrlResponseString});</script>");
Or, in my case I'm using action result, so I just return it within:
return Ok($"<script src=\"actual-path-to/globalpayments-3ds.min.js\"></script><script>GlobalPayments.ThreeDSecure.handleChallengeNotification({challengeUrlResponseString});</script>");
This works for me, but if anyone knows of a better proper way, please share, as the docs are lacking.
I'm confused as a java dev trying his way into C#. I've read about the string type and it being immutable and such , not much different from java except that it doesn't seem to be an object like there but I'm getting weird behavior regardless. I have following toString method on a class
public override string ToString()
{
StringBuilder builder = new StringBuilder();
builder.Append("BlockType: ");
builder.Append(BlockType + "\n");
//builder.Append(System.Text.ASCIIEncoding.ASCII.GetChars(Convert.FromBase64String("dHh0AA==")));
//builder.Append("\n");
builder.Append("BlockName: ");
builder.Append(BlockName + "\n");
//builder.Append(System.Text.ASCIIEncoding.ASCII.GetChars(Convert.FromBase64String(this.BlockName)));
//builder.Append("\n");
builder.Append("BlockLength: " + this.BlockLength + "\n");
builder.Append("pBlockData: " + this.pBlockData + "\n");
return builder.ToString();
}
When I fill it with data. Taking in account that BlockType and BlockName will contain a Base64 String. I get following result
FileVersionNo: 0
nx: 1024
ny: 512
TileSize: 256
HorizScale: 10
Precis: 0,01
ExtHeaderLength: 35
nExtHeaderBlocks: 1
pExtHeaderBlocks: System.Collections.Generic.LinkedList`1[LibFhz.HfzExtHeaderBlock]
BlockType: dHh0AA==
BlockName: YXBwLW5hbWUAAAAAAAAAAA==
BlockLength: 11
pBlockData: System.Byte[]
Which is perfect exactly what I want, however when I try to get the ASCII value of those Base64 (or UTF-8, I tried both) I get the following result
FileVersionNo: 0
nx: 1024
ny: 512
TileSize: 256
HorizScale: 10
Precis: 0,01
ExtHeaderLength: 35
nExtHeaderBlocks: 1
pExtHeaderBlocks: System.Collections.Generic.LinkedList`1[LibFhz.HfzExtHeaderBlock]
BlockType: txt
The code just seems to stop, without error or stacktrace. I have no idea what is going on. I thought first that a \0 is missing so I've added it to the string, then I thought I need a \r\n ... again not the sollution, I started to google with people just wanting to know how to do a Bas64 to UTF-8 conversion ... but that part seems easy ... this code stop isn't.
Any insights or links to decent articles about string handling in .net would be appreciated
I've had a look at what you get from this:
var test = Convert.FromBase64String("YXBwLW5hbWUAAAAAAAAAAA==");
var builder = new StringBuilder();
builder.Append(System.Text.Encoding.ASCII.GetChars(test));
The answer is the string "app-name" with a load of null (0) characters at the end.
You could try removing all the null characters by adding this line just before you return builder.ToString():
builder.Replace("\0", null);
That may or may not help, depending on what you're doing with the returned string.
First
builder.Append("pBlockData: " + this.pBlockData + "\n");
Doesn't do what you think it does, specifically if pBlockData is a byte array you will get something like this (output from scriptcs):
> byte[] data = new byte[11];
> StringBuilder sb = new StringBuilder();
> sb.Append("data = ")
{Capacity:16,MaxCapacity:2147483647,Length:7}
> sb.Append(data);
{Capacity:32,MaxCapacity:2147483647,Length:20}
> sb.ToString()
data = System.Byte[]
Second C# strings (.NET strings in general) are UTF-16, so it doesn't really know how to handle displaying bytes. It doesn't matter if it is bas64 encoded or ASCII or French pickles ;-) the runtime just treats it as binary. Also null termination is not required, the length of the string is kept as a property of the string object.
So you need to turn the byte array you have into a UTF-16 character array, or string before you output it. If the byte array contains valid ASCII you can look into the 'System.Text.ASCIIEncoding.ASCII.GetDecoder().Convert' method as one way to accomplish this.
I will receive an response in the form of JSON string.
We have an existing tool developed in C# which will take input in XML format.
Hence i am converting the JSON string obtained from server using Newtonsoft.JSON to XML string and passing to the tool.
Problem:
When converting JSON response to XML, I am getting an error
"Failed to process request. Reason: The ' ' character, hexadecimal
value 0x20, cannot be included in a name."
The above error indicates that the JSON Key contains a space [For Example: \"POI Items\":[{\"lat\":{\"value\":\"00\"}] which cannot be converted to XML element.
Is there any approach to identify spaces only JSON key's ["POI Items"] and remove the spaces in it?
Also suggest any alternative solution so that we needn't change the existing solution?
Regards,
Sudhir
You can use Json.Net and replace the names while loading the json..
JsonSerializer ser = new JsonSerializer();
var jObj = ser.Deserialize(new JReader(new StringReader(json))) as JObject;
var newJson = jObj.ToString(Newtonsoft.Json.Formatting.None);
.
public class JReader : Newtonsoft.Json.JsonTextReader
{
public JReader(TextReader r) : base(r)
{
}
public override bool Read()
{
bool b = base.Read();
if (base.CurrentState == State.Property && ((string)base.Value).Contains(' '))
{
base.SetToken(JsonToken.PropertyName,((string)base.Value).Replace(" ", "_"));
}
return b;
}
}
Input : {"POI Items":[{"lat":{"value":"00","ab cd":"de fg"}}]}
Output: {"POI_Items":[{"lat":{"value":"00","ab_cd":"de fg"}}]}
I recommend using some sort of Regex.Replace().
Search the input string for something like:
\"([a-zA-Z0-9]+) ([a-zA-Z0-9]+)\":
and then replace something like (mind the missing space):
\"(1)(2)\":
The 1st pair of parenthesis contain the first word in a variable name, the 2nd pair of parenthesis means the 2nd word. The : guarantees that this operation will be done in variable names only (not in string data). the JSON variable names are inside a pair of \"s.
Maybe it's not 100% correct but you can start searching by this.
For details check MSDN, and some Regex examples
http://msdn.microsoft.com/en-us/library/system.text.regularexpressions.regex.replace.aspx
I have a file in visual studio with the following contents:"{"Name":"Pete"}"
If I read the file with the following code it appears to create a string with the original value:
byte[] byteArray = System.IO.File.ReadAllBytes(filePath);
string jsonResponse = System.Text.Encoding.UTF8.GetString(byteArray);
However, the string is actually different to the version that exists if I use the following code:
string jsonResponse = "{\"Name\":\"Pete\"}";
Why? (The reason I think it is different is because when I pass each version to a json deserializer it behaves differently)
Thanks.
Given your final comment in the question, I suspect the problem is that you've got a byte-order mark at the start of the file. Try loading the file like this instead:
string jsonResponse = File.ReadAllText(filePath);
I believe that will strip the BOM for you. Alternatively, you could try explicitly trimming it yourself:
jsonResponse = jsonResponse.TrimStart('\feff');
My guess would be that you have a terminating newline in your file.
You can easily verify if two strings have the same content in C# by just comparing them with a == b.
Here's a short code sample that might help you identify the problem. The strings are output surrounded by < >, which should help you identify surrounding whitespace (which, by the way, can be removed using String.Trim).
byte[] byteArray = System.IO.File.ReadAllBytes(filePath);
string fromFile = System.Text.Encoding.UTF8.GetString(byteArray);
string fromString = "{\"Name\":\"Pete\"}";
if (fromFile == fromString) {
Console.WriteLine("Strings are the same.");
} else {
Console.WriteLine("Strings are different!");
Console.WriteLine("fromFile: <" + fromFile + ">");
Console.WriteLine("fromString: <" + fromString + ">");
}
Part of my application accepts arbitrary text and posts it as an Update to Twitter. Everything works fine, until it comes to posting foreign ( non ASCII/UTF7/8 ) character sets, then things no longer work.
For example, if someone posts:
に投稿できる
It ( within my code in Visual Studio debugger ) becomes:
=?ISO-2022-JP?B?GyRCJEtFajlGJEckLSRrGyhC?=
Googling has told me that this represents ( minus ? as delimiters )
=?ISO-2022-JP is the text encoding
?B means it is base64 encoded
?GyRCJEtFajlGJEckLSRrGyhC? Is the encoded string
For the life of me, I can't figure out how to get this string posted as an update to Twitter in it's original Japanese characters. As it stands now, sending '=?ISO-2022-JP?B?GyRCJEtFajlGJEckLSRrGyhC?=' to Twitter will result in exactly that getting posted. Ive also tried breaking the string up into pieces as above, using System.Text.Encoding to convert to UTF8 from ISO-2022-JP and vice versa, base64 decoded and not. Additionally, ive played around with the URL Encoding of the status update like this:
string[] bits = tweetText.Split(new char[] { '?' });
if (bits.Length >= 4)
{
textEncoding = System.Text.Encoding.GetEncoding(bits[1]);
xml = oAuth.oAuthWebRequest(TwitterLibrary.oAuthTwitter.Method.POST, url, "status=" + System.Web.HttpUtility.UrlEncode(decodedText, textEncoding));
}
No matter what I do, the results never end up back to normal.
EDIT:
Got it in the end. For those following at home, it was pretty close to the answer listed below in the end. It was just Visual Studios debugger was steering me the wrong way and a bug in the Twitter Library I was using. End result was this:
decodedText = textEncoding.GetString(System.Convert.FromBase64String(bits[3]));
byte[] originalBytes = textEncoding.GetBytes(decodedText);
byte[] utfBytes = System.Text.Encoding.Convert(textEncoding, System.Text.Encoding.UTF8, originalBytes);
// now, back to string form
decodedText = System.Text.Encoding.UTF8.GetString(utfBytes);
Thanks all.
This produced the output you are looking for:
using System;
using System.Text;
class Program {
static void Main(string[] args) {
string input = "に投稿できる";
Console.WriteLine(EncodeTwit(input));
Console.ReadLine();
}
public static string EncodeTwit(string txt) {
var enc = Encoding.GetEncoding("iso-2022-jp");
byte[] bytes = enc.GetBytes(txt);
char[] chars = new char[(bytes.Length * 3 + 1) / 2];
int len = Convert.ToBase64CharArray(bytes, 0, bytes.Length, chars, 0);
return "=?ISO-2022-JP?B?" + new string(chars, 0, len) + "?=";
}
}
Standards are great, there are so many to choose from. ISO never disappoints, there are no less than 3 ISO-2022-JP encodings. If you have trouble then also try encodings 50221 and 50222.
Your understanding of how the text is encoded seems correct. In python
'GyRCJEtFajlGJEckLSRrGyhC'.decode('base64').decode('ISO-2022-JP')
returns the correct unicode string. Note that you need to decode base64 first in order to get the ISO-2022-JP-encoded text.