{"id":61,"date":"2014-04-06T06:30:08","date_gmt":"2014-04-06T06:30:08","guid":{"rendered":"http:\/\/blog.catalystlogic.com.au\/?p=61"},"modified":"2026-03-01T01:44:18","modified_gmt":"2026-02-28T14:44:18","slug":"console-rest-messages-with-restsharp-netcli-costura-fody","status":"publish","type":"post","link":"http:\/\/54.253.247.134\/?p=61","title":{"rendered":"Console REST messages with Restsharp, .NetCLI &#038; Costura.Fody"},"content":{"rendered":"<p>After Integrating <a href=\"http:\/\/www.visualsvn.com\/\u200e\">Visual SVN<\/a> &amp; <a href=\"https:\/\/www.atlassian.com\/software\/jira\u200e\">Jira <\/a>with <a href=\"https:\/\/slack.com\/\u200e\">Slack<\/a>, I decided to replace the existing bat file calling a python script with something a bit more extensible.<\/p>\n<p>I also wanted to change Slack's <a href=\"https:\/\/slack.com\/integrations\">SVN integration<\/a> to a custom one that would point to the revision on our Fisheye server, which would show the changes made and link to Jira when we added the \u00a0ticket &lt;ProjectName-Ticket#&gt; in the Commit Notes, which Fisheye does out of the box<\/p>\n<p><span style=\"font-size: 1.285714286rem; font-weight: bold; line-height: 1.6;\">.Net REST Console App<\/span><\/p>\n<p>I decided to build a console app that call the slack incoming webhooks API. It needed to:<\/p>\n<ul>\n<li>Accept a channel name, title &amp;\u00a0API Token<\/li>\n<li>Accept a SVN Projectname &amp; revision number to call SVNlook &amp; get author &amp; log details. (When fired by SVN Server)<\/li>\n<li>Accept a Jenkins name to hit up the Jenkins JSON API for build details<\/li>\n<li>Parse success\/fail messages and convert them to the Slack notification color names (good, warning &amp; danger)<\/li>\n<li>Create a JSON Object<\/li>\n<li>Post the JSON object to the slack API<\/li>\n<li>A verbose option for debugging<\/li>\n<li>Manually enter message text, and author to integrate with other apps down the line.<\/li>\n<\/ul>\n<p>.Net Apache Common CLI<\/p>\n<p>As there is quite a large set of parameters, I made use of the .<a href=\"http:\/\/sourceforge.net\/projects\/dotnetcli\/\">Net port<\/a> of the <a href=\"http:\/\/commons.apache.org\/proper\/commons-cli\/\">Apache Commons CLI libraries<\/a>\u00a0by Akutz. This handles all aspects of console arguments, while adhering to best practices and existing expectation when passing argument to a cone application.<\/p>\n<p>An example of the init &amp; usage syntax is below.<\/p>\n<pre class=\"lang:c# decode:true\">options.AddOption(\"a\", \"apiToken\", true, \"API token.\");\n...\nget\n{\n  if (_apiToken == null &amp;&amp; Globals.CMD.HasOption('a'))\n  {\n     _apiToken = CMD.GetOptionValue('a');\n  }\n  return _apiToken;\n}<\/pre>\n<p>This is a huge help in argument management, and also handled the help messages.<\/p>\n<p>There was very little documention on .Net CLI, though using the <a href=\"http:\/\/commons.apache.org\/proper\/commons-cli\/usage.html\">Apache usage documentation<\/a> was fine, just remeber to capitalise the method name i nthe .ent vesrion, for example <em>option.AddOption<\/em> instead \u00a0of <em>option.addOption<\/em>, <em>option.HasOption<\/em> instead of <em>option.hasOption<\/em> and so on.<\/p>\n<p>And one last catch, the Apache <em>DefaultParser <\/em>was called the <em>BasicParser <\/em>in the .Net port.<\/p>\n<pre class=\"lang:c# decode:true\">BasicParser parser = new BasicParser();\nCommandLine commandLine = parser.Parse(options, args);<\/pre>\n<h3>RestSharp<\/h3>\n<p><a href=\"http:\/\/restsharp.org\/\">Restsharp <\/a>likely needs no instruction has a library for simple Rest messaging.<\/p>\n<p>I found it very easy to use, apart from one hitch that had me stumped for much longer than I would like to admit.<\/p>\n<p>The following code (I thought) added the query string with the API token for slacker to the url.<\/p>\n<pre class=\"lang:c# decode:true\"> var request = new RestRequest(resource, Method.POST);\nrequest.AddParameter(\"token\", \"CfkRAp1041vYQVb\");<\/pre>\n<p>However, doing so, and then trying to add any details to body via <em>request.AddBody<\/em> resulted in it not being added, nor raising an error attempting to do so.<\/p>\n<pre class=\"lang:c# decode:true\">request.RequestFormat = DataFormat.Json;\nrequest.AddBody(json); \/\/Ignored if AddParameter was previously called<\/pre>\n<p>Opening up <a href=\"http:\/\/www.wireshark.org\/\">Wireshark<\/a> showed that the query string was being added to the body.<\/p>\n<p>After a bit of head scratching I found that AddParameter took a third argument,<\/p>\n<pre class=\"lang:c# decode:true\">request.AddParameter(\"token\", \"CfkRAp1041vYQVb\", ParameterType.QueryString);<\/pre>\n<h3>SVN versioning<\/h3>\n<p>As I planned to use this exe on various production servers, automated SVN versioning was the next logical step.<\/p>\n<p>I utilised <a href=\"http:\/\/stackoverflow.com\/users\/900570\/avi-turner\">Avi Turner's<\/a>\u00a0SVN versioning script on <a href=\"http:\/\/stackoverflow.com\/questions\/17713513\/linking-tortoise-svn-revision-number-to-assembly-version\">stackoverflow <\/a>to update the\u00a0<em>$WCREV$<\/em> tag I inserted into the <em>AssemblyFileVersion<\/em> in <em>AssemblyInfo.cs<\/em> and <em>rev.subwcrev-template<\/em> used to track the currently checked out &amp; built version.<\/p>\n<h3><span style=\"line-height: 1.8; font-size: 1rem;\">\u00a0Costura.Fody<\/span><\/h3>\n<p>Finally, I though I would try my hand at weaving assemblies into the .exe for a single file deployment.<\/p>\n<p>I settled on <a href=\"https:\/\/github.com\/Fody\/Costura\">Costura.Fody<\/a> as many had said that it\u00a0Just Works&#x2122;<\/p>\n<p>After adding both Fody and Costura.Fody via the VS2013 package manager, I assumed the various build xml files automatically would need to be tweaked. Though, when I hit build, I realised that I didn't need to touch them at all, and ended up with a exe file where every assembly set to copy local, in this case RestSharp, was embedded into the exe.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>After Integrating Visual SVN &amp; Jira with Slack, I decided to replace the existing bat file calling a python script with something a bit more extensible. I also wanted to change Slack's SVN integration to a custom one that would point to the revision on our Fisheye server, which would show the changes made and <a class=\"read-more\" href=\"http:\/\/54.253.247.134\/?p=61\">...continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2,17,18],"tags":[],"class_list":["post-61","post","type-post","status-publish","format-standard","hentry","category-net","category-svn","category-visual-studio"],"jetpack_featured_media_url":"","_links":{"self":[{"href":"http:\/\/54.253.247.134\/index.php?rest_route=\/wp\/v2\/posts\/61","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/54.253.247.134\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/54.253.247.134\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/54.253.247.134\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/54.253.247.134\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=61"}],"version-history":[{"count":1,"href":"http:\/\/54.253.247.134\/index.php?rest_route=\/wp\/v2\/posts\/61\/revisions"}],"predecessor-version":[{"id":238,"href":"http:\/\/54.253.247.134\/index.php?rest_route=\/wp\/v2\/posts\/61\/revisions\/238"}],"wp:attachment":[{"href":"http:\/\/54.253.247.134\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=61"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/54.253.247.134\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=61"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/54.253.247.134\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=61"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}