将JSON字符串作为命令行参数传递

17

我正在尝试通过命令行将一个JSON字符串传递给C#程序。

JSON字符串的格式如下:

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

在命令行中看起来是这样的:

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

但如果我只传递字符串,那么它会被分成几个部分。但我希望我的程序将其视为单个字符串。

我需要改变我的JSON字符串吗?


1
所有 JSON 中固有的引号都会混淆内置解析器。 - Ňɏssa Pøngjǣrdenlarp
@Plutonix 是的,它们会被踢出,然后JSON解析器不知道如何处理无效字符串。 - Snickbrack
环境解析参数,因此您必须适当转义:http://ss64.com/nt/syntax-esc.html - Berin Loritsch
6个回答

20

将其声明为字符串使用"",并用\转义其他",它就应该可以工作。

命令行:

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

我尝试了,但是出现了“index”未被识别为内部或外部命令的错误! - JGFMK
2
"{'config':{'script':{'script_name':'test','dir':'D:\test','destination':'M:\neu\test','params':'/b /s /r:3 /w:5'}}}" 可能单引号也可以使用。 - Rescommunes

6
这应该能够工作:
var jsonString = Environment.CommandLine;

我用调试器进行了测试,如下所示:

我用调试器进行了测试:

        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);

使用VS2015进行调试,不修改json输入(甚至不去掉换行符)。我使用和你的输入相同的结构:

    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; }
    }

关于 (*) => 反序列化的问题在于exe信息会在命令行前面添加 Environment.CommandLine,这会导致其"污染"json文件,如下所示: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"
        }
    }
}

如果有更好的解决方法,请告诉我。


1
你可以删除所有在开头的"{"字符之前的文本,这个字符很少用于文件名。或者你可以更聪明一些,从执行程序集中获取完整路径并删除其中带引号的版本。 - Berin Loritsch

4
尝试将 JSON 对象保存到文件中,并将该文件作为应用程序的参数传递。 @Wildcard27: 这是一个实际用例,用于创建 Windows 任务,该任务用于教职员工学位应用程序。JSON 只是我正在使用的 DTO 的简单序列化。 在对 JSON 进行序列化时,只需将其保存到空白文件中,并赋予其适当的名称,以使其唯一。
    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;
        }

然后将文件路径作为参数提供给控制台应用程序:

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;
        }

你可以使用类似于以下方式的工具:
ConsoleApplication.exe -yourFilePath

我已经移除了对空值的冗余检查,以便更加清晰。


请您能否提供一个例子? - Wildcard27

1

你可以使用Environment.CommandLine,而不是查看"string[] args"。

来自 MSDN https://msdn.microsoft.com/zh-cn/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);
}

// 该示例显示输出如下所示: // C:>env0 ARBITRARY TEXT //
// 命令行:env0 ARBITRARY TEXT


这给了我以下内容:\"CURRENT_EXECUTIVE\" {\"config\":{\"script\":{\"script_name\":\"test\",\"dir\":\"D:\\\\test\",\"destination\":\"M:\\\\neu\\\\test\",\"params\":\"/b /s /r:3 /w:5\"}}}",那么我该如何提取我的JSON字符串? - Snickbrack
是的,它将包括实际的exe路径。尝试仅在第二个引号之后丢弃。类似于 json = cmdline.substring(cmdline.IndexOf("\"", 2))。不确定所有的 "是否只是Visualstudio的产物。但是 cmdline.Replace("\\\"", "\"") 应该可以解决这个问题。 - AndyPook

0

在捕获值后,只需将json值发送到命令行并替换它即可。 这对我有用。

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

我认为你有点眉目了。但是,如果你的JSON列表在冒号后面紧跟着方括号,那么替换需要进行调整。 - JGFMK

-1

继@Selcuk Gurals的帖子之后,这里是一个更完整的答案:

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

这适用于嵌入式http/https和端口等内容。我的端口号在9000区域内...因此,正则表达式解决方案会更好。但它改进了以前的答案。

  1. 另一个JSON对象
  2. 列表

"key": {}, ....
"key":[], ....

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接