16

I am trying to pass a json string to a C#-Program using Commandline.

The JSON-String looks like this:

{
    "config": {
        "script": {
            "script_name": "test",
            "dir": "D:\\test",
            "destination": "M:\\neu\\test",
            "params": "/b /s /r:3 /w:5"
        }
    }
}

In Commandline it looks like this:

{"config":{"script":{"script_name":"test","dir":"D:\\test","destination":"M:\\neu\\test","params":"/b /s /r:3 /w:5"}}}

But if I just pass the string then it gets chunked into several pieces. But I want my program to see it as just a single string.

Do I have to adapt my JSON-String?

codeforester
  • 39,467
  • 16
  • 112
  • 140
Snickbrack
  • 1,253
  • 4
  • 21
  • 56

6 Answers6

20

Declare it as a string with "" and escape the other " with \ and it should work.

Command line:

"{\"config\":{\"script\":{\"script_name\":\"test\",\"dir\":\"D:\\test\",\"destination\":\"M:\\neu\\test\",\"params\":\"/b /s /r:3 /w:5\"}}}"
Simon Karlsson
  • 4,090
  • 22
  • 39
  • I tried that the got.. 'index' is not recognized as an internal or external command! – JGFMK May 02 '19 at 09:16
  • 2
    `'{\"config\":{\"script\":{\"script_name\":\"test\",\"dir\":\"D:\\test\",\"destination\":\"M:\\neu\\test\",\"params\":\"/b /s /r:3 /w:5\"}}}'` single quote might work – Rescommunes Aug 19 '19 at 17:57
6

This should work:

var jsonString = Environment.CommandLine;

I tested it with the debugger like so:

        var jsonString = Environment.CommandLine;
        // (*) This correction makes it work, although it is pretty ugly:
        jsonString = jsonString.Split(new string[] { ".exe\" " }, StringSplitOptions.None)[1];
        var obj =   Newtonsoft.Json.JsonConvert.DeserializeObject<RootObject>(jsonString);

Debugging with VS2015, and not modifying the json input (not even removing the line changes). I am using the same structure as your input:

    public class Script
    {
        public string script_name { get; set; }
        public string dir { get; set; }
        public string destination { get; set; }
        public string @params { get; set; }
    }

    public class Config
    {
        public Script script { get; set; }
    }

    public class RootObject
    {
        public Config config { get; set; }
    }

About (*) => The problem with the deserialization is that the exe info is added in front of the command line with Environment.CommandLine and it "pollutes" the json like this: jsonString =

"path\to\assembly\name.vshost.exe" {
    "config": {
        "script": {
            "script_name": "test",
            "dir": "D:\\test",
            "destination": "M:\\neu\\test",
            "params": "/b /s /r:3 /w:5"
        }
    }
}

If anybody has a prettier fix to this problem please let me know.

Xavier Peña
  • 7,399
  • 9
  • 57
  • 99
  • 1
    You can remove all text before the opening "{" character, which is rarely used for the file name. Or you can be a bit smarter and get the full path from the executing assembly and remove the quoted version of that. – Berin Loritsch Mar 24 '16 at 15:27
4

Try to save the JSON object into a file, and pass the file as the argument to your application.

@Wildcard27 : This is an actual use case in order to create Windows Tasks which was used for the faculty degree app. The JSON was just a simple serialization of a DTO that I was using.

When you serialize the JSON, just save it into a blank file, giving it a proper name so that is unique.

    private string CreateTaskConfigurationFile(string taskName, EquipmentEventExtended eventData, string host)
        {
            List<Change> changes = new List<Change>
            {
                new Change(MailConstants.EventName,eventData.EventName),
                new Change(MailConstants.Deadline, eventData.DateTo.Value.ToShortDateString()),
                new Change(MailConstants.EventDetails, eventData.EventDetails),
                new Change(MailConstants.Link,$"{host}/Inventory/Details/{eventData.InventoryId}")
            };

            MailTaskModel mtm = new MailTaskModel
            {
                Body = MailConstants.UpdateTemplate(MailConstants.TaskMailTemplate, changes),
                Subject = "[Reminder] Upcoming Event needs your attention",
                ToAddress = "abcdef@gmail.com",
                IsHtml = true
            };
            var fileName = string.Format(@"E:\{0}.json", taskName);
            using (StreamWriter file = File.CreateText(fileName))
            {
                JsonSerializer js = new JsonSerializer();
                js.Serialize(file, mtm);
            }
            return fileName;
        }

Then you provide the file path as an argument to the console application:

static void Main(string[] args)
        {
            var configFilePath = args[0];
            var mailConfig = LoadConfigurationFile(configFilePath);
            MailManager manager = new MailManager(mailConfig.ToAddress, mailConfig.FromAddress,mailConfig.Subject, mailConfig.Body,mailConfig.IsHtml);
            manager.SendMail();
        }
        private static MailTaskModel LoadConfigurationFile(string configurationFilePath)
        {
            MailTaskModel mailConfig;
            using(var sr = new StreamReader(configurationFilePath))
            {
                string json = sr.ReadToEnd();
                mailConfig = JsonConvert.DeserializeObject<MailTaskModel>(json);
            }
            return mailConfig;
        }

You can then use something like

ConsoleApplication.exe -yourFilePath

I've removed noisy check-ups for nulls and all that so that it's more clear.

Dan Mihalea
  • 164
  • 8
1

Instead of looking at the "string[] args" you could use Environment.CommandLine.

From MSDN https://msdn.microsoft.com/en-us/library/system.environment.commandline.aspx

public static void Main() 
{
   Console.WriteLine();
   //  Invoke this sample with an arbitrary set of command line arguments.
   Console.WriteLine("CommandLine: {0}", Environment.CommandLine);
}

// The example displays output like the following: // C:>env0 ARBITRARY TEXT //
// CommandLine: env0 ARBITRARY TEXT

AndyPook
  • 2,762
  • 20
  • 23
  • this gives me following: `\"CURRENT_EXECUTIVE\" {\"config\":{\"script\":{\"script_name\":\"test\",\"dir\":\"D:\\\\test\",\"destination\":\"M:\\\\neu\\\\test\",\"params\":\"/b /s /r:3 /w:5\"}}}"` so how can I extract my JSON-String? – Snickbrack Mar 24 '16 at 15:22
  • Yes, it will include the actual exe path. Try discarding just past the second quote. Something like `json = cmdline.substring(cmdline.IndexOf("\"", 2))`. Not sure if all the \" is just an artifact of Visualstudio. But `cmdline.Replace("\\\"", "\"")` ought to fix that up. – AndyPook Mar 24 '16 at 15:24
0

Just send json value to commandline after catch value and replace it. It's work for me.

args[1].Replace("{","{\"").Replace(":","\":\"").Replace(",","\",\"").Replace("}","\"}");
  • I think you are onto something. But if you have a JSON list involving square brackets immediately after a colon, then the Replace needs tweaking. – JGFMK May 02 '19 at 09:27
-1

Following on from @Selcuk Gurals post, here is a more complete answer:

args[1].Replace("{", "{\"").Replace(":", "\":\"").Replace(",", "\",\"").Replace("}", "\"}").Replace(":\"[", ":[").Replace(":\"{", ":{").Replace("https\":\"", "https:").Replace("http\":\"", "http:").Replace("\":\"9", ":9").Replace("}\",", "},").Replace("]\",", "],").Replace("}\"}", "}}");

This caters for things like embedded http/https and ports. My port number was in the 9000 region... So a regex solution would be better. But it improves on the former answer The value part of a JSON key/value pair can also be:

  1. another JSON object
  2. a list

"key": {}, ....
"key":[], ....
JGFMK
  • 8,425
  • 4
  • 58
  • 92