5

I'm serialize an object to json string and passing that to an app through command line but when I receive the arguments in the app, this is no longer a json string but a regular string .

I'm using below code to create json string

var jsonStr = new JavaScriptSerializer().Serialize(obj);

string that I'm passing - "{"name":"abc","place":"xyz"}"
string that I receive - "{name:abc,place:xyz}";

How can I maintain the structure of the json string ?

Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236
Kapil
  • 9,469
  • 10
  • 40
  • 53
  • 1
    There's no such thing as a json string. There are only strings. Where is the *relevant* code. ie the command line and how do you parse it? Did you escape the quotes before creating the command line? What is the raw value of the command line argument? BTW JavascriptSerializer is a legacy class that isn't used anymore, even ASP.NET uses Json.NET – Panagiotis Kanavos Mar 09 '15 at 10:44
  • 1
    from json string , i mean string with a json structure , you get when you serialize a object to json. – Kapil Mar 09 '15 at 10:47
  • Again, there's no difference or need for special handling. If you have issues, it's because the plain-old string you passed wasn't the one you thought you passed - you forgot to encode the quotes or there were no quotes to begin with. What is the command line you used and what are the value of the `args` items? – Panagiotis Kanavos Mar 09 '15 at 10:55
  • possible duplicate of [quotes around quotes in windows command line](http://stackoverflow.com/questions/17205292/quotes-around-quotes-in-windows-command-line) – Panagiotis Kanavos Mar 09 '15 at 11:22
  • If you want to pass a json string from one command-line program to another, you can pipe the first program's output to the second eg `first.exe|second.exe` and change the second program to read from the console with `Console.ReadToEnd()`. You won't have to escape or encode the string *and* the script will be cleaner – Panagiotis Kanavos Mar 11 '15 at 09:07

3 Answers3

20

I guess double quots are wiped out because they've meaning inside the CLI world.

I would say that converting the whole JSON into a base 64 string, and then, in the CLI internally turn into regular string again should work:

var jsonStr = Convert.ToBase64String(Encoding.UTF8.GetBytes(new JavaScriptSerializer().Serialize(obj)));

// When your receive the whole string....
var jsonStr = Encoding.UTF8.GetString(Convert.FromBase64String(inputStr));

// Now deserialize your JSON string into a regular .NET object...

Answering to some comment from @Panagiotis Kanavos...

The CLI doesn't corrupt any string - people would have noticed by now. If the OP sends a different string, the problem is in that code, not the CLI

As I pointed out in comments as answers to your ones, I know that inside .NET world we don't need to escape a JSON and maybe in other environments there's also no need to do this.

I suggested base 64 approach because it's a bullet-proof solution, and as OP provided few details and insufficient code samples, at the end of the day, I believe it's the base 64 approach is as valid as just escaping double quots, but it also provides an added value: it escapes any special character in addition to ".

BTW, there're actual cases where a CLI prevents some characters. redis-cli on Windows doesn't allow curly brackets...

Update 2

Since @Panagiotis Kanavos has confused CLI with Common Language Interface, I want to be sure that everyone that reads my answer understand CLI as Command Line Interface.

Matías Fidemraizer
  • 63,804
  • 18
  • 124
  • 206
  • There are no issues with double quotes in .NET. When writing string literals one has to escape them but that's not the case here. JSon is used in .NET extensively, especially in ASP.NET MVC without resorting to Base64 – Panagiotis Kanavos Mar 09 '15 at 10:59
  • @PanagiotisKanavos With all respects, I know that, but as OP didn't provide actual code about the CLI or how it actually works in his/her environment, I need to provide a bullet-proof solution. – Matías Fidemraizer Mar 09 '15 at 11:02
  • This code will return the original string. How does it help with the question? – Panagiotis Kanavos Mar 09 '15 at 11:04
  • @PanagiotisKanavos Hey, use your mind (like Bruce Lee!). It helps in terms of receiving the string "as is" in the CLI! The issue is that OP doesn't receive the correct JSON once it gets it in the target environment (the CLI) – Matías Fidemraizer Mar 09 '15 at 11:06
  • @PanagiotisKanavos Obviously, the so-called string is corrupted by the CLI. I doubt a CLI would corrupt a base 64 string, because it contains numbers and letters, and `=` symbols... – Matías Fidemraizer Mar 09 '15 at 11:08
  • The CLI doesn't corrupt any string - people would have noticed by now. If the OP sends a different string, the problem is in that code, not the CLI – Panagiotis Kanavos Mar 09 '15 at 11:10
  • @PanagiotisKanavos I understand you downvoted the answer, but at the end of the day, you don't know what's the CLI. If it's not .NET? – Matías Fidemraizer Mar 09 '15 at 11:16
  • @PanagiotisKanavos Also, if it's not CMD? We don't know what's behind the OP issue. I suggested the base64 approach because you also escape special characters, accutes, whatever. – Matías Fidemraizer Mar 09 '15 at 11:18
  • The OP has already mentioned the command line. By using Base64 you negate the very advantage of using command-line parameters - ease of scripting and command chaining. – Panagiotis Kanavos Mar 09 '15 at 11:25
  • @PanagiotisKanavos You're trying to find arguments to refute my answer, that's all. What has to do a json or base64 string with ease of scripting and command chaining? It's still a string, either a json or base64 string.................... In my humble opinion, you're right at adding a new answer if you find you can provide more value!! SO is full of alternative approaches to the same issue! – Matías Fidemraizer Mar 09 '15 at 11:28
  • Excellent solution. This works perfectly. Without doing it this way, trying to send valid json as a command line argument, that was created from serializing an .net object, always stripped out the double quotes in the command line. The command line looked like this in the app I was running: MyApp.exe {OrderId:10321,OrderDetailIds:[99997,99998,99999]}. With this argument, I could not deserialize the json back into an object in the console app. – Brent Oct 26 '22 at 17:15
7

Just escape quotes with backslashes so CMD will not remove quotes inside a JSON.

String which should be passed:

"{\"name\":\"abc\",\"place\":\"xyz\"}"

String which will be received:

{"name":"abc","place":"xyz"}

Use this code to escape the string:

string jsonString = new JavaScriptSerializer().Serialize(obj);
string escapedString = jsonString.Replace("\"", "\\\"");
Josh Crozier
  • 233,099
  • 56
  • 391
  • 304
Yoh Deadfall
  • 2,711
  • 7
  • 28
  • 32
  • 1
    It's not the CLI that causes issues, it's CMD (the command line). CMD *also* uses the backslash though so this would work – Panagiotis Kanavos Mar 09 '15 at 11:15
  • Agree. Fixed the answer. – Yoh Deadfall Mar 09 '15 at 11:19
  • 1
    @YohDeadfall Because of some Panagiotis comment... I've discovered he refers to CLI as "common language interface", and I believe that both you and me were talking about "Command Line Interface" if we refer about "CLI" on this Q&A lol – Matías Fidemraizer Mar 09 '15 at 11:33
  • Yes, CLI means Command Line Interface in this question. But I replaced it with CMD to be more clear :) – Yoh Deadfall Mar 09 '15 at 11:37
  • I can't understand this at all, because I would be talking about CLI as Common Language Infrastructure if I were talking about how to implement a new .NET language or something like this...!!!!!!!!! – Matías Fidemraizer Mar 09 '15 at 11:43
0

First, JavaScriptSerializer.Serialize doesn't return the string you posted, it returns a properly quoted string:

class Item
{
    public string name { get; set; }
    public string place { get; set; }
}
....
var t = new Item {name = "abc", place = "xyz"};
var s = JsonConvert.SerializeObject(t);
Debug.Assert(s == "{\"name\":\"abc\",\"place\":\"xyz\"}");

This is really a question about CMD and how it uses quotes.

The problem is that the command line uses " as a delimiter so you have to escape quotes in your strings, just as you would do with .NET.

Luckily, the backslash is the escape character in CMD as well, so myprog.exe "{\"name\":\"abc\",\"place\":\"xyz\"}" will preserve the quotes, and the following will work

var newItem = new JavaScriptSerializer().Deserialize<Item>(args[0]);

A quick and dirty way to escape quotes is to replace them with \":

var encoded=s.Replace("\"", "\\\"");

Notice the multiple backslashes - both the backslash and the quote need to be escaped.

UPDATE

It's possible to avoid escaping entirely and obfuscating the json string either by using piping or by saving the json string to a separate file. In both cases, it's important for humans to be able to edit the script without having to encode/decode the commands and data. Eg. an administrator should be able to make quick corrections or inspect the parameters without having to encode/decode a simple json string.

Using a json string in a command line makes sense when using scripts, in two scenarios:

  1. The first program creates a Json output that must be processed by the second program
  2. The first program generates a batch file calling the second program, passing a json parameter.

In the first scenario, the first program's output can be piped to the second program's input if the fist program simply writes to the console and the second program reads from the console, instead of inspecting its parameters. No escaping is needed in this case because the string is passed as-is from the first program to the second.

This has the additional advantage that the json string can be written to an intermediate file eg. for inspection or to allow running the second program at a later time.

In the second scenario the first program creates the file and either uses piping to pass it to the second program, or passes the file's path as a parameter.

The only change needed by the second program to allow piping is to use Console.ReadToEnd() to read from the console instead of the args array.

For example, the first program should end with:

var s = JsonConvert.SerializeObject(t);
Console.WriteLine(s);

and the second program should read the input from the console:

var json=Console.ReadToEnd();
var newItem= new JavaScriptSerializer().Deserialize<Item>(t);

This will allow you to create a script as simple as:

first.exe | second.exe

Or

myJson.json > second.exe
Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236
  • See my accepted answer. First paragraph says "I guess double quots are wiped out because they've meaning inside the CLI world.", which is, at the end of the day, the same as you said in your answer "The problem is that the command line uses " as a delimiter [...]". Your answer provides value in giving an alternate solution... – Matías Fidemraizer Mar 09 '15 at 11:26
  • In .NET CLI is the Common Language Infrastructure – Panagiotis Kanavos Mar 09 '15 at 11:29