{"id":4156,"date":"2015-08-20T16:49:02","date_gmt":"2015-08-20T16:49:02","guid":{"rendered":"https:\/\/ushipblogsubd.wpengine.com\/?p=4156"},"modified":"2025-09-03T16:06:44","modified_gmt":"2025-09-03T16:06:44","slug":"net-web-applications-running-docker","status":"publish","type":"post","link":"https:\/\/ushipblogsubd.wpengine.com\/shipping-code\/net-web-applications-running-docker\/","title":{"rendered":".NET Web Applications Running in Docker"},"content":{"rendered":"<p>Here at uShip, we love to try interesting things during our hackathons. Recently, <a href=\"https:\/\/github.com\/Eibwen\" target=\"_blank\" rel=\"noopener\">Greg Walker<\/a> and I decided to try to get one of our front-end solutions up and running in a docker container. Since <a href=\"https:\/\/www.docker.com\/\" target=\"_blank\" rel=\"noopener\">docker<\/a> containers have to run on Linux, that meant getting the project running on <a href=\"http:\/\/www.mono-project.com\/\" target=\"_blank\" rel=\"noopener\">Mono<\/a> first.<\/p>\n<h2>Installing Mono<\/h2>\n<p>To start, we set up a Ubuntu 14.04 virtual machine. The first thing we did when we got the box setup is installed MonoDevelop, which installed all the Mono dependencies for us. I would recommend <a href=\"http:\/\/www.mono-project.com\/docs\/getting-started\/install\/linux\/#debian-ubuntu-and-derivatives\" target=\"_blank\" rel=\"noopener\">following the installation instructions<\/a> provided by the Mono Project. The latest version of Mono in Ubuntu\u2019s repositories at the time of this post (3.2.8) were out of date and caused additional problems. Use at least Mono version 4.0.2 and MonoDevelop version 5.9.5. Once you get the official Mono repositories setup. You can install MonoDevelop with the command <span style=\"font-family: monospace\">sudo apt-get update &amp;&amp; sudo apt-get install monodevelop<\/span>.<\/p>\n<h2>Building in MonoDevelop<\/h2>\n<p>The first step we took was to try to clone our repository in Linux and attempt to build it in MonoDevelop. Unfortunately, one of our test projects refused to load because the project type wasn\u2019t supported. We decided to ignore this error and unload that test project since we weren\u2019t planning on running any tests for this example.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone\" src=\"https:\/\/i.imgur.com\/06l3BWR.gif\" alt=\"\" width=\"647\" height=\"575\" \/><\/p>\n<p>&nbsp;<\/p>\n<p>We attempted to build our project in Mono, but we had a few assembly versioning issues. Luckily, these are only warnings that MonoDevelop treats as errors, thus we decided to turn those errors off and move onward.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone\" src=\"https:\/\/i.imgur.com\/p3xiY9L.gif\" alt=\"\" width=\"1186\" height=\"694\" \/><\/p>\n<p>&nbsp;<\/p>\n<p>Once we made these changes, our project was building successfully.<\/p>\n<h2>Running with Mono<\/h2>\n<p>Once we solved the issues with getting the solution building on Linux, it was just a matter of fixing our code to make everything work in the new environment.<\/p>\n<p>To start up a web server to host our MVC project, we used <a href=\"http:\/\/manpages.ubuntu.com\/manpages\/precise\/man1\/xsp.1.html\" target=\"_blank\" rel=\"noopener\">xsp4<\/a>. You can install this by running <span style=\"font-family: monospace\">sudo apt-get install mono-xsp4<\/span>. To get this up and running, we ran the command <span style=\"font-family: monospace\">xsp4<\/span> in our project\u2019s root directory which got a server up and running on port 8080.<\/p>\n<h3>Missing Assemblies<\/h3>\n<p>The first code-related issue we ran into was assemblies that live in the Global Assembly Cache (GAC) on Windows were not found on Linux. We fixed this by copying the DLLs over and placing them in the bin directory. Another solution to this problem is to add it to Mono\u2019s GAC. This can be done by running the following command <span style=\"font-family: monospace\">gacutil -i &lt;assembly&gt;<\/span>. If you are trying to add any delayed-signed assemblies to the GAC, add the <span style=\"font-family: monospace\">-bootstrap<\/span> option before specifying the assembly.<\/p>\n<p>We fixed several of these missing assembly errors until we started getting new exceptions that had our code in the stack traces. Once we saw our methods in the stack traces, this told us that Mono was able to begin executing our code!<\/p>\n<h3>Loading our Configuration<\/h3>\n<p>The next major issue was in the way we locate our external configuration files.<\/p>\n<p>In our code, when we look for our configuration files, we start by calling <span style=\"font-family: monospace\">Server.MapPath(&#8220;\/&#8221;)<\/span> in order to get the root directory. Unfortunately, this doesn\u2019t quite work in Mono, and instead we needed to change it to <span style=\"font-family: monospace\">Server.MapPath(&#8220;~&#8221;)<\/span>. This works in both Mono and in .NET, so this is likely the correct way to do it, anyway.<\/p>\n<p>For Linux file systems, letter case matters! We had several places in our code where we looked for files without the proper casing. Solving this was simple, but tracking it down took quite a bit of time stepping through code and very thoroughly analyzing every filename in our code to make sure it matched what was on disk.<\/p>\n<h2>Differences in Mono<\/h2>\n<p>Now that configuration files were loading, we could actually use our site. We ran into one problem that was due to differences between Mono and Microsoft\u2019s .NET Runtime.<\/p>\n<h3>CultureInfo Implementations<\/h3>\n<p>Deep in our localization code, we do a check to see if a culture is the <a href=\"http:\/\/stackoverflow.com\/a\/2423405\/46429\" target=\"_blank\" rel=\"noopener\">InvariantCulture<\/a>. To do this, we were comparing the culture\u2019s <span style=\"font-family: monospace\">ThreeLetterISOLanguageName<\/span> to a constant string <span style=\"font-family: monospace\">&#8220;ivl&#8221;<\/span>.<\/p>\n<p>[cc lang=&#8221;csharp&#8221;]<br \/>\nprivate const string InvariantCultureCode = &#8220;ivl&#8221;;<br \/>\npublic static CultureSpecificity Specificity(this CultureInfo culture)<br \/>\n{<br \/>\nif (culture.ThreeLetterISOLanguageName == InvariantCultureCode)<br \/>\n{<br \/>\nreturn CultureSpecificity.Default;<br \/>\n}<br \/>\n\/\/&#8230;<br \/>\n}<br \/>\n[\/cc]<\/p>\n<p>This works in Windows, where the <span style=\"font-family: monospace\">ThreeLetterISOLanguageName<\/span> is all lower case. But, in Mono, it is all uppercase and this check was not passing when it should have. To solve this error, we changed the code to compare the culture to <span style=\"font-family: monospace\">CultureInfo.InvariantCulture<\/span>. Doing so removes the need for the constant string and the <span style=\"font-family: monospace\">ThreeLetterISOLanguageName<\/span>.<\/p>\n<p>[cc lang=&#8221;csharp&#8221;]<br \/>\npublic static CultureSpecificity Specificity(this CultureInfo culture)<br \/>\n{<br \/>\nif(culture.Equals(CultureInfo.InvariantCulture))<br \/>\n{<br \/>\nreturn CultureSpecificity.Default;<br \/>\n}<br \/>\n\/\/&#8230;<br \/>\n}<br \/>\n[\/cc]<\/p>\n<p>This is the only difference we encountered when running on Mono, which was a huge surprise to us. We were expecting many more things to not work quite right, but had no clue what might go wrong.<\/p>\n<h2>Installing Docker<\/h2>\n<p>Setting up docker on our Ubuntu 14.04 virtual machine was straight forward. We were able to follow the <a href=\"http:\/\/docs.docker.com\/linux\/step_one\/\" target=\"_blank\" rel=\"noopener\">docker installation instructions for Linux<\/a> and got up and running quickly.<\/p>\n<p>The <a href=\"https:\/\/linuxcontainers.org\/\" target=\"_blank\" rel=\"noopener\">technologies that docker relies on<\/a> are only available in Linux. Installing docker on <a href=\"http:\/\/docs.docker.com\/windows\/step_one\/\" target=\"_blank\" rel=\"noopener\">Windows<\/a> or <a href=\"http:\/\/docs.docker.com\/mac\/step_one\/\" target=\"_blank\" rel=\"noopener\">OSX<\/a> requires running a Linux virtual machine that hosts your containers.<\/p>\n<h2>Setting up our Docker Container<\/h2>\n<p>Setting up our docker container proved to be the least convoluted part of this experiment. We decided to use the official Mono container from <a href=\"https:\/\/hub.docker.com\/_\/mono\/\" target=\"_blank\" rel=\"noopener\">Docker Hub<\/a> which saved us a bit of time scripting out the installation of Mono in our own container.<\/p>\n<p><b>Dockerfile<\/b><\/p>\n<pre>FROM mono:4.0\r\nRUN apt-get update &amp;&amp; apt-get -y install mono-xsp4\r\nADD . \/app\/\r\n# RUN gacutil -i -bootstrap assembly_1.dll\r\n# RUN gacutil -i -bootstrap assembly_2.dll\r\nWORKDIR \/app\r\nEXPOSE 9000\r\nENTRYPOINT [\"xsp4\", \"--port=9000\", \"--nonstop\"]\r\n<\/pre>\n<p>What this configuration file is doing:<\/p>\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li>Start <span style=\"font-family: monospace\">FROM the <a href=\"https:\/\/github.com\/mono\/docker\/blob\/0d3556995aa47043059d60c42321e8ccaf173363\/4.0.0\/Dockerfile\" target=\"_blank\" rel=\"noopener\">mono:4.0<\/a> base image<\/span><\/li>\n<li><span style=\"font-family: monospace\">RUN<\/span> our install command to get our server, mono-xsp4, installed<\/li>\n<li><span style=\"font-family: monospace\">ADD<\/span> the current directory to \/app\/. This makes our code available to processes within the container<\/li>\n<li>If you\u2019ve decided to store assemblies in Mono\u2019s GAC, but sure to register them in your container<\/li>\n<li>Set the current working directory to \/app<\/li>\n<li><span style=\"font-family: monospace\">EXPOSE<\/span> port 9000, this will be the port we expect requests to come to<\/li>\n<li>Finally, our container\u2019s <span style=\"font-family: monospace\">ENTRYPOINT<\/span>, or what to run when the container starts<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>Now, we can open a console in our application\u2019s directory and execute <span style=\"font-family: monospace\">docker run<\/span>. This will read our <span style=\"font-family: monospace\">Dockerfile<\/span>, build the container, and start our web application.<\/p>\n<h2>Conclusion<\/h2>\n<p>Getting our application up and running in a docker container was easier than we originally thought it would be when we first started. The whole process took Greg and I about 6 hours, most of which was spent debugging to figure out what was wrong with our code and not issues with Mono or docker.<\/p>\n<p>We\u2019re looking deeper into this to see how and if this can be integrated into our development and continuous integration and deployment processes.<\/p>\n<h2>We\u2019re Hiring<\/h2>\n<p>Interested in playing with these technologies? <a href=\"http:\/\/uship.applytojob.com\/apply\/\" target=\"_blank\" rel=\"noopener\">We\u2019re hiring<\/a>!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Here at uShip, we love to try interesting things during our hackathons. Recently, Greg Walker and I decided to try to get one of our front-end solutions up and running in a docker container. Since docker containers have to run on Linux, that meant getting the project running on Mono first. Installing Mono To start,&#8230;<a class=\"read-more\" href=\"https:\/\/ushipblogsubd.wpengine.com\/shipping-code\/net-web-applications-running-docker\/\"> Read More<\/a><\/p>\n","protected":false},"author":6,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[295,2],"tags":[20,22,23,297],"class_list":["post-4156","post","type-post","status-publish","format-standard","hentry","category-shipping-code","category-company-news","tag-net","tag-docker","tag-linux","tag-shipping-code"],"acf":{"blog_post_content":null},"_links":{"self":[{"href":"https:\/\/ushipblogsubd.wpengine.com\/wp-json\/wp\/v2\/posts\/4156","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ushipblogsubd.wpengine.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ushipblogsubd.wpengine.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ushipblogsubd.wpengine.com\/wp-json\/wp\/v2\/users\/6"}],"replies":[{"embeddable":true,"href":"https:\/\/ushipblogsubd.wpengine.com\/wp-json\/wp\/v2\/comments?post=4156"}],"version-history":[{"count":0,"href":"https:\/\/ushipblogsubd.wpengine.com\/wp-json\/wp\/v2\/posts\/4156\/revisions"}],"wp:attachment":[{"href":"https:\/\/ushipblogsubd.wpengine.com\/wp-json\/wp\/v2\/media?parent=4156"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ushipblogsubd.wpengine.com\/wp-json\/wp\/v2\/categories?post=4156"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ushipblogsubd.wpengine.com\/wp-json\/wp\/v2\/tags?post=4156"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}