<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Christopher P. Town]]></title><description><![CDATA[Austin, Code, Life...]]></description><link>http://christophertown.com/</link><image><url>http://christophertown.com/favicon.png</url><title>Christopher P. Town</title><link>http://christophertown.com/</link></image><generator>Ghost 1.25</generator><lastBuildDate>Sat, 28 Mar 2026 22:23:33 GMT</lastBuildDate><atom:link href="http://christophertown.com/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Developing Angular Applications with Docker Containers]]></title><description><![CDATA[Learn to run and debug your Angular applications within docker containers. ]]></description><link>http://christophertown.com/docker-angular/</link><guid isPermaLink="false">5aec6ef795413474bf79485a</guid><category><![CDATA[Angular]]></category><category><![CDATA[Docker]]></category><category><![CDATA[Orchestration]]></category><category><![CDATA[imagebg]]></category><dc:creator><![CDATA[Christopher Town]]></dc:creator><pubDate>Fri, 01 Jun 2018 14:45:41 GMT</pubDate><media:content url="http://christophertown.com/content/images/2018/05/angularjs-banner.png" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="http://christophertown.com/content/images/2018/05/angularjs-banner.png" alt="Developing Angular Applications with Docker Containers"><p>With microservice architectures, often times it is benefitial to develop you Angular applications from within Docker.  Placing an <code>Nginx</code> proxy in front of your docker container can provide you with clean portless urls and ssl - making integration with services like <a href="https://auth0.com" target="_blank">Auth0</a> more natural.</p>
<p>In this article, I will show you how to work locally while serving your Angular application from within docker.</p>
<hr>
<h2 id="docker">Docker</h2>
<p>We will leverage both Docker and Docker Compose for this project.</p>
<h3 id="dockerfile">Dockerfile</h3>
<p>In order to increase the build times, we will be leveraging a docker cache layer based on the contents of the node <code>package.config</code>. This will prevent the build from having to pull down all of the <code>node_modules</code> files every time. The only time the layer will need to be refreshed is if you add or update an <code>npm</code> package.</p>
<p>Additionally, we will use the environment variable <code>ENABLE_POLLING</code> for Windows development machines that do not support <a href="https://www.npmjs.com/package/fsevents" target="_blank">File System Events</a>.</p>
<pre><code class="language-dockerfile">FROM node:10

LABEL Maintainer = Christopher Town 
LABEL Name = Docker Angular App

# #############################################################################
# Cache layer with package.json for node_modules 
#
ADD package.json package-lock.json ./tmp/
RUN cd /tmp &amp;&amp; npm i npm@latest -g &amp;&amp; npm install &amp;&amp; npm i -g nodemon
RUN mkdir -p /home/app/angular-app &amp;&amp; cp -a /tmp/node_modules /home/app/angular-app

# #############################################################################
# Application Code
#
COPY . /home/app/angular-app

# #############################################################################
# Expose
#
WORKDIR /home/app/angular-app
EXPOSE 4200

# #############################################################################
# Start dev server with polling for Windows
# 
ENTRYPOINT [&quot;/bin/bash&quot;, &quot;-c&quot;, &quot;if [ \&quot;$ENABLE_POLLING\&quot; = \&quot;enabled\&quot; ]; \
then npm run start:docker:poll; else npm run start:docker; fi&quot;]

</code></pre>
<center>
    <a href="https://github.com/christophla/blog-docker-angular/blob/master/Dockerfile" target="_blank">Dockerfile</a>
</center>
<br>
<h3 id="dockercompose">docker-compose</h3>
<p>The docker compose configuration maps the application source in the container to the local development folder via a <code>volume</code>. This will allow <code>ng serve</code> to detect changes and dynamically reload your application.</p>
<pre><code class="language-yaml">version: '3'
services:

  docker-angular-app:
    image: docker-angular-app
    build:
      context: .
      dockerfile: Dockerfile
    container_name: docker-angular-app
    environment:
      - ENABLE_POLLING=${ENABLE_POLLING}
      - VIRTUAL_HOST=web.mydomain.com
    ports:
      - &quot;4200:4200&quot;
    volumes:
      - ./src:/home/app/angular-app/src
    working_dir: /home/app/angular-app
    networks:
      - dev-network
    tty: true
    stdin_open: true

networks:
  dev-network:
    driver: bridge
</code></pre>
<center>
    <a href="https://github.com/christophla/blog-docker-angular/blob/master/docker-compose.yml" target="_blank">docker-compose.yml</a>
</center>
<br>
<blockquote>
<p>The <code>VIRTUAL_HOST</code> variable is used to support loading your container behind an nginx ssl proxy. Check out the post <a href="https://christophertown.com/docker-nginx-proxy/" target="_blank">Clean Development URLs and SSL with Docker and Nginx Proxy</a> for more info.</p>
</blockquote>
<hr>
<h2 id="nodetasks">Node Tasks</h2>
<p>In order to support containers and polling, the following tasks are used:</p>
<pre><code class="language-json">{
  &quot;name&quot;: &quot;docker-angular-app&quot;,
  &quot;version&quot;: &quot;0.0.0&quot;,
  &quot;scripts&quot;: {
    &quot;start&quot;: &quot;ng serve --host 0.0.0.0 --port 4200&quot;,
    &quot;start:docker&quot;: &quot;ng serve --host 0.0.0.0 --port 4200 --configuration=container&quot;,
    &quot;start:docker:poll&quot;: &quot;npm run start:docker -- --poll 1000&quot;
  }
}
</code></pre>
<center>
    <a href="https://github.com/christophla/blog-docker-angular/blob/master/package.json" target="_blank">package.json</a>
</center>
<br>
<hr>
<h2 id="visualstudiocodetasks">Visual Studio Code Tasks</h2>
<p>To streamline launching and debugging your application in a container, we'll add some VS Code tasks and debug launchers.</p>
<h3 id="tasksjson">Tasks.json</h3>
<p>The <code>compose</code> task will help build and compose the docker container.</p>
<pre><code class="language-json">{
    &quot;label&quot;: &quot;compose&quot;,
    &quot;type&quot;: &quot;shell&quot;,
    &quot;osx&quot;: {
        &quot;command&quot;: &quot;bash ./scripts/project-tasks.sh compose&quot;
    },
    &quot;presentation&quot;: {
        &quot;echo&quot;: true,
        &quot;reveal&quot;: &quot;always&quot;,
        &quot;focus&quot;: true,
        &quot;panel&quot;: &quot;dedicated&quot;
    },
    &quot;problemMatcher&quot;: [],
    &quot;windows&quot;: {
        &quot;command&quot;: &quot;.\\scripts\\project-tasks.ps1 -Compose&quot;
    }
}
</code></pre>
<center>
    <a href="https://github.com/christophla/blog-docker-angular/blob/master/.vscode/tasks.json" target="_blank">tasks.json</a>
</center>
<br>
<h3 id="launchjson">Launch.json</h3>
<p>The <code>docker launch</code> debugger will call the <code>compose</code> task to create your container and then launch Chrome with the debugger attached. This will allow you to set breakpoints in you Angular application - even when running in the container.</p>
<pre><code class="language-json">{
    &quot;name&quot;: &quot;Docker Launch&quot;,
    &quot;request&quot;: &quot;launch&quot;,
    &quot;preLaunchTask&quot;: &quot;compose&quot;,
    &quot;type&quot;: &quot;chrome&quot;,
    &quot;url&quot;: &quot;http://localhost:4200&quot;,
    &quot;webRoot&quot;: &quot;${workspaceFolder}&quot;
}
</code></pre>
<center>
    <a href="https://github.com/christophla/blog-docker-angular/blob/master/.vscode/launch.json" target="_blank">launch.json</a>
</center>
<br>
<hr>
<h2 id="helperscripts">Helper Scripts</h2>
<p>Two helper scripts, <code>project-tasks.sh</code> and <code>project-tasks.ps1</code>, have been added to orchestrate the management of your containers. You can read more about them in the web series, <a href="https://christophertown.com/orchestrating-visual-studio-code-overview/" target="_blank">Orchestrating Visual Studio Code</a>.</p>
<hr>
<h2 id="sourcecode">Source Code</h2>
<p><a href="https://github.com/christophla/blog-docker-angular" target="_blank">https://github.com/christophla/blog-docker-angular</a></p>
</div>]]></content:encoded></item><item><title><![CDATA[Orchestrating Visual Studio Code Series]]></title><description><![CDATA[One of the great features of Visual Studio Code is its extensibility. In this series, we will discover how to orchestrate your development environment by leveraging the built in extension points of the IDE to automate everything from unit tests to docker to deployment.]]></description><link>http://christophertown.com/orchestrating-visual-studio-code-overview/</link><guid isPermaLink="false">5ae7c0c472e90b095ddfdf59</guid><category><![CDATA[VSCode]]></category><category><![CDATA[Orchestration]]></category><category><![CDATA[Docker]]></category><category><![CDATA[double]]></category><dc:creator><![CDATA[Christopher Town]]></dc:creator><pubDate>Wed, 16 May 2018 01:23:00 GMT</pubDate><media:content url="http://christophertown.com/content/images/2018/05/orchestrating-vs-code-intro-banner.jpg" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="http://christophertown.com/content/images/2018/05/orchestrating-vs-code-intro-banner.jpg" alt="Orchestrating Visual Studio Code Series"><p>One of the great features of Visual Studio Code is its extensibility. In this series, we will learn how to orchestrate your development environment by leveraging the built in extension points of the IDE.</p>
<h2 id="prerequisites">Prerequisites</h2>
<ul>
<li>Visual Studio Code: <a href="https://code.visualstudio.com">https://code.visualstudio.com</a></li>
<li>DotNet Core SDK: <a href="https://www.microsoft.com/net/download">https://www.microsoft.com/net/download</a></li>
<li>Docker: <a href="https://www.docker.com">https://www.docker.com</a></li>
</ul>
<h2 id="sections">Sections</h2>
<p>The series is broken down into several sections:</p>
<h3 id="part2tasksandlaunchers"><a href="https://christophertown.com/orchestrating-vscode-tasks-and-launchers">Part 2 : Tasks and Launchers</a></h3>
<p>We start by learning how to leverage tasks to build docker containers, push NuGet packages, run unit and integration tests, and more. Configure launchers to debug your code locally and remotely within docker.</p>
<h3 id="part3debuggingwithdockercontainers"><a href="https://christophertown.com/orchestrating-vscode-debugging-docker">Part 3 : Debugging with Docker Containers</a></h3>
<p>Everything needed to remotely debug your microservices from within the docker environment.</p>
<h3 id="part4appsettingsandthecontainer"><a href="https://christophertown.com/orchestrating-vscode-running-docker-containers">Part 4 : AppSettings and the Container</a></h3>
<p>Learn to configure multiple runtime settings to allow combinations of local and container debugging.</p>
<h3 id="part5unittesting"><a href="https://christophertown.com/orchestrating-vscode-unit-testing">Part 5 : Unit Testing</a></h3>
<p>Executing unit tests using VSCode tasks.</p>
<h3 id="part6codecoverage"><a href="https://christophertown.com/orchestrating-vscode-test-code-coverage/">Part 6 : Code Coverage</a></h3>
<p>Leverage coverlet and LCOV to generate html test-coverage reports.</p>
<h3 id="part7nugetdeployments"><a href="https://christophertown.com/orchestrating-vscode-nuget-deployment">Part 7 : NuGet Deployments</a></h3>
<p>Deploy nuget packages with VSCode tasks.</p>
<h3 id="part8continuousintegrationbuilds"><a href="https://christophertown.com/orchestrating-vscode-ci-builds">Part 8 : Continuous Integration Builds</a></h3>
<p>Create a CI build using everything we've learned using TravisCI.</p>
<hr>
<h2 id="windowsusers">Windows Users</h2>
<p>All script samples in this series are written in <a href="https://en.wikipedia.org/wiki/Bash_(Unix_shell)">bash</a> for OSX and Linux. <em>PowerShell</em> equivalent scripts are provided in the source repository to allow identical functionality under Windows. In fact, all of the provided VS Code tasks will automatically point to the <em>PowerShell</em> scripts when running on a Windows OS.</p>
<h2 id="codesamples">Code Samples</h2>
<p>A fully-functional project is provided for the series. Each part is contained in its <strong>own branch</strong>. Be sure to select the appropriate branch for each part of the series.</p>
<p>The full source code can be found at: <a href="https://github.com/christophla/blog-orchestrating-vscode" target="_blank">https://github.com/christophla/blog-orchestrating-vscode</a></p>
<hr>
<h2 id="nextposttasksandlaunchers">Next Post : <a href="https://christophertown.com/orchestrating-vscode-tasks-and-launchers">Tasks and Launchers</a></h2>
<p>In the next post we will learn how to leverage <em>tasks</em> and <em>launchers</em> to orchestrate building and debugging our application.</p>
<hr>
<center>
<a class="btn btn-sm" href="https://christophertown.com/orchestrating-vscode-tasks-and-launchers">Let's get started!</a>
</center>
</div>]]></content:encoded></item><item><title><![CDATA[Clean Development URLs and SSL with Docker and Nginx Proxy]]></title><description><![CDATA[Developing port-less docker microservices with nginx proxy, host names, and SSL.]]></description><link>http://christophertown.com/docker-nginx-proxy/</link><guid isPermaLink="false">5aec739695413474bf79485e</guid><category><![CDATA[Docker]]></category><category><![CDATA[Nginx]]></category><dc:creator><![CDATA[Christopher Town]]></dc:creator><pubDate>Tue, 15 May 2018 16:29:43 GMT</pubDate><media:content url="http://christophertown.com/content/images/2018/05/url-banner.jpg" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="http://christophertown.com/content/images/2018/05/url-banner.jpg" alt="Clean Development URLs and SSL with Docker and Nginx Proxy"><p>When developing microservices with docker containers, I often find myself trying to remember all of the different ports exposed by each service. Fortunately, there is a way to provide memorable, clean urls for each of your service endpoints.</p>
<p>By leveraging an <em>Nginx Proxy</em> in one of your containers, we can easily assign subdomains <em>(e.g. service-a.mydomain.com)</em> to each of your microservice projects.</p>
<p>I'll also show you how to dynamically generate a development certificate and load it into the proxy so that you will be able to connect securely to your services with SSL.</p>
<h3 id="sourcefiles">Source Files</h3>
<p>All files are available in the repository: <a href="https://github.com/christophla/blog-docker-nginx-proxy">https://github.com/christophla/blog-docker-nginx-proxy</a></p>
<p>Both <code>Bash</code> and <code>PowerShell</code> scripts are provided for Windows, OSX, and Linux.</p>
<h2 id="thedockercomposefile">The Docker Compose File</h2>
<p>Jason Wilder has created a great docker image, <a href="https://github.com/jwilder/nginx-proxy">jwilder/nginx-proxy</a>, that contains an instance of Nginx that automatically wires up a reverse proxy with host-headers for any docker containers that include the environmental variable <code>VIRTUAL_HOST</code>.</p>
<p>In the <a href="https://github.com/christophla/blog-docker-nginx-proxy">sample code</a>, I've included a dotnet core webapi project as a service, along with an instance of nginx-proxy. The service <code>nginx-proxy-app</code> sets its virtual host as <code>myapp.nginx-proxy-app.com</code>.</p>
<pre><code class="language-yaml">version: '3'

services:

  nginx-proxy-app:
    container_name: nginx-proxy-app
    image: nginx-proxy-app
    build: 
      context: .
      dockerfile: Dockerfile
    environment:
      - ASPNETCORE_ENVIRONMENT=development
      - REMOTE_DEBUGGING=${REMOTE_DEBUGGING}
      - VIRTUAL_HOST=myapp.nginx-proxy-app.com
    ports:
      - &quot;5000:80&quot;
    networks:
      - dev-network
    tty: true
    stdin_open: true

  nginx-proxy-nat:
    image: jwilder/nginx-proxy
    container_name: nginx-proxy-nat
    environment:
      - HSTS=off
      - HTTPS_METHOD=noredirect
    ports:
      - &quot;80:80&quot;
      - &quot;443:443&quot;
    networks:
      - dev-network
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock:ro
      - ./certs:/etc/nginx/certs

networks:
  dev-network:
    driver: bridge
</code></pre>
<center>
    <a href="https://github.com/christophla/blog-docker-nginx-proxy/blob/master/docker-compose.yml" target="_blank">docker-compose.yml</a>
</center>
<br>
<hr>
<h3 id="thesetupscript">The Setup Script</h3>
<p>Our script is going to have to perform several things in order to setup our project to be able to use hostnames and SSL. First, we will remove any existing certificates generated for our custom domain. This will allow us to generate a new certificate when we add or remove services (and hostnames) to our development environment. Next, we will generate a certificate and add it to the docker volume <code>./certs:/etc/nginx/certs</code> so that Nginx can pick it up for SSL. Last, we will add our hostnames to the local machine <code>etc/hosts</code> file..</p>
<pre><code class="language-bash">setupProxy () {

    # remove existing certificates
    echo -e &quot;${YELLOW} Removing existings certificates... ${RESTORE}&quot;
    sudo security delete-certificate -c $certificatePrefix /Library/Keychains/System.keychain

    # generate key
    openssl \
        genrsa \
        -out certs/$certificatePrefix.key \
        4096

    # generate csr request
    openssl \
        req \
        -new \
        -sha256 \
        -out certs/$certificatePrefix.csr \
        -key certs/$certificatePrefix.key \
        -config openssl-san.conf

    #generate certificate from csr request
    openssl \
        x509 \
        -req \
        -days 3650 \
        -in certs/$certificatePrefix.csr \
        -signkey certs/$certificatePrefix.key \
        -out certs/$certificatePrefix.crt \
        -extensions req_ext \
        -extfile openssl-san.conf

    # generate pem
    cat certs/$certificatePrefix.crt certs/$certificatePrefix.key &gt; certs/$certificatePrefix.pem

    # install certificate
    if [ -f certs/$certificatePrefix.crt ]; then
        echo -e &quot;${YELLOW} Installing certificate... ${RESTORE}&quot;
        sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain certs/$certificatePrefix.crt
    else
        echo -e &quot;${RED} An error occurred while generating the certificate: certs/$certificatePrefix.crt ${RESTORE}&quot;
    fi
    
    # Write Hosts
    addHost &quot;myapp.nginx-proxy-app.com&quot;

}
</code></pre>
<center>
    <a href="https://github.com/christophla/blog-docker-nginx-proxy/blob/master/scripts/project-tasks.sh#L105" target="_blank">project-tasks.sh</a>
</center>
<br>
<p>Since Chrome 58, self signed wildcard certificates are not supported without Subject Alternative Names (SANs). As a result, we will will use the config file <code>openssl-san.conf</code> to include each of our service hostnames.</p>
<pre><code class="language-conf">[req]
default_bits = 2048
prompt = no
default_md = sha256
req_extensions = req_ext
distinguished_name = dn

[ dn ]
C=US
ST=Texas
L=Austin
O=Development
OU=Development Domain
emailAddress=admin@nginx-proxy-app.com
CN = nginx-proxy-app.com

[ req_ext ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names

[alt_names]
DNS.1 = myapp.nginx-proxy-app.com

</code></pre>
<center>
    <a href="https://github.com/christophla/blog-docker-nginx-proxy/blob/master/openssl-san.conf#L105" target="_blank">openssl-san.conf</a>
</center>
<br>
<h3 id="thesetuptask">The Setup Task</h3>
<p>We are going to create a VS Code Task to make running our script easier from within the IDE.</p>
<pre><code class="language-json">{
    &quot;version&quot;: &quot;2.0.0&quot;,
    &quot;tasks&quot;: [{
        &quot;label&quot;: &quot;setup&quot;,
        &quot;type&quot;: &quot;shell&quot;,
        &quot;osx&quot;: {
            &quot;command&quot;: &quot;bash ./scripts/project-tasks.sh setup&quot;
        },
        &quot;presentation&quot;: {
            &quot;echo&quot;: true,
            &quot;reveal&quot;: &quot;always&quot;,
            &quot;focus&quot;: true,
            &quot;panel&quot;: &quot;dedicated&quot;
        },
        &quot;problemMatcher&quot;: [],
        &quot;windows&quot;: {
            &quot;command&quot;: &quot;.\\scripts\\project-tasks.ps1 -Setup&quot;
        }
    }]
}
</code></pre>
<center>
    <a href="https://github.com/christophla/blog-docker-nginx-proxy/blob/master/.vscode/tasks.json#L49" target="_blank">tasks.json</a>
</center>
<br>
<hr>
<h2 id="conclusion">Conclusion</h2>
<p>At this point, you should able to launch your docker-compose project and the Nginx service will automatically wire up your other services as hostnames with SSL.</p>
<hr>
<h2 id="sourcecode">Source Code</h2>
<p>A fully-functional project is available at:</p>
<p><a href="https://github.com/christophla/blog-docker-nginx-proxy">https://github.com/christophla/blog-docker-nginx-proxy</a></p>
</div>]]></content:encoded></item><item><title><![CDATA[Orchestrating Visual Studio Code : Part 8 : CI Builds]]></title><description><![CDATA[Adding a Travis CI build that leverages the orchestration tasks created in this web series.]]></description><link>http://christophertown.com/orchestrating-vscode-ci-builds/</link><guid isPermaLink="false">5af0f45795413474bf79488e</guid><category><![CDATA[VSCode]]></category><category><![CDATA[Orchestration]]></category><category><![CDATA[Travis]]></category><category><![CDATA[CI]]></category><category><![CDATA[Docker]]></category><dc:creator><![CDATA[Christopher Town]]></dc:creator><pubDate>Sat, 12 May 2018 13:17:00 GMT</pubDate><media:content url="http://christophertown.com/content/images/2018/05/vscode-orchestration-banner-8.jpg" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="http://christophertown.com/content/images/2018/05/vscode-orchestration-banner-8.jpg" alt="Orchestrating Visual Studio Code : Part 8 : CI Builds"><p>In this section, we will be adding a Continuous Integration (CI) build that leverages our <code>project-tasks.sh</code> scripts and tasks.</p>
<h2 id="travisci">Travis CI</h2>
<p><a href="https://travis.org">Travis CI</a> is a free CI server for open-source  projects.</p>
<h3 id="theconfigurationfile">The Configuration File</h3>
<p>Create the file <code>.travis.yaml</code> in the the root of your project:</p>
<pre><code class="language-yaml">language: csharp
solution: WebApp.sln
mono: none
dotnet: 2.1.101
script:
  - chmod +x ./scripts/project-tasks.sh
  - ./scripts/project-tasks.sh compose
  - ./scripts/project-tasks.sh unitTests
  - ./scripts/project-tasks.sh nugetPublish
sudo: required
services:
  - docker
</code></pre>
<center>
    <a href="https://github.com/christophla/blog-orchestrating-vscode/blob/part-8-ci-builds/.travis.yml" target="_blank">.travis.yml</a>
</center>
<br>
<blockquote>
<p>Be sure to include the leading <code>.</code> in the filename.</p>
</blockquote>
<h3 id="travissetup">Travis Setup</h3>
<p>Head over to <a href="https://travis-ci.org/christophla/blog-orchestrating-vscode">https://travis-ci.org/christophla/blog-orchestrating-vscode</a> to see the build in-action.</p>
<h2 id="conclusion">Conclusion</h2>
<p>This wraps up the end of the web series <em><strong>Orchestrating Visual Studio Code</strong></em>.</p>
<hr>
<h1 id="thesourcecode">The Source Code</h1>
<p>You can find the source code for this article in the following repository under the <code>part-7-nuget-deployment</code> branch:</p>
<p><a href="https://github.com/christophla/blog-orchestrating-vscode/tree/part-8-ci-builds" target="_blank">https://github.com/christophla/blog-orchestrating-vscode/tree/part-8-ci-builds</a></p>
<hr>
<h3 id="previouspostnugetdeployment">Previous Post : NuGet Deployment</h3>
<p><a href="https://christophertown.com/orchestrating-vscode-nuget-deployment">https://christophertown.com/orchestrating-vscode-nuget-deployment</a></p>
</div>]]></content:encoded></item><item><title><![CDATA[Hosting Angular Entirely on Azure CDN]]></title><description><![CDATA[Learn how to host your Angular SPA entirely on a CDN without needing a Virtual Machine.]]></description><link>http://christophertown.com/hosting-angular-entirely-on-azure-cdn/</link><guid isPermaLink="false">5af37ce76f4aa2282edd0323</guid><category><![CDATA[Azure]]></category><category><![CDATA[Cloud]]></category><category><![CDATA[CDN]]></category><dc:creator><![CDATA[Christopher Town]]></dc:creator><pubDate>Fri, 11 May 2018 14:44:09 GMT</pubDate><media:content url="http://christophertown.com/content/images/2018/05/cdn-banner-3.jpg" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="http://christophertown.com/content/images/2018/05/cdn-banner-3.jpg" alt="Hosting Angular Entirely on Azure CDN"><p>Content Delivery Networks (CDNs) are the backbone of the internet. Instead of sending content from your datacenter to a client half-way around the world, the content is pre-distributed and fetched from a server far closer (sometimes just down the street).</p>
<p>Typically with an Angular application, we put the <code>index.html</code> loading page on a Virtual Machine (VM) or Docker instance and then ship the rest of our application off to a CDN to make delivery more efficient and responsive. But what if you don't want to front the cost of hosting an <code>index.html</code> with a single VM or docker image?</p>
<p>Just imagine if your index page is hosted in a datacenter in Texas (South Central US) and a customer in London (UK South) brings up your site, they need to make a connection all the way across the Atlantic, just to be told that they can grab all of the additional required resources from a CDN a couple of miles away.</p>
<p>Why not cut out the middleman and bring everything close to home - all while cutting costs? We can achieve this by leveraging Azure's Premium CDN and its rules engine.</p>
<h2 id="enterazurepremiumcdn">Enter Azure Premium CDN</h2>
<p>What differentiates Azure CDN and Azure Premium CDN is that premium (Verizon) gives you an interface to control far more aspects of its behavior. You can set tokens, geo-filtering, caching, and - most importantly - add <strong>rules</strong>.</p>
<h3 id="managingrules">Managing Rules</h3>
<p>For the sake of hosting a single page application on the CDN, lets focus on the rules engine that Azure Premium CDN offers. Rules will allow us to set a default document (index.html) for our site so that we have clean URLs.</p>
<p>Once you've created a Premium Azure CDN endpoint, go ahead an open it up in Azure Portal and select <code>manage</code>.</p>
<p><img src="http://christophertown.com/content/images/2018/05/cdn-manage-bar.PNG" alt="Hosting Angular Entirely on Azure CDN"></p>
<p>Go ahead an open the rules section under the CDN management site.</p>
<p><img src="http://christophertown.com/content/images/2018/05/cdn-rules-menu.png" alt="Hosting Angular Entirely on Azure CDN"></p>
<h3 id="addingarule">Adding a Rule</h3>
<p>Click <code>Add New</code>:</p>
<p>Name / Description : Default Document</p>
<p>Choose <code>IF</code> and <code>Always</code> and add the following features. The source and destination pull-down should be your blob storage location for your app.</p>
<ul>
<li>URL Rewrite
<ul>
<li>Source: <code>((?:[^\?]*/)?)($|\?.*)</code></li>
<li>Destination : <code>$1index.html$2</code></li>
</ul>
</li>
<li>URL Rewrite
<ul>
<li>Source: <code>((?:[^\?]*/)?[^\?/.]+)($|\?.*)</code></li>
<li>Destination : <code>$1.html$2</code></li>
</ul>
</li>
</ul>
<hr>
<p>This will point all URIs to your index.html page, e.g.:</p>
<ul>
<li><a href="http://mysite.com">http://mysite.com</a></li>
<li><a href="http://mysite.com/#/home?myvar=one">http://mysite.com/#/home?myvar=one</a></li>
<li><a href="http://mysite.com/index.html">http://mysite.com/index.html</a></li>
</ul>
<hr>
<p><img src="http://christophertown.com/content/images/2018/05/cdn-rule-default-document-2.png" alt="Hosting Angular Entirely on Azure CDN"></p>
<h3 id="settingupdns">Setting Up DNS</h3>
<p>At this point, you can create a C-Name Record pointing www.yourdomain.com to the Azure CDN entpoint at <a href="https://yourapp.azureedge.net">https://yourapp.azureedge.net</a>. If your DNS provider supports it,  you can create a page-rule that redirects all requests to <code>yourdomain.com/*</code> to <code>www.yourdomain.com/*</code>. Personally, I use <a href="https://www.cloudflare.com">CloudFlare</a> account to manage my DNS, which supports redirecting to the C-Name.</p>
<h3 id="caveats">Caveats</h3>
<p>Since your <code>index.html</code> page is hosted on the CDN, when you push a new version of your application, it can take a long time for the changes to be reflected. You will need to select <code>purge</code> to see changes immediately.</p>
<p><img src="http://christophertown.com/content/images/2018/05/cdn-manage-bar.PNG" alt="Hosting Angular Entirely on Azure CDN"></p>
<h2 id="conclusion">Conclusion</h2>
<p>I will be publishing a post in the future that describes how to host the <code>index.html</code> in an proxied <em><strong>Azure Function</strong></em>. This can help alleviate the need to reset the CDN cache after each deployment.</p>
</div>]]></content:encoded></item><item><title><![CDATA[Orchestrating Visual Studio Code : Part 2 : Tasks and Launchers]]></title><description><![CDATA[Leverage tasks to build docker containers, push nuget packages, run unit and integration tests, and more. Configure launchers to debug your code locally and remotely within docker.]]></description><link>http://christophertown.com/orchestrating-vscode-tasks-and-launchers/</link><guid isPermaLink="false">5ae9fbad72e90b095ddfdf81</guid><category><![CDATA[VSCode]]></category><category><![CDATA[Orchestration]]></category><category><![CDATA[Docker]]></category><dc:creator><![CDATA[Christopher Town]]></dc:creator><pubDate>Thu, 10 May 2018 21:01:00 GMT</pubDate><media:content url="http://christophertown.com/content/images/2018/05/vscode-orchestration-banner.jpg" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="http://christophertown.com/content/images/2018/05/vscode-orchestration-banner.jpg" alt="Orchestrating Visual Studio Code : Part 2 : Tasks and Launchers"><p>As developers, we are always leveraging various tools to help automate our day-to-day tasks. VS Code provides a built-in way of organizing all of these various workflows with <em>Tasks</em>. You can easily fire of a task without trying to remember what command to type, all while staying within the IDE. Combined with debug launchers, tasks can supercharge your environment and help you automate any process.</p>
<p>We are going to create a simple solution with a web-api project and then create some basic tasks to help us build and debug the application.</p>
<h2 id="settinguptheenvironment">Setting Up the Environment</h2>
<p>To get started, let’s create a basic web-api solution from the command line:</p>
<pre><code class="language-bash">dotnet new sln --name WebApp
</code></pre>
<p>Next, let's create a webapi application in the <code>/src</code> folder.</p>
<pre><code class="language-bash">mkdir src
cd src
dotnet new webapi
</code></pre>
<p>Go ahead and open your project in VSCode. The IDE should ask you if you'd like to add default folders. Say <code>Yes</code> and you should see a folder structure similar to the following:</p>
<pre><code class="language-bash">│   WebApp.sln
│
├───.vscode
│       launch.json
│       tasks.json
│
└───src
    │   appsettings.json
    │   appsettings.development.json
    │   Program.cs
    │   Startup.cs
    │   WebApp.csproj
    │
    └───Controllers
            ValuesController.cs
</code></pre>
<center>
    <a href="https://github.com/christophla/blog-orchestrating-vscode/tree/part-2-tasks-and-launchers" target="_blank">source</a>
</center>
<hr>
<h3 id="tasksandlaunchers">Tasks and Launchers</h3>
<p>As stated earlier, <em>Tasks</em> allow you to easily call commands and scripts from within the IDE. They can be used to automate any process that you may need; builds with gulp, building docker containers, pushing code to NuGet, etc. <em>Launchers</em> are used to launch your application with a debugger attached.</p>
<p>Both are defined in the <code>.vscode</code> folder in the root of your project:</p>
<pre><code class="language-bash">├── .vscode
    ├── launch.json
    ├── tasks.json
</code></pre>
<blockquote>
<p>If VSCode doesn't prompt you to automatically create the <code>.vscode</code> folder, you can always add it yourself.</p>
</blockquote>
<hr>
<h3 id="creatingatask">Creating a Task</h3>
<p>We'll start by creating a task to build our project.</p>
<pre><code class="language-json">{
    &quot;version&quot;: &quot;2.0.0&quot;,
    &quot;tasks&quot;: [{
        &quot;label&quot;: &quot;build&quot;,
        &quot;command&quot;: &quot;dotnet&quot;,
        &quot;type&quot;: &quot;process&quot;,
        &quot;args&quot;: [
            &quot;build&quot;,
            &quot;${workspaceFolder}/src/WebApp.csproj&quot;
        ],
        &quot;problemMatcher&quot;: &quot;$msCompile&quot;
    }]
}
</code></pre>
<center>
    <a href="https://github.com/christophla/blog-orchestrating-vscode/blob/part-2-tasks-and-launchers/.vscode/tasks.json" target="_blank">tasks.json</a>
</center>
<p>To run your task, press <code>F1</code> and then select <code>Tasks:Run Task</code>. Your task should be in the list the the label <code>build</code>. You'll see the solution being built in the VSCode output panel.</p>
<hr>
<h3 id="creatingadebuglauncher">Creating a Debug Launcher</h3>
<p>Debug Launchers are just that - a way to execute a process with the VSCode debugger attached. The <code>preLaunchTask</code> property tells the launcher to call our <code>build</code> task before launching the application.</p>
<pre><code class="language-json">{
    &quot;version&quot;: &quot;0.2.0&quot;,
    &quot;configurations&quot;: [{
        &quot;name&quot;: &quot;Local Launch&quot;,
        &quot;args&quot;: [],
        &quot;cwd&quot;: &quot;${workspaceFolder}/src&quot;,
        &quot;env&quot;: {
            &quot;ASPNETCORE_ENVIRONMENT&quot;: &quot;development&quot;,
            &quot;ASPNETCORE_URLS&quot;: &quot;http://+:5000&quot;
        },
        &quot;internalConsoleOptions&quot;: &quot;openOnSessionStart&quot;,
        &quot;launchBrowser&quot;: {
            &quot;args&quot;: &quot;http://localhost:5000&quot;,
            &quot;enabled&quot;: true,
            &quot;linux&quot;: {
                &quot;command&quot;: &quot;xdg-open&quot;
            },
            &quot;osx&quot;: {
                &quot;command&quot;: &quot;open&quot;
            },
            &quot;windows&quot;: {
                &quot;args&quot;: &quot;/C start http://localhost:5000/api/values&quot;,
                &quot;command&quot;: &quot;cmd.exe&quot;
            }
        },
        &quot;preLaunchTask&quot;: &quot;build&quot;,
        &quot;program&quot;: &quot;${workspaceFolder}/src/bin/Debug/netcoreapp2.0/WebApp.dll&quot;,
        &quot;request&quot;: &quot;launch&quot;,
        &quot;sourceFileMap&quot;: {
            &quot;/src&quot;: &quot;${workspaceFolder}/src&quot;
        },
        &quot;stopAtEntry&quot;: false,
        &quot;type&quot;: &quot;coreclr&quot;
    }]
}
</code></pre>
<center>
<a href="https://github.com/christophla/blog-orchestrating-vscode/blob/part-2-tasks-and-launchers/.vscode/launch.json" target="_blank">launch.json</a>
</center>
<br>
<h3 id="launchingyourproject">Launching Your Project</h3>
<p>The <code>launchBrowser</code> section tells VSCode to open the page <code>http://localhost:5000/api/values</code> once the application is running. Go ahead and press F5 or the <em>debug icon</em> to launch your application.</p>
<p>You should see a webpage with the following response (default for webapi scaffold):</p>
<pre><code>[&quot;value1&quot;,&quot;value2&quot;]
</code></pre>
<hr>
<h2 id="projectsettings">Project Settings</h2>
<p>Visual Studio Code support project-level settings via the file <code>settings.json</code> in the <code>.vscode</code> folder.</p>
<pre><code class="language-json">{
    &quot;files.eol&quot;: &quot;\n&quot;
}
</code></pre>
<center>
<a href="https://github.com/christophla/blog-orchestrating-vscode/blob/part-2-tasks-and-launchers/.vscode/settings.json" target="_blank">settings.json</a>
</center>
<br>
<hr>
<h2 id="projectextensions">Project Extensions</h2>
<p>Visual Studio Code supports project-level extensions via the file <code>extensions.json</code> in the <code>.vscode</code> folder. When your project is first opened by a new developer, the IDE will prompt to install the extensions.</p>
<pre><code class="language-json">{
    &quot;recommendations&quot;: [
        &quot;editorconfig.editorconfig&quot;,
        &quot;ms-vscode.csharp&quot;,
        &quot;robertohuertasm.vscode-icons&quot;
    ]
}
</code></pre>
<center>
<a href="https://github.com/christophla/blog-orchestrating-vscode/blob/part-2-tasks-and-launchers/.vscode/extensions.json" target="_blank">extensions.json</a>
</center>
<br>
<h3 id="editorconfigeditorconfigeditorconfig">EditorConfig (editorconfig.editorconfig)</h3>
<p>EditorConfig is used to maintain consistent formatting across developers in a project. <a href="http://editorconfig.org">http://editorconfig.org</a></p>
<h3 id="omnisharpcmsvscodecsharp">OmniSharp C# (ms-vscode.csharp)</h3>
<p>OniSharp is required to provide support for C#. It performs code anylsis with the Roslyn compiler and loads assemblies and projects. <a href="http://www.omnisharp.net">http://www.omnisharp.net</a></p>
<h3 id="vscodeiconsrobertohuertasmvscodeicons">VSCode Icons (robertohuertasm.vscode-icons)</h3>
<p>VSCode icons extend the built-in icons and provide an enhanced user experience.</p>
<hr>
<h2 id="conclusion">Conclusion</h2>
<p>At this point, we have learned how to configure the built-in project extension points in Visual Studio Code. By leveraging <em>tasks</em>, <em>launchers</em>, <em>settings</em>, and <em>extensions</em>, we are able to customize our project across development teams and provide functionality without leaving the IDE.</p>
<hr>
<h2 id="sourcecode">Source Code</h2>
<p><a href="https://github.com/christophla/blog-orchestrating-vscode/tree/part-2-tasks-and-launchers" target="_blank">https://github.com/christophla/blog-orchestrating-vscode/tree/part-2-tasks-and-launchers</a></p>
<hr>
<h2 id="nextpostdebuggingdockercontainers">Next Post : Debugging Docker Containers</h2>
<p>In the next post we will learn how to leverage <em>tasks</em> and <em>launchers</em> to orchestrate building and debugging our application.</p>
<hr>
<center>
<a class="btn btn-sm" href="https://christophertown.com/orchestrating-vscode-debugging-docker">Let's start debugging!</a>
</center>
<hr>
<h3 id="previouspostoverview">Previous Post : Overview</h3>
<p><a href="https://christophertown.com/orchestrating-visual-studio-code-overview">https://christophertown.com/orchestrating-visual-studio-code-overview</a></p>
</div>]]></content:encoded></item><item><title><![CDATA[Orchestrating Visual Studio Code : Part 7 : NuGet Deployment]]></title><description><![CDATA[Deploying NuGet packages with VSCode tasks.]]></description><link>http://christophertown.com/orchestrating-vscode-nuget-deployment/</link><guid isPermaLink="false">5aea050872e90b095ddfdf87</guid><category><![CDATA[VSCode]]></category><category><![CDATA[Orchestration]]></category><category><![CDATA[Docker]]></category><category><![CDATA[NuGet]]></category><dc:creator><![CDATA[Christopher Town]]></dc:creator><pubDate>Wed, 02 May 2018 22:44:29 GMT</pubDate><media:content url="http://christophertown.com/content/images/2018/05/vscode-orchestration-banner-6.jpg" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="http://christophertown.com/content/images/2018/05/vscode-orchestration-banner-6.jpg" alt="Orchestrating Visual Studio Code : Part 7 : NuGet Deployment"><p>In this part, we will learn how to integrate NuGet package packing and deployment into our project.</p>
<h2 id="thenugetscript">The NuGet Script</h2>
<p>We will add the method <code>nugetPublish()</code> to <code>.vscode/tasks.json</code>. This will search all projects in the solution that contain a <code>.nuspec</code> file, run <code>dotnet pack</code>, and <code>curl</code> upstream to NuGet.</p>
<pre><code class="language-json">nugetPublish () {

    echo -en &quot;${YELLOW} Using Key: $nugetKey ${RESTORE}\n&quot;

    buildEnvironment=@1

    if [[ -z buildEnvironment ]]; then
        buildEnvironment=&quot;debug&quot;
    fi

    shopt -s nullglob # hide hidden

    cd src

    for dir in */ ; do # iterate projects
        [ -e &quot;$dir&quot; ] || continue

        cd $dir

        for nuspec in *.nuspec; do

            projectName=${dir::-1}
            echo -e &quot;${YELLOW}Found nuspec for ${projectName} ${RESTORE}&quot;

            dotnet pack \
            -c $buildEnvironment \
            --include-source \
            --include-symbols

            echo -e &quot;${YELLOW}Publishing: ${projectName}.$nugetVersion ${RESTORE}&quot;

            curl \
            -H 'Content-Type: application/octet-stream' \
            -H &quot;X-NuGet-ApiKey: $nugetKey&quot; \
            $nugetFeedUri \
            --upload-file bin/$buildEnvironment/${projectName}.$nugetVersion.nupkg

        done

        cd $ROOT_DIR

    done
}
</code></pre>
<center>
    <a href="https://github.com/christophla/blog-orchestrating-vscode/blob/part-7-nuget-deployment/scripts/project-tasks.sh#L94" target="_blank">project-tasks.sh</a>
</center>
<br>
<blockquote>
<p>You can also use a MyGet feed with the variable <code>$nugetFeedUri</code> in this script.</p>
</blockquote>
<hr>
<h2 id="thenugettask">The NuGet Task</h2>
<p>We will add the task <code>nuget-publish</code> to the <code>.vscode\tasks.json</code> file:</p>
<pre><code class="language-json">{
    &quot;label&quot;: &quot;nuget-publish&quot;,
    &quot;type&quot;: &quot;shell&quot;,
    &quot;osx&quot;: {
        &quot;command&quot;: &quot;bash ./scripts/project-tasks.sh nugetPublish&quot;
    },
    &quot;presentation&quot;: {
        &quot;echo&quot;: true,
        &quot;reveal&quot;: &quot;always&quot;,
        &quot;focus&quot;: true,
        &quot;panel&quot;: &quot;dedicated&quot;
    },
    &quot;problemMatcher&quot;: [],
    &quot;windows&quot;: {
        &quot;command&quot;: &quot;.\\scripts\\project-tasks.ps1 -NugetPublish&quot;
    }
}
</code></pre>
<center>
    <a href="https://github.com/christophla/blog-orchestrating-vscode/blob/part-7-nuget-deployment/.vscode/tasks.json#L49" target="_blank">tasks.json</a>
</center>
<br>
<hr>
<h2 id="deploying">Deploying</h2>
<p>After adding a project with a <code>.nuspec</code> to your solution, press F1 and select the task <code>nuget-publish</code>. You will see the project get built, packed, and uploaded to NuGet or MyGet.</p>
<pre><code class="language-bash">++++++++++++++++++++++++++++++++++++++++++++++++
+ Deploying nuget packages to nuget feed
+ https://www.myget.org/F/envoice/api/v2
++++++++++++++++++++++++++++++++++++++++++++++++

 Using Key: 00000000-0000-0000-0000-000000000000

Found nuspec for MyApp.NuGetProject
Microsoft (R) Build Engine version 15.6.82.30579 for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.

  Restoring packages for ...
   Publishing: MyApp.NuGetProject.1.0.0
    The package has been created.

++++++++++++++++++++++++++++++++++++++++++++++++
Uploaded nuspec for MyApp.NuGetProject
++++++++++++++++++++++++++++++++++++++++++++++++
</code></pre>
<blockquote>
<p>Instead of storing your api-key in source code, the script looks for an environment variable <code>NUGET_KEY</code>. You also need to set the NuGet|MyGet feed uri to the one provided from your account.</p>
</blockquote>
<hr>
<h1 id="thesourcecode">The Source Code</h1>
<p>You can find the source code for this article in the following repository under the <code>part-7-nuget-deployment</code> branch:</p>
<p><a href="https://github.com/christophla/blog-orchestrating-vscode/tree/part-7-nuget-deployment" target="_blank">https://github.com/christophla/VSCode-Orchestration/tree/part-7-nuget-deployment</a></p>
<h2 id="nextpostpart8ciintegration">Next Post : Part 8 : CI Integration</h2>
<p>In the next post we will learn how integrate our tasks and scripts in our Continuous Build Server.</p>
<hr>
<center>
<a class="btn btn-red btn-sm" href="https://christophertown.com/orchestrating-vscode-ci-builds">Let's build this!!</a>
</center>
<hr>
<h3 id="previouspostunittestcodecoverage">Previous Post : Unit Test Code Coverage</h3>
<p><a href="https://christophertown.com/orchestrating-vscode-test-code-coverage">https://christophertown.com/orchestrating-vscode-test-code-coverage</a></p>
</div>]]></content:encoded></item><item><title><![CDATA[Orchestrating Visual Studio Code : Part 6 : Unit Test Code Coverage]]></title><description><![CDATA[Running integration tests with docker containers.]]></description><link>http://christophertown.com/orchestrating-vscode-test-code-coverage/</link><guid isPermaLink="false">5aea04eb72e90b095ddfdf86</guid><category><![CDATA[VSCode]]></category><category><![CDATA[Orchestration]]></category><category><![CDATA[Docker]]></category><category><![CDATA[xUnit]]></category><category><![CDATA[lcov]]></category><category><![CDATA[Gulp]]></category><dc:creator><![CDATA[Christopher Town]]></dc:creator><pubDate>Wed, 02 May 2018 22:44:17 GMT</pubDate><media:content url="http://christophertown.com/content/images/2018/05/vscode-orchestration-banner-5.jpg" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="http://christophertown.com/content/images/2018/05/vscode-orchestration-banner-5.jpg" alt="Orchestrating Visual Studio Code : Part 6 : Unit Test Code Coverage"><p>We will learn how to add test code coverage reports using <code>xUnit</code>, <code>Gulp</code> and <code>Coverlet</code>, and <code>LCOV</code>.</p>
<h2 id="thefiles">The Files</h2>
<p>The following files will be created in this section:</p>
<pre><code class="language-bash">.
├── gulpfile.js
├── package.json
├── .coverage
</code></pre>
<h2 id="nodejs">NodeJS</h2>
<p>In order to use <code>Gulp</code>, you will need to have <a href="https://nodejs.org/en/">NodeJS</a> installed.</p>
<pre><code class="language-bash">brew install node
</code></pre>
<blockquote>
<p>Windows users can either load the installer from <a href="https://nodejs.org">https://nodejs.org</a> or use <a href="https://chocolatey.org">chocolatey</a> to install node.</p>
</blockquote>
<h2 id="gulp">Gulp</h2>
<p><a href="https://gulpjs.com">Gulp</a> is a toolkit for automating repetitive tasks in your development environment.</p>
<h3 id="installation">Installation</h3>
<p>To use gulp, we will need to initialize <code>npm</code> (Node Package Manager). Run the following in the root of your project:</p>
<pre><code class="language-bash">npm init
</code></pre>
<p>Then add <code>gulp</code> to your project:</p>
<pre><code class="language-bash">npm install gulp --save-dev
</code></pre>
<p>And the LCOV html report generator:</p>
<pre><code class="language-bash">npm install gulp-lcov-to-html --save-dev
</code></pre>
<blockquote>
<p>While we have tried to focus on VS Code's built-in task runner and local scripts throughout this series, sometimes you need to step out of the box and leverage node and gulp for heavier workloads.</p>
</blockquote>
<h3 id="thegulptask">The Gulp Task</h3>
<p>Create a file <code>gulpfile.js</code> in the root of your solution and add the following code:</p>
<pre><code class="language-javascript">const gulp = require('gulp')
const lcov = require('gulp-lcov-to-html')

gulp.task('generate-coverage-report', function () {

    return gulp
        .src(&quot;test/**/coverage.info&quot;) // grab the lcov files
        .pipe(lcov({
            name : &quot;My WebApp&quot;
        })) 
        .pipe(gulp.dest(&quot;.coverage&quot;)) // output to .coverage folder

});
</code></pre>
<center>
    <a href="https://github.com/christophla/blog-orchestrating-vscode/blob/part-6-xunit-code-coverage/gulpfile.js" target="_blank">gulpfile.js</a>
</center>
<br>
<blockquote>
<p>This task <code>generate-coverage-report</code> will look through the <code>test</code> folder for <code>coverage.info</code> files and generate an html report with them in the <code>.coverage</code> directory.</p>
</blockquote>
<h2 id="coverlet">Coverlet</h2>
<p><a href="https://github.com/tonerdo/coverlet">Coverlet</a> is a code coverage library for .NET Core, with support for line, branch, and method coverage. We will be using it in our test project to output coverage data in <code>lcov</code> format.</p>
<h3 id="installation">Installation</h3>
<p>In the root of <code>test/UnitTests</code>, run the following to install coverlet in your project:</p>
<pre><code class="language-bash">dotnet add package coverlet.msbuild --version 1.2.0
</code></pre>
<h3 id="thescripts">The Scripts</h3>
<p>We will add the following to our <code>unitTests()</code> method in <code>project-tasks.sh</code> to generate a coverage report when our tests run.</p>
<pre><code class="language-bash">unitTests () {

    for dir in test/*.UnitTests*/ ; do
        ...
        dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=lcov
        ...
    done
    
    ...
    
    gulp generate-coverage-report
}
</code></pre>
<center>
    <a href="https://github.com/christophla/blog-orchestrating-vscode/blob/part-6-xunit-code-coverage/scripts/project-tasks.sh#L89" target="_blank">project-tasks.sh</a>
</center>
<br>
<blockquote>
<p>The switches we added to <code>dotnet test</code> tell the test runner that we want to enable code coverage and output the results as <code>lcov</code>. We also call the gulp task that we created earlier to create the report.</p>
</blockquote>
<h2 id="runningthetests">Running the Tests</h2>
<p>Press F1 and run the <code>unit-tests</code> task. You will see output from our gulp task. Opening the report in a web browser will give you detailed results per project, namespace, and class.</p>
<pre><code class="language-bash">Calculating coverage result...
  Generating report 'C:\Users\CTown\AppDev\VSCode-Orchestration\test\UnitTests\coverage.info'

| Module   | Coverage |
|----------|----------|
   WebApp       0%
 
++++++++++++++++++++++++++++++++++++++++++++++++
+ Generating code-coverage html report
++++++++++++++++++++++++++++++++++++++++++++++++
[11:10:19] Using gulpfile ~\AppDev\VSCode-Orchestration\gulpfile.js
[11:10:19] Starting 'generate-coverage-report'...
[11:10:19] Finished 'generate-coverage-report' after 118 ms
++++++++++++++++++++++++++++++++++++++++++++++++
+ Report generated at:
+
+ /.coverage/index.html
++++++++++++++++++++++++++++++++++++++++++++++++
</code></pre>
<blockquote>
<p>Since we only have a simple smoke test that doesn't actually <strong>cover</strong> any of our application code - the <code>module</code> and <code>coverage</code> results will be empty. Go ahead and start writing some real unit tests and you will begin to see percentages.</p>
</blockquote>
<hr>
<h1 id="thesourcecode">The Source Code</h1>
<p>You can find the source code for this article in the following repository under the <code>part-6-xunit-code-coverage</code> branch:</p>
<p><a href="https://github.com/christophla/blog-orchestrating-vscode/tree/part-6-xunit-code-coverage" target="_blank">https://github.com/christophla/VSCode-Orchestration/tree/part-6-xunit-code-coverage</a></p>
<h2 id="nextpostdeployingnugetpackages">Next Post : Deploying NuGet Packages</h2>
<p>In the next post we will learn how to create a task to scan our solution for NuGet projects and deploy them to <code>nuget.org</code> and <code>myget.org</code>.</p>
<hr>
<center>
<a class="btn btn-red btn-sm" href="https://christophertown.com/orchestrating-vscode-nuget-deployment">Let's NuGet!</a>
</center>
<hr>
<h3 id="previouspostunittesting">Previous Post : Unit Testing</h3>
<p><a href="https://christophertown.com/orchestrating-vscode-unit-testing">https://christophertown.com/orchestrating-vscode-unit-testing</a></p>
</div>]]></content:encoded></item><item><title><![CDATA[Orchestrating Visual Studio Code : Part 5 : Unit Testing]]></title><description><![CDATA[Executing unit tests using VSCode tasks.]]></description><link>http://christophertown.com/orchestrating-vscode-unit-testing/</link><guid isPermaLink="false">5aea04ca72e90b095ddfdf85</guid><category><![CDATA[VSCode]]></category><category><![CDATA[Orchestration]]></category><category><![CDATA[Docker]]></category><category><![CDATA[xUnit]]></category><dc:creator><![CDATA[Christopher Town]]></dc:creator><pubDate>Wed, 02 May 2018 22:44:05 GMT</pubDate><media:content url="http://christophertown.com/content/images/2018/05/vscode-orchestration-banner-4.jpg" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="http://christophertown.com/content/images/2018/05/vscode-orchestration-banner-4.jpg" alt="Orchestrating Visual Studio Code : Part 5 : Unit Testing"><p>In this section, we will be automating unit tests with Visual Studio Code tasks.</p>
<hr>
<h2 id="xunit">XUnit</h2>
<p><a href="https://xunit.github.io">xUnit</a> is a lightweight test framework that is very popular in the .NET community. It supports extensions for <a href="https://en.wikipedia.org/wiki/Behavior-driven_development">BDD</a> with the <a href="http://xbehave.github.io">xBehave</a> library that can be very helpful in descibing tests with your <em>Product Team</em> as well as increased readability via syntax similar to <a href="https://github.com/cucumber/cucumber/wiki/Gherkin"><em>Gherkin</em></a> notation.</p>
<hr>
<h2 id="gitlens">GitLens</h2>
<p><a href="https://github.com/eamodio/vscode-gitlens">GitLense</a> is a Visual Studio Code plugin that gives insights into your underlying git repository (similar to CodeLens) as well as providing test run/debug links throughtout your code.</p>
<h2 id="yourfirsttest">Your First Test</h2>
<p>We will be creating a test project, adding the xUnit and xBehave NuGet packages, and wiring it up to a VSCode <code>task</code> so that we can run it from the IDE.</p>
<h3 id="thetestproject">The Test Project</h3>
<p>We are going to add a new top-level folder <code>/test/UnitTests</code> to hold your solution's tests. Navigate your shell to that folder and create a project.</p>
<pre><code class="language-bash">mkdir -p test/UnitTests
cd test/UnitTests
dotnet new classlib
</code></pre>
<p>We need to switch the project from <code>netstandard2.0</code> to <code>netcoreapp2.0</code> to support the xunit dotnet cli integration. Change the following in <code>UnitTests.csproj</code>:</p>
<pre><code class="language-xml">&lt;PropertyGroup&gt;
    &lt;TargetFramework&gt;netcoreapp2.0&lt;/TargetFramework&gt;
&lt;/PropertyGroup&gt;
</code></pre>
<p>Make sure to add the new test project to our solution. Run the following from the root of the project:</p>
<pre><code class="language-bash">dotnet sln add test/UnitTests/UnitTests.csproj
</code></pre>
<hr>
<h3 id="addingtestpackages">Adding Test Packages</h3>
<p>Within the <code>./test/UnitTests</code> directoy, we will add xUnit...</p>
<pre><code class="language-bash">dotnet add package xunit --version 2.3.1
dotnet add package xunit.runner.visualstudio --version 2.3.1
</code></pre>
<p>... and then add the xunit cli tool to the <code>UnitTests.csproj</code>:</p>
<pre><code class="language-xml">&lt;ItemGroup&gt;
    &lt;DotNetCliToolReference Include=&quot;dotnet-xunit&quot; Version=&quot;2.3.1&quot; /&gt;
&lt;/ItemGroup&gt;
</code></pre>
<blockquote>
<p>The OmniSharp extension we loaded earlier will prompt to <code>Restore Packages</code>. This will pull the binaries down from NuGet into your local test project.</p>
</blockquote>
<hr>
<h3 id="creatingasmoketest">Creating a Smoke Test</h3>
<p>We are going to create a simple smoke test for this example:</p>
<pre><code class="language-bash">└── test
    └── UnitTests
        ├── SmokeTest.cs
        ├── UnitTests.csproj
</code></pre>
<pre><code class="language-csharp">using Xunit;

namespace UnitTests
{
    public class SmokeTest
    {
        [Fact]
        public void CanAssertTrue()
        {
            Assert.True(true, &quot;Our first test!&quot;);
        }
    }
}
</code></pre>
<center>
    <a href="https://github.com/christophla/blog-orchestrating-vscode/blob/part-6-xunit-code-coverage/gulpfile.js" target="_blank">TODO</a>
</center>
<br>
<blockquote>
<p>From time to time, OmniSharp will hang when loading new packages. If you aren't seeing intellisense, press F1 and select <code>Reload Window</code>. This will reset the analysis engine.</p>
</blockquote>
<hr>
<h3 id="theunittesttask">The Unit Test Task</h3>
<p>We are now going to add a new tasks to our <code>.vcode/tasks.json</code> file:</p>
<pre><code class="language-json">{
    &quot;label&quot;: &quot;unit-tests&quot;,
    &quot;type&quot;: &quot;shell&quot;,
    &quot;group&quot;: {
        &quot;kind&quot;: &quot;test&quot;,
        &quot;isDefault&quot;: true
    },
    &quot;osx&quot;: {
        &quot;command&quot;: &quot;bash ./scripts/project-tasks.sh unitTests&quot;
    },
    &quot;presentation&quot;: {
        &quot;echo&quot;: true,
        &quot;reveal&quot;: &quot;always&quot;,
        &quot;focus&quot;: true,
        &quot;panel&quot;: &quot;dedicated&quot;
    },
    &quot;problemMatcher&quot;: [],
    &quot;windows&quot;: {
        &quot;command&quot;: &quot;.\\scripts\\project-tasks.ps1 -UnitTests&quot;
    }
}
</code></pre>
<center>
    <a href="https://github.com/christophla/blog-orchestrating-vscode/blob/part-5-unit-testing/.vscode/tasks.json#L48" target="_blank">tasks.json</a>
</center>
<hr>
<h3 id="theunittestscript">The Unit Test Script</h3>
<p>The task will call the <code>unitTests()</code> method in the <code>scripts/project-tasks.sh</code> file which iterates over the projects under the <code>/test</code> directory and executes <code>dotnet test</code> for folders with <code>UnitTests</code> in their name.</p>
<pre><code class="language-bash"># #############################################################################
# Runs the unit tests.
#
unitTests () {

    echo -e &quot;${GREEN}&quot;
    echo -e &quot;++++++++++++++++++++++++++++++++++++++++++++++++&quot;
    echo -e &quot;+ Running unit tests                            &quot;
    echo -e &quot;++++++++++++++++++++++++++++++++++++++++++++++++&quot;
    echo -e &quot;${RESTORE}&quot;

    for dir in test/*UnitTests*/ ; do
        [ -e &quot;$dir&quot; ] || continue
        dir=${dir%*/}
        echo -e &quot;Found tests in: test/${dir##*/}&quot;
        cd $dir
        dotnet test 
        rtn=$?
        if [ &quot;$rtn&quot; != &quot;0&quot; ]; then            
            echo -e &quot;${RED}An error occurred${RESTORE}&quot;
            exit $rtn
        fi
    done

}
</code></pre>
<center>
    <a href="https://github.com/christophla/blog-orchestrating-vscode/blob/part-5-unit-testing/scripts/project-tasks.sh#L89" target="_blank">project-tasks.sh</a>
</center>
<br>
<hr>
<h3 id="runningyourtests">Running Your Tests</h3>
<p>At this point, press F1 and run the task <code>unit-tests</code>. You should see the following output:</p>
<pre><code class="language-bash">++++++++++++++++++++++++++++++++++++++++++++++++
+ Running unit tests
++++++++++++++++++++++++++++++++++++++++++++++++

Found: test/UnitTests
Build started, please wait...
Build completed.

Test run for /VSCode-Orchestration/test/UnitTests/bin/Debug/netcoreapp2.0/UnitTests.dll(.NETCoreApp,Version=v2.0)
Microsoft (R) Test Execution Command Line Tool Version 15.6.0-preview-20180109-01
Copyright (c) Microsoft Corporation.  All rights reserved.

Starting test execution, please wait...
[xUnit.net 00:00:00.6418600]   Discovering: UnitTests
[xUnit.net 00:00:00.7619690]   Discovered:  UnitTests
[xUnit.net 00:00:00.7693280]   Starting:    UnitTests
[xUnit.net 00:00:00.9738810]   Finished:    UnitTests

Total tests: 1. Passed: 1. Failed: 0. Skipped: 0.
Test Run Successful.
Test execution time: 2.0896 Seconds
</code></pre>
<hr>
<h2 id="debuggingyourtest">Debugging Your Test</h2>
<h3 id="installinggitlense">Installing GitLense</h3>
<p>We will now load the <code>GitLense</code> extension to allow running and debugging individual tests. Open the extensions menu on the left panel and search for <code>GitLense</code> to install it.</p>
<h3 id="runninganddebuggingasingletest">Running and Debugging a single test</h3>
<p>Once GitLense is loaded, you will see gray annotations above your classes and methods. If the method is a [Test], [Fact], [Scenario], or any other attribute designating a testable mehtod, you will see two options, <code>run test</code> and <code>debug test</code>.</p>
<p><img src="http://christophertown.com/content/images/2018/05/gitlense-annotations.png" alt="Orchestrating Visual Studio Code : Part 5 : Unit Testing"></p>
<blockquote>
<p>GitLense also provides insights into your git repository blame logs. You can see <strong>what time</strong> and <strong>which team member</strong> last updated each line of code. This is very simlar to Visual Studio's CodeLense feature (but free!).</p>
</blockquote>
<hr>
<h1 id="conclusion">Conclusion</h1>
<p>We learned how to wire-up multiple unit test projects to run within VS Code.</p>
<hr>
<h1 id="thesourcecode">The Source Code</h1>
<p>You can find the source code for this article in the following repository under the <code>part-5-unit-testing</code> branch:</p>
<p><a href="https://github.com/christophla/blog-orchestrating-vscode/tree/part-5-unit-testing" target="_blank">https://github.com/christophla/VSCode-Orchestration/tree/part-5-unit-testing</a></p>
<hr>
<h2 id="nextpostcodecoverage">Next Post : Code Coverage</h2>
<p>In the next post we will learn how to add code coverage reports to our test runs with <code>gulp</code> and <code>lcov</code>.</p>
<hr>
<center>
<a class="btn btn-sm" href="https://christophertown.com/orchestrating-vscode-test-code-coverage">Let's add code coverage!</a>
</center>
<hr>
<h3 id="previouspostrunningdockercontainers">Previous Post : Running Docker Containers</h3>
<p><a href="https://christophertown.com/orchestrating-vscode-running-docker-containers">https://christophertown.com/orchestrating-vscode-running-docker-containers</a></p>
</div>]]></content:encoded></item><item><title><![CDATA[Orchestrating Visual Studio Code : Part 4 :  Running Docker Containers]]></title><description><![CDATA[Learn to configure multiple runtime settings to allow combinations of local and container debugging.]]></description><link>http://christophertown.com/orchestrating-vscode-running-docker-containers/</link><guid isPermaLink="false">5aea049672e90b095ddfdf84</guid><category><![CDATA[VSCode]]></category><category><![CDATA[Orchestration]]></category><category><![CDATA[Docker]]></category><dc:creator><![CDATA[Christopher Town]]></dc:creator><pubDate>Wed, 02 May 2018 22:43:50 GMT</pubDate><media:content url="http://christophertown.com/content/images/2018/05/vscode-orchestration-banner-3.jpg" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="http://christophertown.com/content/images/2018/05/vscode-orchestration-banner-3.jpg" alt="Orchestrating Visual Studio Code : Part 4 :  Running Docker Containers"><p>Previously, in part 3, we learned how to debug a container running in docker. In this section, we will learn how to run our containerized application without the debugger.</p>
<blockquote>
<p>Unfortunately at this time, the <code>vsdbg</code> debugger for Visual Studio Code does not support attaching to a running process remotely. Instead, it listens for commands to start the application and, as a result, your docker application will not run without it.</p>
</blockquote>
<h2 id="containerappsettings">Container AppSettings</h2>
<p>Make a copy of your <code>appsettings.json</code> file and call it <code>appsettings.container.json</code>. This file will be used <em>exclusively</em> when the application runs inside of docker.</p>
<pre><code class="language-bash">└───src
    │   appsettings.container.json
    │   appsettings.development.json
    │   appsettings.json
    │   Program.cs
    │   Startup.cs
    │   WebApp.csproj
</code></pre>
<center>
    <a href="https://github.com/christophla/blog-orchestrating-vscode/tree/part-4-running-containers" target="_blank">source</a>
</center>
<br>
<blockquote>
<p>For now we will leave it alone, but in a future post I will show you how to leverage this file to perform cross-container communications between multiple microservices.</p>
</blockquote>
<h2 id="composemethod">Compose Method</h2>
<p>We will be leveraging the <code>compose</code> method we created earlier to add a new switch that <strong>does not</strong> set the <code>REMOTE_DEBUGGING</code> environment variable. This will cause the <code>Dockerfile</code> entrypoint to fire up the application instead of waiting for debug commands.</p>
<pre><code class="language-docker">ENTRYPOINT [&quot;/bin/bash&quot;, &quot;-c&quot;, &quot;if [ \&quot;$REMOTE_DEBUGGING\&quot; = \&quot;enabled\&quot; ]; then sleep infinity; else dotnet WebApp.dll; fi&quot;]
</code></pre>
<hr>
<pre><code class="language-bash">case &quot;$1&quot; in
    &quot;clean&quot;)
        clean
        ;;
    &quot;compose&quot;)
        compose
        ;;
    &quot;composeForDebug&quot;)
        export REMOTE_DEBUGGING=&quot;enabled&quot;
        compose
        ;;
    *)
        showUsage
        ;;
esac
</code></pre>
<center>
    <a href="https://github.com/christophla/blog-orchestrating-vscode/blob/part-4-running-containers/scripts/project-tasks.sh" target="_blank">project-tasks.sh</a>
</center>
<hr>
<h2 id="composetask">Compose Task</h2>
<p>We will add a new task to <code>.vscode/tasks.json</code> that will call our <code>compose()</code> method in the <code>project-tasks.sh</code> script.</p>
<pre><code class="language-json">{
    &quot;label&quot;: &quot;compose&quot;,
    &quot;type&quot;: &quot;shell&quot;,
    &quot;group&quot;: {
        &quot;kind&quot;: &quot;build&quot;,
        &quot;isDefault&quot;: true
    },
    &quot;osx&quot;: {
        &quot;command&quot;: &quot;bash ./scripts/project-tasks.sh compose&quot;
    },
    &quot;presentation&quot;: {
        &quot;echo&quot;: true,
        &quot;reveal&quot;: &quot;always&quot;,
        &quot;focus&quot;: true,
        &quot;panel&quot;: &quot;dedicated&quot;
    },
    &quot;problemMatcher&quot;: [],
    &quot;windows&quot;: {
        &quot;command&quot;: &quot;.\\scripts\\project-tasks.ps1 -Compose&quot;
    }
}
</code></pre>
<center>
    <a href="https://github.com/christophla/blog-orchestrating-vscode/blob/part-4-running-containers/.vscode/tasks.json#L14" target="_blank">tasks.json</a>
</center>
<hr>
<h2 id="runningourtask">Running our Task</h2>
<p>At this point, press F1, select <code>Tasks: Run Task</code>, and select <code>compose</code>. Your docker container will build and run without a debugger attached. You will need to manually open your web browser to view the application at: <a href="http://localhost:5000/api/values">http://localhost:5000/api/values</a></p>
<h2 id="conclusion">Conclusion</h2>
<p>We have learned how to compose and run our docker container without attaching a debugger.</p>
<hr>
<h2 id="sourcecode">Source Code</h2>
<p><a href="https://github.com/christophla/blog-orchestrating-vscode/tree/part-4-running-containers" target="_blank">https://github.com/christophla/blog-orchestrating-vscode/tree/part-4-running-containers</a></p>
<hr>
<h2 id="nextpostunittests">Next Post : Unit Tests</h2>
<p>In the next post we will learn how to create a unit test project and a VS Code task to run them. We will also explore the <code>GitLense</code> extension to support running and debugging individual tests from within the IDE.</p>
<hr>
<center>
<a class="btn btn-red btn-sm" href="https://christophertown.com/orchestrating-vscode-unit-testing">Let's write some tests!</a>
</center>
<hr>
<h3 id="previouspostdebuggingdockercontainers">Previous Post : Debugging Docker Containers</h3>
<p><a href="https://christophertown.com/orchestrating-vscode-debugging-docker">https://christophertown.com/orchestrating-vscode-debugging-docker</a></p>
</div>]]></content:encoded></item><item><title><![CDATA[Orchestrating Visual Studio Code : Part 3 : Debugging Docker Containers]]></title><description><![CDATA[Everything needed to remotely debug your microservices from within the docker environment using Visual Studio Code.]]></description><link>http://christophertown.com/orchestrating-vscode-debugging-docker/</link><guid isPermaLink="false">5ae9fd4072e90b095ddfdf83</guid><category><![CDATA[VSCode]]></category><category><![CDATA[Orchestration]]></category><category><![CDATA[Docker]]></category><dc:creator><![CDATA[Christopher Town]]></dc:creator><pubDate>Wed, 02 May 2018 21:01:21 GMT</pubDate><media:content url="http://christophertown.com/content/images/2018/05/vscode-orchestration-banner-2.jpg" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="http://christophertown.com/content/images/2018/05/vscode-orchestration-banner-2.jpg" alt="Orchestrating Visual Studio Code : Part 3 : Debugging Docker Containers"><p>When working with multiple microservices, it is important to be able to run a debugger inside the docker container. In this article, we will learn how to load <code>vsdbg</code> - the Visual Studio Debugger - inside of a docker image and attach to it using VS Code's launchers.</p>
<h2 id="thefiles">The Files</h2>
<p>The following files will be created in this section:</p>
<pre><code class="language-bash">.
├── Dockerfile
├── docker-compose.yml
├── scripts
    ├── project-tasks.ps1
    └── project-tasks.sh
</code></pre>
<center>
    <a href="https://github.com/christophla/blog-orchestrating-vscode/tree/part-3-debugging-docker" target="_blank">Source</a>
</center>
<hr>
<h2 id="thedockerfile">The Dockerfile</h2>
<p>We are using a multi-stage dockerfile to load a base image containing the Visual Studio Code debugger with the following steps:</p>
<ul>
<li>Create a base image layer from <code>aspnetcore2.0</code>.</li>
<li>Download the VSCode debugger <code>vsdbg</code>.</li>
<li>Create a build image layer from <code>aspnetcore-build</code>.</li>
<li>Copy the contents of the web project WebProject.</li>
<li>Publish the web project into <code>/publish</code> folder.</li>
<li>Create a production layer from the base layer.</li>
<li>Copy the <code>/publish</code> folder contents into the production layer.</li>
</ul>
<p>The <code>ENTRYPOINT</code> for the dockerfile serves dual purposes:</p>
<ul>
<li>Run the application normally.</li>
<li>If the <code>ENABLE_DEBUGGING</code> environmental variable is set, <code>sleep</code> the application and listen for debug commands</li>
</ul>
<pre><code class="language-yaml"># #############################################################################
# Development docker image with support for Visual Studio debugging integration
#

# #############################################################################
# BASE IMAGE
FROM microsoft/aspnetcore:2.0 AS base
WORKDIR /app
EXPOSE 80

# vscode debugging support
WORKDIR /vsdbg
RUN apt-get update \
    &amp;&amp; apt-get install -y --no-install-recommends \
        unzip \
    &amp;&amp; rm -rf /var/lib/apt/lists/* \
    &amp;&amp; curl -sSL https://aka.ms/getvsdbgsh | bash /dev/stdin -v latest -l /vsdbg


# #############################################################################
# BUILDER IMAGE
FROM microsoft/aspnetcore-build:2.0 AS builder
ENV NUGET_XMLDOC_MODE skip

# publish
COPY . /app
WORKDIR /app/src
RUN dotnet publish -f netcoreapp2.0 -r debian.8-x64 -c Debug -o /publish -v quiet


# #############################################################################
# PRODUCTION IMAGE
FROM base AS production
WORKDIR /app
COPY --from=builder /publish .

# Kick off a container just to wait debugger to attach and run the app
ENTRYPOINT [&quot;/bin/bash&quot;, &quot;-c&quot;, &quot;if [ \&quot;$REMOTE_DEBUGGING\&quot; = \&quot;enabled\&quot; ]; then sleep infinity; else dotnet WebProject.dll; fi&quot;]

# #############################################################################
</code></pre>
<center>
    <a href="https://github.com/christophla/blog-orchestrating-vscode/blob/part-3-debugging-docker/Dockerfile" target="_blank">Dockerfile</a>
</center>
<hr>
<h2 id="thedockercomposefile">The docker-compose file</h2>
<p>The docker-compose file contains a single service for creating the docker container.<br>
The REMOTE_DEBUGGING variable is set via a VSCode pre-launch task.</p>
<pre><code class="language-yaml">version: '3'

services:

  docker-debug-webapp:
    container_name: docker-debug-webapp
    image: docker-debug-webapp
    build: 
      context: .
      dockerfile: Dockerfile
    environment:
      - ASPNETCORE_ENVIRONMENT=development
      - REMOTE_DEBUGGING=${REMOTE_DEBUGGING}
    ports:
      - &quot;5000:80&quot;
    networks:
      - dev-network
    tty: true
    stdin_open: true

networks:
  dev-network:
    driver: bridge
</code></pre>
<center>
    <a href="https://github.com/christophla/blog-orchestrating-vscode/blob/part-3-debugging-docker/docker-compose.yml" target="_blank">docker-compose.yml</a>
</center>
<hr>
<h2 id="thesetupscripts">The setup scripts</h2>
<p>The setup scripts <code>project-tasks.sh</code> and <code>project-tasks.ps1</code> are used to build and compose the container before launching the debugger.</p>
<pre><code>.
├── scripts
│   ├── project-tasks.ps1
│   └── project-tasks.sh
</code></pre>
<blockquote>
<p>We will be using the <code>bash</code> <code>project-tasks.sh</code> script for this exercise. If you are on windows, a <code>PowerShell</code> <code>project-tasks.ps</code> script is provided in the GitHub source.</p>
</blockquote>
<h3 id="thecomposehelpermethod">The compose() helper method</h3>
<p>The <code>compose()</code> method is called by the task to stage your container. It supports multiple <code>docker.{environment}.yml</code> files. The default is <code>docker-compose.yml</code>.</p>
<pre><code class="language-bash">compose () {

    echo -e &quot;${GREEN}&quot;
    echo -e &quot;++++++++++++++++++++++++++++++++++++++++++++++++&quot;
    echo -e &quot;+ Composing docker images                       &quot;
    echo -e &quot;++++++++++++++++++++++++++++++++++++++++++++++++&quot;
    echo -e &quot;${RESTORE}&quot;

    if [[ -z $ENVIRONMENT ]]; then
        ENVIRONMENT=&quot;debug&quot;
    fi

    composeFileName=&quot;docker-compose.yml&quot;
    if [[ $ENVIRONMENT != &quot;debug&quot; ]]; then
        composeFileName=&quot;docker-compose.$ENVIRONMENT.yml&quot;
    fi

    if [[ ! -f $composeFileName ]]; then
        echo -e &quot;${RED} $ENVIRONMENT is not a valid parameter. File '$composeFileName' does not exist. ${RESTORE}\n&quot;
    else

        echo -e &quot;${YELLOW} Building the image $imageName ($ENVIRONMENT). ${RESTORE}\n&quot;
        docker-compose -f &quot;$composeFileName&quot; build

        echo -e &quot;${YELLOW} Creating the container $imageName ${RESTORE}\n&quot;
        docker-compose -f $composeFileName kill
        docker-compose -f $composeFileName up -d
    fi
}

...

case &quot;$1&quot; in
    &quot;composeForDebug&quot;)
        export REMOTE_DEBUGGING=&quot;enabled&quot;
        compose
        ;;
    *)
        showUsage
        ;;
esac
</code></pre>
<center>
    <a href="https://github.com/christophla/blog-orchestrating-vscode/blob/part-3-debugging-docker/scripts/project-tasks.sh" target="_blank">project-tasks.sh</a>
</center>
<br>
<blockquote>
<p>Note the <code>export REMOTE_DEBUGGING</code> environmental variable. It is being set so that docker-compose can pass it to the Dockerfile's <code>ENTRYPOINT</code>. This will pause the container so that it can listen for <code>vsdbg</code> debugging commands from the IDE. It also allows us to use the <code>compose()</code> method to run our containers without debugging enabled.</p>
</blockquote>
<hr>
<h2 id="thevscodetask">The VSCode Task</h2>
<p>The Visual Studio Code tasks.json is used to link the setup scripts.<br>
Links to the Windows PowerShell and OSX/Linux Bash scripts. It is used to create our docker image and container:</p>
<ul>
<li>Creates the image.</li>
<li>Kills any running instances.</li>
<li>Starts the container.</li>
</ul>
<p>Add the following to your <code>.vscode/tasks.json</code>:</p>
<pre><code class="language-json">{
    &quot;label&quot;: &quot;compose-for-debug&quot;,
    &quot;type&quot;: &quot;shell&quot;,
    &quot;osx&quot;: {
        &quot;command&quot;: &quot;bash ./scripts/project-tasks.sh composeForDebug&quot;
    },
    &quot;presentation&quot;: {
        &quot;echo&quot;: true,
        &quot;reveal&quot;: &quot;always&quot;,
        &quot;focus&quot;: true,
        &quot;panel&quot;: &quot;dedicated&quot;
    },
    &quot;problemMatcher&quot;: [],
    &quot;windows&quot;: {
        &quot;command&quot;: &quot;.\\scripts\\project-tasks.ps1 -ComposeForDebug&quot;
    }
}
</code></pre>
<center>
    <a href="https://github.com/christophla/blog-orchestrating-vscode/blob/part-3-debugging-docker/.vscode/tasks.json" target="_blank">tasks.json</a>
</center>
<hr>
<h2 id="thevscodelauncher">The VSCode Launcher</h2>
<p>The Visual Studio Code launch.json orchestrates the application with the following settings:</p>
<ul>
<li>Configures apreLaunchTask called compose-for-debug to build and compose the docker container.</li>
<li>Sets the REMOTE_DEBUGGING env variable to allow the container debugger vsdbg to listen for commands.</li>
<li>Configures the pipeTransport with the path /vsdgb/vsdbgto the debugger within the container and the command docker and args exec -i <image-name> that should be executed to begin debugging.</image-name></li>
<li>Sets the sourceFileMap to allow breakpoints on the local filesystem to line-up with the compiled source in the container.</li>
</ul>
<pre><code class="language-json">{
    &quot;version&quot;: &quot;0.2.0&quot;,
    &quot;configurations&quot;: [
        {
            &quot;name&quot;: &quot;Docker Launch&quot;,
            &quot;type&quot;: &quot;coreclr&quot;,
            &quot;request&quot;: &quot;launch&quot;,
            &quot;preLaunchTask&quot;: &quot;compose-for-debug&quot;,
            &quot;cwd&quot;: &quot;/app&quot;,
            &quot;program&quot;: &quot;/app/WebApp.dll&quot;,
            &quot;env&quot;: {
                &quot;ASPNETCORE_ENVIRONMENT&quot;: &quot;development&quot;,
                &quot;REMOTE_DEBUGGING&quot;: &quot;true&quot;
            },
            &quot;sourceFileMap&quot;: {
                &quot;/app&quot;: &quot;${workspaceRoot}&quot;
            },
            &quot;launchBrowser&quot;: {
                &quot;enabled&quot;: true,
                &quot;args&quot;: &quot;http://localhost:5000/api/values&quot;,
                &quot;windows&quot;: {
                    &quot;command&quot;: &quot;cmd.exe&quot;,
                    &quot;args&quot;: &quot;/C start http://localhost:5000/api/values&quot;
                },
                &quot;osx&quot;: {
                    &quot;command&quot;: &quot;open&quot;
                }
            },
            &quot;pipeTransport&quot;: {
                &quot;debuggerPath&quot;: &quot;/vsdbg/vsdbg&quot;,
                &quot;pipeProgram&quot;: &quot;docker&quot;,
                &quot;pipeCwd&quot;: &quot;${workspaceRoot}&quot;,
                &quot;pipeArgs&quot;: [
                    &quot;exec -i docker-debug-webapp&quot;
                ],
                &quot;quoteArgs&quot;: false
            }
        }
    ]
}
</code></pre>
<center>
    <a href="https://github.com/christophla/blog-orchestrating-vscode/blob/part-3-debugging-docker/.vscode/launch.json" target="_blank">launch.json</a>
</center>
<hr>
<h2 id="debuggingyourapp">Debugging Your App</h2>
<p>At this point, you should be able to run the debug task from within VSCode. Press F1, select <code>Run Tasks</code>, and select <code>compose-for-debug</code>. You application will start with a debugger attached.</p>
<hr>
<h2 id="composingwithoutdebug">Composing Without Debug</h2>
<p>I've included an additional task <code>compose</code> that allows you to run your docker container without the debugger attached. This is useful in microservice environments where you want to run several services to work against.</p>
<p>In a later post, I'll be showing how you can orchestrate a large number of microservices using VSCode workspaces and the <code>compose</code> task.</p>
<h1 id="thesourcecode">The Source Code</h1>
<p>You can find the source code for this article in the following repository under the <code>part-2-tasks-and-launchers</code> branch:</p>
<p><a href="https://github.com/christophla/blog-orchestrating-vscode/tree/part-3-debugging-docker" target="_blank">https://github.com/christophla/blog-orchestrating-vscode/tree/part-3-debugging-docker</a></p>
<h2 id="nextpostrunningdockercontainers">Next Post : Running Docker Containers</h2>
<p>In the next post we will learn how to run stand-along docker container without the debugger attached. This is useful when orchestrating several dependent microservices in a large application.</p>
<hr>
<center>
<a class="btn btn-sm" href="https://christophertown.com/orchestrating-vscode-running-docker-containers">Let's run some containers!</a>
</center>
<hr>
<h3 id="previousposttasksandlaunchers">Previous Post : Tasks and Launchers</h3>
<p><a href="https://christophertown.com/orchestrating-vscode-tasks-and-launchers">https://christophertown.com/orchestrating-vscode-tasks-and-launchers</a></p>
</div>]]></content:encoded></item></channel></rss>