public void List(ContentstackClient client)
            {
                foreach (Newtonsoft.Json.Linq.JObject contentType in
                         client.GetContentTypes(new Dictionary <string, object>()).Result)
                {
                    string contentTypeUid = contentType.GetValue("uid").ToString();
                    Message(contentTypeUid);

                    client.ContentType(contentTypeUid).Query().Find <Entry>().ContinueWith((t) =>
                    {
                        foreach (Entry entry in t.Result.Items)
                        {
                            string line = entry.Uid;

                            if (entry.Object.ContainsKey("url") &&
                                entry.Object["url"] != null &&
                                !String.IsNullOrEmpty(entry.Object["url"].ToString()))
                            {
                                line += " (" + entry.Object["url"] + ")";
                            }

                            line += " : " + entry.Title;
                            Message(line);
                        }

                        Line();
                    }).GetAwaiter().GetResult();
                }
            }
        private async Task <int> getGlobalFields(ContentstackClient client, int skip)
        {
            ContentstackResponse contentstackResponse = await client.GetGlobalFields(skip : skip);

            _contentTypes.AddRange(contentstackResponse.listContentTypes);
            return(contentstackResponse.Count);
        }
Exemplo n.º 3
0
        public static ContentstackClient GetStack()
        {
            StackConfig config = new StackConfig();

            if (config.assemblyConfiguration.HasFile && string.Compare(config.assemblyConfiguration.FilePath, config.currentConfiguration.FilePath, true) != 0)
            {
                config.assemblyConfiguration.SaveAs(config.currentConfiguration.FilePath);
                ConfigurationManager.RefreshSection("appSettings");
                ConfigurationManager.RefreshSection("connectionStrings");
            }
            string apiKey      = ConfigurationManager.AppSettings["api_key"];
            string accessToken = ConfigurationManager.AppSettings["access_token"];
            string environment = ConfigurationManager.AppSettings["environment"];
            string host        = ConfigurationManager.AppSettings["host"];

            Configuration.ContentstackOptions contentstackOptions = new Configuration.ContentstackOptions
            {
                ApiKey      = apiKey,
                AccessToken = accessToken,
                Environment = environment,
                Host        = host
            };

            ContentstackClient contentstackClient = new ContentstackClient(new OptionsWrapper <Configuration.ContentstackOptions>(contentstackOptions));

            return(contentstackClient);
        }
        public void Go(ContentstackClient stack, OutputWriter writer)
        {
            // https://www.contentstack.com/docs/developers/apis/content-delivery-api/#initial-sync
            // https://www.contentstack.com/docs/platforms/dot-net/api-reference/api/Contentstack.Core.Models.SyncStack.html
            SyncStack syncStack = stack.SyncRecursive(
                null,           /*Locale*/
                SyncType.All,
                null,           /* ContentTypeUID */
                DateTime.MinValue).Result;

            //WARN: in case of multiple events for an Entry, threads running out of event date sequence could load stale data
            foreach (JObject entryEvent in syncStack.items)
            {
                //WARN: https://stackoverflow.com/questions/271440/captured-variable-in-a-loop-in-c-sharp
                JObject myEntryEvent = entryEvent;
                ProcessMessage(stack, myEntryEvent, writer);
            }

            string syncToken = syncStack.sync_token;

            // https://www.contentstack.com/docs/developers/apis/content-delivery-api/#subsequent-sync
            SyncStack updatesSinceSync = stack.SyncToken(syncToken).Result;

            writer.Message(this, updatesSinceSync.items.Count() + " update(s) since last sync");

            foreach (JObject entryEvent in updatesSinceSync.items)
            {
                //WARN: https://stackoverflow.com/questions/271440/captured-variable-in-a-loop-in-c-sharp
                JObject myEntryEvent = entryEvent;
                ProcessMessage(stack, myEntryEvent, writer);
            }
        }
 public HomeController(
     ContentstackClient client,
     ICompositeViewEngine engine,
     ILogger <HomeController> logger)
 {
     _client     = client;
     _viewEngine = engine;
     _logger     = logger;
 }
Exemplo n.º 6
0
        public void Go(
            ContentstackClient stack,
            string assetUid,
            OutputWriter writer)
        {
            Asset asset = stack.Asset(assetUid).Fetch().Result;

            writer.Message(this, asset.Url + " : " + asset.FileSize);
        }
Exemplo n.º 7
0
        public static void Initialize(Contentstack.Core.Models.Entry entry, ContentstackClient client, string contentType)
        {
            if (entry.Metadata == null || !entry.Metadata.ContainsKey(REPOSITORY_KEY))
            {
                entry.Metadata = new Dictionary <string, object>();
            }

            entry.Metadata[REPOSITORY_KEY]   = contentType;
            entry.Metadata[CONTENT_TYPE_KEY] = contentType;
        }
Exemplo n.º 8
0
        public async Task FetchEntry()
        {
            ContentstackClient contentstackClient = new ContentstackClient("blt520df8d675f11a0a", "bltcc8f202fa758bdf2", "development");
            Entry csEntry = contentstackClient.ContentType("test").Entry("blt9f9e183545e2fe5b");

            csEntry.SetLanguage(Internals.Language.GERMEN_SWITZERLAND);
            Entry entry = await csEntry.Fetch();

            Console.WriteLine(entry.ToString());
            Assert.True(true, "result is greater than 11");
        }
Exemplo n.º 9
0
        public ContentStackController()
        {
            ContentstackOptions options = new ContentstackOptions()
            {
                ApiKey      = _ApiKey,
                AccessToken = _AccessToken,
                Environment = _Environment,
            };

            _ContentStackClient = new ContentstackClient(options);
        }
 public void Go(
     ContentstackClient stack,
     OutputWriter writer)
 {
     // https://www.contentstack.com/docs/developers/apis/content-delivery-api/#get-all-content-types
     foreach (JObject contentTypeJson in stack.GetContentTypes().GetAwaiter().GetResult())
     {
         ContentType contentType = stack.ContentType(contentTypeJson["uid"].ToString());
         new Thread(() => { ProcessContentType(contentType, writer); }).Start();
     }
 }
Exemplo n.º 11
0
        //    private int ContentstackQueryResultLimit { get; } = 100;

        public void Go(ContentstackClient stack, OutputWriter writer)
        {
            // https://www.contentstack.com/docs/developers/apis/content-delivery-api/#get-all-content-types
            foreach (JObject contentTypeJson in stack.GetContentTypes().GetAwaiter().GetResult())
            {
                string contentTypeUid = contentTypeJson["uid"].ToString();

                if (contentTypeJson.SelectToken("$..[?(@.uid=='url')]") == null)
                {
                    writer.Message(this, contentTypeUid + " does not define URL field; skip.");
                    continue;
                }

                new Thread(() => { ProcessContentType(stack, contentTypeUid, writer); }).Start();
            }
        }
Exemplo n.º 12
0
        static void Main(string[] args)
        {
https:      //www.contentstack.com/docs/platforms/dot-net/api-reference/api/Contentstack.Core.ContentstackClient.html
            ContentstackClient stack = new ContentstackClient(
                APIKEY,
                DELIVERY_TOKEN,
                ENVIRONMENT);
            OutputWriter writer = new OutputWriter();

            new KnownEntry().Go(stack, CONTENT_TYPE_UID, ENTRY_UID, writer);
            new KnownUrl().Go(stack, ENTRY_URL, writer);
            new FieldSubsetQueryExample().Go(stack, writer);
            new GraphQlLister().Go(stack, writer);
            new SyncEventLister().Go(stack, writer);
            new EntryModelExample().Go(stack, CONTENT_TYPE_UID, ENTRY_UID, writer);
            new AssetExample().Go(stack, ASSET_ID, writer);
        }
Exemplo n.º 13
0
        private void ProcessMessage(ContentstackClient stack, JObject entryEvent, OutputWriter writer)
        {
            string   contentTypeUid = entryEvent["content_type_uid"].ToString();
            string   eventType      = entryEvent["type"].ToString();
            DateTime eventDate      = TimeZoneInfo.ConvertTimeFromUtc(
                DateTime.Parse(entryEvent["event_at"].ToString()), TimeZoneInfo.Local);
            string entryUid = null;

            if (entryEvent["data"].SelectToken("uid") != null)
            {
                entryUid = entryEvent["data"]["uid"].ToString();
            }

            switch (eventType)
            {
            case "entry_published":
                // optional (retrieve metadata for media assets)
                foreach (JValue toReplace in entryEvent.SelectTokens("$..asset"))
                {
                    string assetId = toReplace.ToString();

                    // https://www.contentstack.com/docs/developers/apis/content-delivery-api/#get-a-single-asset
                    Asset   asset    = stack.Asset(assetId).Fetch().GetAwaiter().GetResult();
                    JObject withJson = new JObject();
                    withJson["url"]      = asset.Url;
                    withJson["filename"] = asset.FileName;
                    toReplace.Replace(withJson);
                }

                Entry entry = entryEvent["data"].ToObject <Entry>(JsonSerializer.Create(stack.SerializerSettings));
                writer.Message(this, $"{entryUid} [{contentTypeUid}] : {entry.Title}");
                break;

            case "asset_published":
            case "asset_unpublished":
            case "asset_deleted":
            case "content_type_deleted":
            case "entry_unpublished":
            case "entry_deleted":
            default:
                writer.Message(this, $"{eventDate} : {eventType}");
                break;
            }
        }
Exemplo n.º 14
0
        public void Go(
            ContentstackClient stack,
            string contentTypeUid,
            string entryUid,
            OutputWriter writer)
        {
            //TODO: does this really invoke REST API?
            // https://www.contentstack.com/docs/developers/apis/content-delivery-api/#get-a-single-content-type
            // https://www.contentstack.com/docs/platforms/dot-net/api-reference/api/Contentstack.Core.Models.ContentType.html
            ContentType contentType = stack.ContentType(contentTypeUid);

            // https://www.contentstack.com/docs/developers/apis/content-delivery-api/#get-a-single-entry
            // https://www.contentstack.com/docs/platforms/dot-net/api-reference/api/Contentstack.Core.Models.Entry.html
            contentType.Entry(entryUid).Fetch <Entry>().ContinueWith((t) =>
            {
                Entry entry       = t.Result;
                string message    = $"Asynchronous: {entry.Uid} : {entry.Title}";
                JObject entryJson = entry.ToJson();

                if (entryJson.ContainsKey("url"))
                {
                    message += " (" + entryJson["url"] + ")";
                }

                writer.Message(this, message);
            });

            Entry entry = contentType.Entry(entryUid).Fetch <Entry>().GetAwaiter().GetResult();

            if (entry != null)
            {
                string  message   = $"Synchronous: {entry.Uid} : {entry.Title}";
                JObject entryJson = entry.ToJson();

                if (entryJson.ContainsKey("url"))
                {
                    message += " (" + entryJson["url"] + ")";
                }

                writer.Message(this, message);
            }
        }
Exemplo n.º 15
0
        private void ProcessContentType(ContentstackClient stack, string contentTypeUid, OutputWriter writer)
        {
            //TODO: paging results with threads?
            // https://www.contentstack.com/docs/developers/apis/graphql-content-delivery-api/explorer/?api_key=APIKEY&access_token=DELIVERY_TOKEN&environment=ENVIRONMENT
            string query = "{all_" + contentTypeUid + "{total items{url title system{uid}}}}";

            using (HttpClient http = new HttpClient())
            {
                string request = "https://graphql.contentstack.com/stacks/" +
                                 stack.GetApplicationKey() + "?access_token=" +
                                 stack.GetAccessToken() + "&environment=" +
                                 stack.GetEnvironment() + "contentdelivery&query=" + query;
                int attempt = 0;

                do
                {
                    try
                    {
                        JObject fromGraphQl = JObject.Parse(http.GetStringAsync(request).GetAwaiter().GetResult());
                        int     count       = Int32.Parse(fromGraphQl["data"]["all_" + contentTypeUid]["total"].ToString());

                        foreach (JToken group in fromGraphQl.SelectTokens("$.data.all_" + contentTypeUid + ".items"))
                        {
                            JToken myGroup = group;

                            foreach (var entry in myGroup.Children())
                            {
                                string entryUid = entry.SelectToken("system").SelectToken("uid").ToString();
                                writer.Message(this, $"{entryUid} [{contentTypeUid}] : {entry["title"]} ({entry["url"]})");
                            }
                        }

                        attempt = 3;
                    }
                    catch (Exception ex)
                    {
                        writer.Message(this, ex + " : " + ex.Message);
                    }
                }while (attempt++ < 3);
            }
        }
        public void Go(
            ContentstackClient stack,
            string contentTypeUid,
            string entryUid,
            OutputWriter writer)
        {
            //TODO: does this really invoke REST API?
            // https://www.contentstack.com/docs/developers/apis/content-delivery-api/#get-a-single-content-type
            // https://www.contentstack.com/docs/platforms/dot-net/api-reference/api/Contentstack.Core.Models.ContentType.html
            ContentType contentType = stack.ContentType(contentTypeUid);

            // https://www.contentstack.com/docs/developers/apis/content-delivery-api/#get-a-single-entry
            BasicEntry directEntry = contentType.Entry(entryUid).Fetch <BasicEntry>().GetAwaiter().GetResult();

            writer.Message(this, "Direct: " + directEntry.CreatedAt);
            Entry      entry          = contentType.Entry(entryUid).Fetch <Entry>().GetAwaiter().GetResult();
            JObject    entryJson      = entry.ToJson();
            BasicEntry convertedEntry = entryJson.ToObject <BasicEntry>(JsonSerializer.Create(stack.SerializerSettings));

            writer.Message(this, "Converted: " + directEntry.CreatedAt);
        }
        public async Task <int> OnExecute(CommandLineApplication app, IConsole console)
        {
            var options = new ContentstackOptions
            {
                ApiKey    = ApiKey,
                Authtoken = Authtoken,
                Host      = Host
            };
            var client = new ContentstackClient(options);

            try
            {
                Console.WriteLine($"Fetching Stack details for API Key {ApiKey}");
                stack = await client.GetStack();
            } catch (Exception e)
            {
                Console.WriteLine(e);
                Console.ForegroundColor = ConsoleColor.Red;
                Console.Error.WriteLine("There was an error communicating with the Contentstack API: " + e.Message);
                Console.Error.WriteLine("Please verify that your api key and authtoken are correct");
                return(Program.ERROR);
            }

            var path = "";

            if (string.IsNullOrEmpty(Path))
            {
                path = Directory.GetCurrentDirectory();
                Console.WriteLine($"No path specified, creating files in current working directory {path}");
            }
            else
            {
                Console.WriteLine($"Path specified. Files will be created at {Path}");
                path = Path;
            }
            path = $"{path}/Models";
            DirectoryInfo dir = CreateDirectory(path);

            try
            {
                Console.WriteLine($"Fetching Content Types from {stack.Name}");
                var totalCount = await getContentTypes(client, 0);

                var skip = 100;
                Console.WriteLine($"Found {totalCount} Content Types .");

                while (totalCount > skip)
                {
                    Console.WriteLine($"{skip} Content Types Fetched.");
                    totalCount = await getContentTypes(client, skip);

                    skip += 100;
                }
                Console.WriteLine($"Total {totalCount} Content Types fetched.");

                CreateEmbeddedObjectClass(Namespace, dir);

                Console.WriteLine($"Fetching Global Fields from {stack.Name}");
                totalCount = await getGlobalFields(client, 0);

                skip = 100;
                Console.WriteLine($"Found {totalCount} Global Fields.");

                while (totalCount > skip)
                {
                    Console.WriteLine($"{skip} Global Fields Fetched.");
                    totalCount = await getGlobalFields(client, skip);

                    skip += 100;
                }
                Console.WriteLine($"Total {totalCount} Global Fields fetched.");
            }
            catch (Exception e)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.Error.WriteLine("There was an error communicating with the Contentstack API: " + e.Message);
                Console.Error.WriteLine("Please verify that your api key and authtoken are correct");
                return(Program.ERROR);
            }
            Console.ResetColor();

            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine($"Generating files from content type");
            Console.ResetColor();

            Console.ForegroundColor = ConsoleColor.DarkYellow;
            CreateLinkClass(Namespace, dir);
            CreateHelperClass(Namespace, dir);
            CreateStringHelperClass(Namespace, dir);
            CreateDisplayAttributeClass(Namespace, dir);

            foreach (var contentType in _contentTypes)
            {
                CreateFile(FormatClassName(contentType.Title), Namespace, contentType, dir);
            }

            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine($"Files successfully created!");
            Console.ResetColor();
            Console.WriteLine($"Opening {dir.FullName}");
            OpenFolderatPath(dir.FullName);
            return(Program.OK);
        }
Exemplo n.º 18
0
        public void DoThing(ContentstackClient client, ContentstackRepository repository)
        {
            if (true)
            {
                McHammer();
            }

            ResourceEntry entry = repository.Get <ResourceEntry>("blt9bfc410b2e10a6f0");

            foreach (var thing in repository.GetChildren(entry.EntryUid, entry.ContentTypeUid))
            {
                Console.WriteLine("CHILD: " + thing);
            }



            Console.WriteLine(repository.GetChildIdentifiers(entry.EntryUid, entry.ContentTypeUid));

            foreach (Tuple <string, string> childIds in repository.GetChildIdentifiers(entry.EntryUid,
                                                                                       entry.ContentTypeUid))
            {
                EntryPointer child = repository.Get <EntryPointer>(childIds.Item1, childIds.Item2);
                Console.WriteLine("Child: " + child.Url);
            }

            foreach (var block in entry.Elements.Members)
            {
                switch (block.ElementType)
                {
                case ElementType.CodeBlock:
                    Console.WriteLine("CodeBlock: " + ((CodeBlockElement)block).Code);
                    break;

                case ElementType.CodeLink:
                    Console.WriteLine("CodeLink: " + ((CodeLinkElement)block).Url);
                    break;

                case ElementType.Download:
                    Console.WriteLine("Download: " + ((DownloadElement)block).Asset.Value.Url);
                    break;

                case ElementType.Image:
                    Console.WriteLine("Image: " + ((ImageElement)block).Asset.Value.Url);
                    break;

                case ElementType.Markdown:
                    Console.WriteLine("Markdown: " + ((MarkdownElement)block).Markdown.Markup);
                    break;

                case ElementType.RichText:
                    Console.WriteLine("RichText: " + ((MarkupElement)block).RichText.Value);
                    break;

                default:
                    Trace.Assert(false,
                                 String.Format("{0} {1} not recognized", block.ElementType.GetType(), block.ElementType));
                    break;
                }
            }

            foreach (ReferenceField <AuthorEntry> field in entry.PageData.Authors)
            {
                Console.WriteLine("Author: " + field.Get().Name);
            }
        }
Exemplo n.º 19
0
 internal Asset(ContentstackClient stack, string uid)
 {
     this.StackInstance = stack;
     this.Uid           = uid;
     this._StackHeaders = stack._LocalHeaders;
 }
Exemplo n.º 20
0
 internal Asset(ContentstackClient stack)
 {
     this.StackInstance = stack;
     this._StackHeaders = stack._LocalHeaders;
 }
Exemplo n.º 21
0
 internal void SetStackInstance(ContentstackClient stack)
 {
     this.StackInstance = stack;
     this._StackHeaders = stack._LocalHeaders;
 }
Exemplo n.º 22
0
 internal void SetStackInstance(ContentstackClient contentstackClient)
 {
     this.StackInstance = contentstackClient;
 }
Exemplo n.º 23
0
        static void Main(string[] args)
        {
            Message($"{typeof(Program)} : Main()", true);
            CommandLineApplication app = new CommandLineApplication();

            try
            {
                app.Description = ".NET Core console app to "; //TODO
                app.Name        = typeof(Program).Namespace;
                CommandOption help = app.HelpOption("-?|-h|--help");
                CommandOption dir  = app.Option("-d|--d<value>",
                                                "Path to directory containing appconfig.json",
                                                CommandOptionType.SingleValue);
                app.OnExecute(() =>
                {
                    if (help.HasValue())
                    {
                        ExitMessage(app, null, ExitCode.HelpRequested);
                    }

                    string directory = Directory.GetCurrentDirectory();

                    if (dir.HasValue())
                    {
                        directory = dir.Value();
                    }

                    if (!Directory.Exists(directory))
                    {
                        ExitMessage(app,
                                    $"{directory} does not exist or is not a subdirectory.",
                                    ExitCode.DirectoryDoesNotExist);
                    }

                    IConfiguration configuration = new ConfigurationBuilder().AddJsonFile(
                        $"{directory}\\appsettings.json",
                        optional: false,
                        reloadOnChange: true).Build();
                    Startup startup = new Startup();
                    ServiceCollection
                    serviceCollection = new ServiceCollection();                          // dependency injection configuration
                    startup.ConfigureServices(serviceCollection, configuration);          // configuration
                    IServiceProvider provider = serviceCollection.BuildServiceProvider(); // caution: may be disposable
                    ContentstackClient client = provider.GetService <ContentstackClient>();
//                    client.SerializerSettings.Converters.Add(); //TODO:
                    IRepository repository = provider.GetService <IRepository>();
                    Console.WriteLine(Environment.NewLine);
                    Message(typeof(ThingDoer) + ".DoThing()", true);
                    new ThingDoer().DoThing(client, repository as ContentstackRepository);
                    Message(typeof(ThingDoer) + ".DoThing() complete.");
                    Console.WriteLine(Environment.NewLine);
                });

                app.Execute(args);
            }
            catch (Exception ex)
            {
                new Instrument().Exception(ex, ex, "exception in Main()");
///                ExitMessage(app, $"{ex} : {ex.Message}", ExitCode.Exception, ex);
                ExitMessage(app, $"{ex} : {ex.Message}", ExitCode.Exception);
            }
        }
 public HomeController(ContentstackClient stack) => _stack = stack;
 public ProductController(ContentstackClient stack) => _stack = stack;
Exemplo n.º 26
0
 internal Asset(ContentstackClient stack)
 {
     this.Stack = stack;
 }
Exemplo n.º 27
0
 internal AssetLibrary(ContentstackClient stack)
 {
     this.Stack         = stack;
     this._StackHeaders = stack._LocalHeaders;
 }
        static void Main(string[] args)
        {
            Message($"{typeof(Program)} : Main()", true);
            CommandLineApplication app = new CommandLineApplication();

            try
            {
                app.Description = ".NET Core console app to validate a Contentstack stack.";
                app.Name        = typeof(Program).Namespace;
                CommandOption help = app.HelpOption("-?|-h|--help");
                CommandOption dir  = app.Option("-d|--d<value>",
                                                "Path to directory containing appconfig.json",
                                                CommandOptionType.SingleValue);
                app.OnExecute(() =>
                {
                    if (help.HasValue())
                    {
                        ExitMessage(app, null, false, true, ExitCode.HelpRequested);
                    }

                    string directory = Directory.GetCurrentDirectory();

                    if (dir.HasValue())
                    {
                        directory = dir.Value();
                    }

                    if (!Directory.Exists(directory))
                    {
                        ExitMessage(app,
                                    $"{directory} does not exist or is not a subdirectory.",
                                    true,
                                    true,
                                    ExitCode.DirectoryDoesNotExist);
                    }

                    IConfiguration configuration = new ConfigurationBuilder().AddJsonFile(
                        $"{directory}\\appsettings.json",
                        optional: false,
                        reloadOnChange: true).Build();
                    Startup startup = new Startup();
                    ServiceCollection serviceCollection = new ServiceCollection();        // dependency injection configuration
                    startup.ConfigureServices(serviceCollection, configuration);          // configuration
                    IServiceProvider provider = serviceCollection.BuildServiceProvider(); // caution: may be disposable
                    ContentstackClient client = provider.GetService <ContentstackClient>();
                    //                    client.SerializerSettings.Converters.Add(new MBFlexibleblocksFlexibleblocksConverter());
                    Console.WriteLine(Environment.NewLine);
                    Message(typeof(EntryLister) + ".List()", true);
                    new EntryLister().List(client);
                    Message(typeof(EntryLister) + ".List() complete.");
                    Console.WriteLine(Environment.NewLine);
                    // Message(typeof(SimpleEntryLister) + ".List()", true);
                    // new SimpleEntryLister(client).List();
                    // Message(typeof(SimpleEntryLister) + ".List() complete.");
                    Console.WriteLine(Environment.NewLine);
                    //                    Message(typeof(BlockLister) + ".List()", true);
                    //                    new BlockLister().List(
                    //                        client.ContentType("flexibleblockspage").Entry("blt36bfa917ffedd575").Fetch<Flexibleblockspage>().Result);
                    //                    Message(typeof(BlockLister) + ".List() complete.");
                });

                app.Execute(args);
            }
            catch (Exception ex)
            {
                ExitMessage(app, $"{ex} : {ex.Message}", false, true, ExitCode.Exception);
            }
        }