<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Corey Lasley</title>
    <description>The latest articles on DEV Community by Corey Lasley (@coreylasley).</description>
    <link>https://dev.to/coreylasley</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F323652%2Fd0b7d5f6-f817-4391-9fa4-d8cd803d5051.jpeg</url>
      <title>DEV Community: Corey Lasley</title>
      <link>https://dev.to/coreylasley</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/coreylasley"/>
    <language>en</language>
    <item>
      <title>Client Side Load Balancing External REST Calls with Java and Spring Boot</title>
      <dc:creator>Corey Lasley</dc:creator>
      <pubDate>Fri, 14 May 2021 00:51:42 +0000</pubDate>
      <link>https://dev.to/coreylasley/client-side-load-balancing-external-rest-calls-with-java-and-spring-boot-hi8</link>
      <guid>https://dev.to/coreylasley/client-side-load-balancing-external-rest-calls-with-java-and-spring-boot-hi8</guid>
      <description>&lt;h4&gt;
  
  
  Targets
&lt;/h4&gt;

&lt;p&gt;Java 8+, Spring Boot 5, Any Client Side Framework such as Angular/React/Vue/etc.&lt;/p&gt;

&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;As uncommon of a need as it may be, there may come a time where you are required to write an application that makes various calls to an external REST API / microservice that exists in multiple locations for the purpose of high availability.  Because there are multiple instances of the service running, it just doesn't seem right to configure your application with a proxy that only hits one of the multiple endpoints, thus making calls to the service in a load balanced manner might be your ultimate goal. &lt;/p&gt;

&lt;p&gt;There are likely better ways of load balancing service calls in the enterprise, such as through load balancing hardware, or an implementation of a GSLB (Global Server Load Balancer) product such as &lt;a href="https://www.nginx.com/products/nginx/load-balancing/" rel="noopener noreferrer"&gt;NGINX&lt;/a&gt;. However with that being said, the need may arise where your application is required to perform this task without the extra expenses and/or additional potential points of failure.&lt;/p&gt;

&lt;p&gt;If you are not familiar with setting up a Spring Boot application, and/or want more background into where I found my inspiration, I strongly encourage you to go through the &lt;a href="https://spring.io/guides/gs/spring-cloud-loadbalancer/" rel="noopener noreferrer"&gt;Client-Side Load-Balancing with Spring Cloud LoadBalancer&lt;/a&gt; guide, before continuing on. &lt;/p&gt;

&lt;h4&gt;
  
  
  When a Proxy Isn't Enough
&lt;/h4&gt;

&lt;p&gt;As a secondary need, when it comes to consuming an external API from a browser based application, is the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" rel="noopener noreferrer"&gt;Cross-Origin Resource Sharing (CORS)&lt;/a&gt; &lt;em&gt;issue&lt;/em&gt; which occurs when a browser detects that a call is being made to an API that exists on a different domain. This can be solved by including &lt;em&gt;Access-Control-Allow-Origin&lt;/em&gt; in the response header of the service; but, for the sake of this exercise, we are going to suppose that we either cannot, or do not want, to make this change within the service code. &lt;/p&gt;

&lt;p&gt;With Spring Boot, one can use the &lt;a href="https://spring.io/guides/gs/routing-and-filtering/" rel="noopener noreferrer"&gt;Netflix Zuul&lt;/a&gt; Proxy to get around this issue, which is extraordinarily easy to configure. Unfortunately, you are going to be limited to consuming a single configured endpoint. If you do some more research, you will undoubtedly come across the Netflix Ribbon, which has much more promise in getting us to where we need to be, but is substantially more complex to setup than a Zuul Proxy, and even more disappointing, you will come to find out that Ribbon has officially been deprecated.&lt;/p&gt;

&lt;h4&gt;
  
  
  Spring Cloud LoadBalancer
&lt;/h4&gt;

&lt;p&gt;Enter &lt;em&gt;Spring Cloud LoadBalancer&lt;/em&gt;, which picks up where the &lt;a href="https://cloud.spring.io/spring-cloud-netflix/multi/multi_spring-cloud-ribbon.html" rel="noopener noreferrer"&gt;Netflix Ribbon&lt;/a&gt; left off, and in fact it actually uses Ribbon under the hood. The official Spring site has some good information on how one can use LoadBalancer in the aforementioned guide: &lt;a href="https://spring.io/guides/gs/spring-cloud-loadbalancer/" rel="noopener noreferrer"&gt;Client-Side Load-Balancing with Spring Cloud LoadBalancer&lt;/a&gt;, from which I base our solution. &lt;/p&gt;

&lt;p&gt;Spring's guide comes pretty close, but doesn't really address our exact need. That is, what we ultimately need to be able to do: Intercept &lt;em&gt;all&lt;/em&gt; API calls being made from our client application running in Spring Boot (gets, posts, puts, and deletes), and redirect them under the hood, in a load balanced manner, to several different external endpoints, without having to define each specific API call.&lt;/p&gt;

&lt;h4&gt;
  
  
  Our Scenario
&lt;/h4&gt;

&lt;p&gt;We have a client application (lets say Angular) with a service that communicates with a RESTful service that exists at multiple endpoints for high-availability. We do not want our application to simply be configured to hit just one of these endpoints, so we are going to use Spring Boot to take advantage of the Spring Cloud LoadBalancer. Lets say that we have 3 external endpoints which host the API(s) that we want to be able to consume in our application:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://myservice.host1.com" rel="noopener noreferrer"&gt;https://myservice.host1.com&lt;/a&gt;, &lt;a href="https://myservice.host2.com" rel="noopener noreferrer"&gt;https://myservice.host2.com&lt;/a&gt;, &lt;a href="https://myservice.host3.com" rel="noopener noreferrer"&gt;https://myservice.host3.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We want our client application to call the APIs via the "&lt;em&gt;/api&lt;/em&gt;" path, as if these endpoints existed within our app. Therefore when calls are made, such as "&lt;em&gt;/api/getthis&lt;/em&gt;" or "&lt;em&gt;/api/savethat&lt;/em&gt;" we will have our Java Spring Boot application, that lives in the same space as our client application, intercept and redirect those calls to one of the 3 external endpoints. The following demonstrates one way that you can set this up.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.coreylasley.com%2Fimg%2Fimage-20210513195524055.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.coreylasley.com%2Fimg%2Fimage-20210513195524055.png" alt="image-20210513195524055"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up the Java Spring Boot Load Balancer
&lt;/h3&gt;

&lt;p&gt;After having setup your Spring Boot application (which is easy to do &lt;a href="https://start.spring.io/" rel="noopener noreferrer"&gt;here&lt;/a&gt;), go to your main application class, which for my example, I have named &lt;strong&gt;LBExampleApplication&lt;/strong&gt;, and make sure it contains the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.lb.example&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;lombok.extern.slf4j.Slf4j&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.boot.SpringApplication&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.boot.autoconfigure.SpringBootApplication&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.cloud.client.loadbalancer.reactive.ReactorLoadBalancerExchangeFilterFunction&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.http.HttpHeaders&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.http.MediaType&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.web.bind.annotation.RequestMapping&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.web.bind.annotation.RestController&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.web.reactive.function.client.WebClient&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;reactor.core.CoreSubscriber&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;reactor.core.publisher.Mono&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;javax.servlet.http.HttpServletRequest&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.io.IOException&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.Enumeration&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.stream.Collectors&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@Slf4j&lt;/span&gt;
&lt;span class="nd"&gt;@SpringBootApplication&lt;/span&gt;
&lt;span class="nd"&gt;@RestController&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LBExampleApplication&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;WebClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Builder&lt;/span&gt; &lt;span class="n"&gt;loadBalancedWebClientBuilder&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
   &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ReactorLoadBalancerExchangeFilterFunction&lt;/span&gt; &lt;span class="n"&gt;lbFunction&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

   &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;LBExampleApplication&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;WebClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Builder&lt;/span&gt; &lt;span class="n"&gt;webClientBuilder&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                           &lt;span class="nc"&gt;ReactorLoadBalancerExchangeFilterFunction&lt;/span&gt; &lt;span class="n"&gt;lbFunction&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;loadBalancedWebClientBuilder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;webClientBuilder&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lbFunction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lbFunction&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
   &lt;span class="o"&gt;}&lt;/span&gt;

   &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="nc"&gt;SpringApplication&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LBExampleApplication&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
   &lt;span class="o"&gt;}&lt;/span&gt;

   &lt;span class="nd"&gt;@RequestMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"/api/*"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
   &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Mono&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;balanceIt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpServletRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;IOException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="nc"&gt;Boolean&lt;/span&gt; &lt;span class="n"&gt;logDebugInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
      &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;uri&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getRequestURI&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
      &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMethod&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
      &lt;span class="nc"&gt;Enumeration&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;headerNames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getHeaderNames&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
      &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"http://load-balancer"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
      &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getReader&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;lines&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;collect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collectors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;joining&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lineSeparator&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;

      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logDebugInfo&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
         &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;headerNames&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;headerNames&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hasMoreElements&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
               &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;" --- Request Header: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getHeader&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;headerNames&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nextElement&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
         &lt;span class="o"&gt;}&lt;/span&gt;
         &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;" --- Request Body: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
         &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;" --- "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" Reroute to Load Balancer: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
      &lt;span class="o"&gt;}&lt;/span&gt;

      &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
         &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"GET"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;loadBalancedWebClientBuilder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;retrieve&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;bodyToMono&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
         &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"POST"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;loadBalancedWebClientBuilder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;post&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;header&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpHeaders&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;CONTENT_TYPE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;MediaType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;APPLICATION_JSON_VALUE&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;bodyValue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;retrieve&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;bodyToMono&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
         &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"PUT"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;loadBalancedWebClientBuilder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;header&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpHeaders&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;CONTENT_TYPE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;MediaType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;APPLICATION_JSON_VALUE&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;bodyValue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;retrieve&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;bodyToMono&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
         &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"DELETE"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;loadBalancedWebClientBuilder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;delete&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;retrieve&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;bodyToMono&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
      &lt;span class="o"&gt;}&lt;/span&gt;

      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Mono&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
         &lt;span class="nd"&gt;@Override&lt;/span&gt;
         &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;CoreSubscriber&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&lt;/span&gt; &lt;span class="kd"&gt;super&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
         &lt;span class="o"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;};&lt;/span&gt;
   &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;NOTE: Logging has been added so that you can see what is going on in the debug console when running locally&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Next, create a class called &lt;strong&gt;LBExampleConfiguration&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.lb.example&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;lombok.extern.slf4j.Slf4j&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.beans.factory.annotation.Value&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.cloud.client.DefaultServiceInstance&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.cloud.client.ServiceInstance&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.context.annotation.Bean&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.context.annotation.Configuration&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.context.annotation.Primary&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;reactor.core.publisher.Flux&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;javax.annotation.PostConstruct&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.ArrayList&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.List&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@Configuration&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LBExampleConfiguration&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Bean&lt;/span&gt;
    &lt;span class="nd"&gt;@Primary&lt;/span&gt;
    &lt;span class="nc"&gt;ServiceInstanceListSupplier&lt;/span&gt; &lt;span class="nf"&gt;serviceInstanceListSupplier&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;IMServiceInstanceListSuppler&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"load-balancer"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@Slf4j&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;IMServiceInstanceListSuppler&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;ServiceInstanceListSupplier&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;serviceId&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Value&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"#{'${api.endpoints}'.split(',')}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;endpoints&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ServiceInstance&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;instances&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nc"&gt;IMServiceInstanceListSuppler&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;serviceId&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;serviceId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;serviceId&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@PostConstruct&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;buildServiceInstance&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
        &lt;span class="n"&gt;instances&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
        &lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;sid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;endpoints&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;sid&lt;/span&gt;&lt;span class="o"&gt;++;&lt;/span&gt;
            &lt;span class="n"&gt;instances&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DefaultServiceInstance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serviceId&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;sid&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;serviceId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;443&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
            &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;" --- Added Host: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getServiceId&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;serviceId&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Flux&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ServiceInstance&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Flux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;just&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;instances&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, create a class called &lt;strong&gt;WebClientConfig&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.lb.example&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.cloud.client.loadbalancer.LoadBalanced&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.context.annotation.Bean&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.context.annotation.Configuration&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.web.reactive.function.client.WebClient&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@Configuration&lt;/span&gt;
&lt;span class="nd"&gt;@LoadBalancerClient&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"api-gateway"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;configuration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LBExampleConfiguration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WebClientConfig&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@LoadBalanced&lt;/span&gt;
    &lt;span class="nd"&gt;@Bean&lt;/span&gt;
    &lt;span class="nc"&gt;WebClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Builder&lt;/span&gt; &lt;span class="nf"&gt;webClientBuilder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;WebClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, within your &lt;strong&gt;application.yml&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;api&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;endpoints&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;myservice.host1.com,myservice.host2.com,myservice.host3.com"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;This is a comma delimited list where you define all of the endpoints in which you want your API calls to be load balanced. Don't include the http or https here, because functionality within the LBExampleConfiguration class takes care of this based on the port number specified in the call to new DefaultServiceInstance(...)&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up the Client Side
&lt;/h3&gt;

&lt;p&gt;Well, there actually isn't much to do here. From your client application, whether it is Angular, React, Vue, or anything else. Just call your API(s) as if they exist on your backend. Your Java Spring Boot Load Balancer is essentially a simple backend application that will handle routes directed to /api/ and direct them to their actual external endpoints.&lt;/p&gt;

</description>
      <category>java</category>
      <category>springboot</category>
      <category>rest</category>
      <category>loadbalancing</category>
    </item>
    <item>
      <title>An Organic .NET Code Profiler/Logger Through IL Weaving</title>
      <dc:creator>Corey Lasley</dc:creator>
      <pubDate>Tue, 21 Apr 2020 01:09:30 +0000</pubDate>
      <link>https://dev.to/coreylasley/an-organic-net-code-profiler-logger-through-il-weaving-1dp5</link>
      <guid>https://dev.to/coreylasley/an-organic-net-code-profiler-logger-through-il-weaving-1dp5</guid>
      <description>&lt;p&gt;This article is sort of a Part II to my &lt;a href="https://dev.to/coreylasley/poor-man-s-profiler-an-approach-to-profiling-net-code-with-code-block-execution-timing-and-parameter-logging-5c3n"&gt;Poor Man’s Profiler&lt;/a&gt; article, in which I have taken profiling code to the next step. Initially, this seemed like it would have been a relatively easy task, but I ended up spending many more evenings than I expected tweaking things in order to find success. Often the thought went through my mind: “&lt;em&gt;Why am I doing this, and is anyone actually going to find this useful?&lt;/em&gt;” Well I am not one to back down from a coding challenge, and even if I am the only one who gets anything out of this exercise, I wanted to finish what I started. Maybe this will be helpful to someone else out there.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Introduction to this Project&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Despite being a developer for two decades, up until more recently, I had simply only &lt;em&gt;known&lt;/em&gt; about CIL (Common Intermediate Language) often simply called “IL” and how the .NET compiler works, but never really gave it much thought beyond that, simply because (perhaps surprisingly,) I never really had a good reason to actually dig in and understand it. When I put together my proof of concept code and article on my &lt;a href="https://dev.to/coreylasley/poor-man-s-profiler-an-approach-to-profiling-net-code-with-code-block-execution-timing-and-parameter-logging-5c3n"&gt;Poor Man’s Profiler&lt;/a&gt;, I started doing some digging into more optimal approaches to profiling code and logging method consumption (i.e. ways to further limit code redundancy and eliminate unnecessary overhead.)&lt;/p&gt;

&lt;p&gt;Of course I could go the easy route and use an existing product like &lt;a href="https://www.postsharp.net/logging"&gt;PostSharp&lt;/a&gt;, but this exercise wasn't simply about finding an existing solution, rather, it was meant to be a learning experience to try to figure out &lt;em&gt;how&lt;/em&gt; something like this could be accomplished. In all honesty, being an engineer, I really love a good challenge, and don’t like to just leave all the from-scratch fun programming to others, even if in this case, I may be reinventing the wheel a bit.&lt;/p&gt;

&lt;p&gt;So this was when I ventured down a path I hadn't traveled before, discovering metaprogramming and IL weaving. It didn't take long after going down this path, before it clicked that I could disassemble .NET assemblies (via &lt;strong&gt;ildasm&lt;/strong&gt;,) modify the IL code, and reassemble them in a modified state (via &lt;strong&gt;ilasm&lt;/strong&gt;,) it was like I was really seeing for the first time, and the gears in my head really started cranking with ideas.&lt;/p&gt;

&lt;p&gt;Granted, I cannot think of a whole lot of uses for directly modifying/writing IL code, that is, unless you are a glutton for punishment. It isn’t the easiest code to understand, as it looks very Assembler’ish. Because it is stack based (push / pop) it gets incredibly lengthy rather quickly, and if you are not careful, you can really dork things up.&lt;/p&gt;

&lt;p&gt;I can at least think of a few reasons for needing to directly modify IL, albeit uncommon, such as writing an obfuscator, or create one’s own .NET programming language for academic purposes. The big reason for modifying/writing IL was the no-brainer reason why I was down this road to begin with: code profiling!&lt;/p&gt;

&lt;p&gt;Two major aspects of my &lt;a href="https://dev.to/coreylasley/poor-man-s-profiler-an-approach-to-profiling-net-code-with-code-block-execution-timing-and-parameter-logging-5c3n"&gt;Poor Man’s Profiler&lt;/a&gt; solution didn’t sit well with me from the get-go, but I continued the project and article regardless to demonstrate the evolution of a concept from good to better. What was obviously not so great with my Poor Man’s Profiler:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Having to add additional code (albeit simple) all over an application where one wants method data logged&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Having to rely heavily on boxing when logging parameter/variable values.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Through modifying IL code, an entirely different approach can be taken:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;In very direct use, a static solution could be written so that no additional code would need to be added to application code, not even a new class library (But in this solution, we are going to take it beyond this.)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;With a little additional code added to each class in an assembly, the weaving solution can become very customizable, by allowing the developer to handle logging events.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;No more explicit boxing of parameter/variables.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Profiler logging calls are weaved into the methods of IL code post-build and could be used as part of a CICD process.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;A Little Background on the Common Intermediate Language&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Given the fact that IL code is the “low level” of what all .NET languages (i.e. C#/VB.NET/F#/etc.) compile down to, it’s a good idea to get a little familiar with it. You can take a deep dive into CIL by reading through the &lt;a href="http://www.ecma-international.org/publications/standards/Ecma-335.htm"&gt;ECMA-335 Standards&lt;/a&gt;. Wikipedia has a good introduction to  the &lt;a href="https://en.wikipedia.org/wiki/Common_Intermediate_Language"&gt;Common Intermediate Language&lt;/a&gt;. An excellent book that I think belongs in every serious C# developers library is &lt;strong&gt;CLR via C# by Jeffrey Richter&lt;/strong&gt; which is a great resource, and for a real deep dive, the book &lt;strong&gt;.NET IL Assembler by Serge Lidin&lt;/strong&gt; (a book I do not yet have.)&lt;/p&gt;

&lt;p&gt;With a couple resource available, I found that the best way for me to wrap my head around IL, was to simply write some C# code, such as in a console app, build it, and then use &lt;strong&gt;&lt;a href="https://docs.microsoft.com/en-us/dotnet/framework/tools/ildasm-exe-il-disassembler"&gt;ildasm&lt;/a&gt;&lt;/strong&gt; to disassemble it to readable IL. At this point I could look at my .NET code and compare it with its corresponding IL code, and identify patterns of translation. This gave me a solid idea of what I needed to do to generate my own IL code blocks that I could then inject into the code, and finally reassemble via &lt;strong&gt;&lt;a href="https://docs.microsoft.com/en-us/dotnet/framework/tools/ilasm-exe-il-assembler"&gt;ilasm&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Using a data/text comparison tool, such as &lt;a href="https://winmerge.org/"&gt;WinMerge&lt;/a&gt; makes it much easier to see the differences between original code, and what code should look like after injecting new code. This takes quite a bit of guesswork out of things.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Writing my Own IL Parser, Code Generator, and Injector/Weaver Solution&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The purpose of my exercise for this project and corresponding article was:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Log execution time of methods.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Log parameter names and values passed into methods, including all primitive types and types that implement IEnumerable.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Limited code needed to be added to a consuming solution, only simple attributes at Class level and/or Method level, depending on how fine tuned one wants things.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Only one method with a specific signature and an Attribute needs to be written in the consuming solution, giving the developer full control over the actual logging process. Method execution time, and parameter data is passed to this method.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Application assemblies are modified post-build to inject all profiling code into applicable methods.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Consumption of this solution should be extremely simple and straight forward.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Having gone through a 101 on IL; On a technical level, the final product will do the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Disassemble a DLL or EXE in IL code with ildasm.exe&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Parse the IL code into an object structure making IL code analysis and injection possible.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Discover the location of the Logging Handler method (based on a Method level attribute)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Based on specific Class/Method level attributes, determine which methods need IL modification.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If any methods that will be profiled/logged are found to have a parameter which implements IEnumerable, generate a method to convert the value of the enumerable to a comma delimited list string.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Generate IL code to assign parameter names and values (i.e. “[parameter]=[value]; ”) to a single string. For IEnumerable types, call our generated conversion method, and inject at the beginning of the method.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Generate IL code to initiate and start a StopWatch object, and inject into the beginning of the method.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Modify the existing “maxstack” and “.locals init” of the method to accommodate for the StopWatch and Parameter list string objects.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Adjust the indexes on the existing “sdloc”, “ldloc”, and “ldloca” instructions of the method to accommodate the injected code above.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Generate IL code to stop the StopWatch, and inject at the end of the method.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Generate IL code to make a call to the discovered Logging Handler method, passing it the calling method name, the string holding our parameter names and values, and the StopWatch’s elapsed milliseconds, and inject at the end of the method.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Save the modified IL code to disk.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Assemble the modified IL code by calling ilasm.exe (including its resource file that was generated when disassembled if one exists).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Overwrite the original assembly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cleanup all temporary working files on disk.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After a couple of weeks, working for an hour or two in the evenings, I was able to successfully pull this off.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The CIL Weaver Solution&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;I am not going to go into the internals of the my code here because there is a lot to dissect. Rather, I will go into how what I have written can be used to weave profiling code into your assemblies. My  &lt;a href="https://github.com/coreylasley/CILWeaverProfiler"&gt;CIL Weaver Profiler&lt;/a&gt; solution on &lt;a href="https://github.com/coreylasley/CILWeaverProfiler"&gt;GitHub&lt;/a&gt; contains the following projects:&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Core Projects&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;CILWeaveProfiler&lt;/strong&gt; (.NET Standard Class Library): This contains all the real beef, containing the code to automate disassembly/assembly, and IL code parsing/writing. There is quite a bit to take in here. Not only does this library contain the logic for modifying assemblies, but it is also the library that you will need to reference in your application that you want to be modified for profiling (more on this later)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CILWeaver.Console&lt;/strong&gt; (.NET Core 3.1 Console): This application consumes the &lt;em&gt;CILWeaveProfiler&lt;/em&gt; class library and performs the calls needed to disassemble an assembly (exe or dll), parse the IL, make modifications to it based on the contents of the existing IL, save the changes, and reassemble the assembly. This could be used manually, or as part of a CICD process. &lt;em&gt;NOTE: If you want to use this, you may need to make some minor modifications.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Development Aids&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;ReferenceApp&lt;/strong&gt; (.NET Core 3.1 Console): This is a sandbox application that I use to write test .NET (C#) code so that I could disassemble it, inspect the IL, and figure out what I needed to do within CILWeaveProfiler to accomplish the end goal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ILStringify.Blazor&lt;/strong&gt; (.NET Core 3.1 Blazor SPA): A quick tool that I whipped up to help me turn large blocks of IL code into C# string assignment code that I could use while developing CILWeaveProfiler. I figured that I might as well include this. Being so comfortable in the .NET world, I absolutely love how simple Blazor is, and how quickly I can slap a simple SPA together to build quick tools in .NET Core (a topic for another day.)&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;How the Solution is Applied to Your .NET Project&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Prepping Your Code&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Through the use of custom &lt;em&gt;Attributes&lt;/em&gt;, which is essentially metadata applied to target elements in our .NET code (i.e. Classes and Methods,) we can customize our logging process. Attributes, as most .NET developers are familiar with, are generally used within the application or sometimes the compiler, however we will use these attributes only within the CILWeaver program (well actually the CILWeaveProfile library,) as they are, more or less, simply IL modification directives, used to determine which methods are going to be profiled and how (what sort of IL modifications need to be made.) Additionally, we point the IL modification process to the existing method that will consume the profiled data, so that the developer has the final say into to how the data is actually logged, while the cumbersome task of gathering the profiled data is taken care of and passed to this method.&lt;/p&gt;

&lt;p&gt;First, you will want to reference the &lt;strong&gt;CILWeaveProfiler&lt;/strong&gt; Class Library in your project. &lt;/p&gt;

&lt;p&gt;In order to tell the CIL Weaver how to modify the application you will use Attributes which require the following reference:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;    &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;CILWeaveProfiler.Attributes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The two Attributes that can be applied are &lt;em&gt;ProfilerClass&lt;/em&gt; and &lt;em&gt;ProfilerMethod&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ProfilerClass&lt;/strong&gt;: This is a class level attribute that can be used to apply how the CILWeaver program will treat all of it’s methods by default. If a method level attribute (see below) is applied to a class’s method, the method level attribute will override this attribute for the particular method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;ProfilerClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LoggingType&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CILWeaveProfiler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LoggingTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;All&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;    
    &lt;span class="k"&gt;class&lt;/span&gt;  &lt;span class="nc"&gt;Program&lt;/span&gt;    
    &lt;span class="p"&gt;{&lt;/span&gt;    
    &lt;span class="err"&gt;…&lt;/span&gt;    
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For &lt;em&gt;LoggingTypes&lt;/em&gt; you can specify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;All&lt;/strong&gt;: Meaning, by default, unless a Method attribute states otherwise, profile the Execution Time and Parameters passed to the Method.
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ExecutionOnly&lt;/strong&gt;: Meaning, by default, unless a Method attribute states otherwise, only profile the Execution Time of the Method.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ParameterValuesOnly&lt;/strong&gt;: Meaning, by default, unless a Method attribute states otherwise, only profile the Parameters passed to the Method.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;None&lt;/strong&gt;: Meaning, by default, unless a Method Attribute states otherwise, do not profile the Class’ methods.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the Class is not marked with the Attribute, it is the same as if it was marked with &lt;strong&gt;None&lt;/strong&gt;. The Class does not need to be marked with the Attribute for Methods to utilize the Attribute.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ProfilerMethod&lt;/strong&gt;: This is a method level attribute that can be used to tell the CILWeaver program if it should profile the method and how if different from the class level attribute. If this attribute is NOT applied to a method, but the ClassAttribute is applied at class level, the attributes of the class level attribute will be applied to the method.&lt;/p&gt;

&lt;p&gt;Little is actually gained by using &lt;strong&gt;ExecutionOnly&lt;/strong&gt; or &lt;strong&gt;ParameterValuesOnly&lt;/strong&gt;, as the modified code will simply pass in an empty string for &lt;em&gt;parameters&lt;/em&gt; or a 0 for &lt;em&gt;milliseconds&lt;/em&gt; to the logging method. The only gain would be in the small overhead required for instantiating and executing a &lt;em&gt;StopWatch&lt;/em&gt; or converting parameter values to strings.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: Inspecting the code, you may notice that the &lt;em&gt;ClassAttribute&lt;/em&gt; and &lt;em&gt;MethodAttribute&lt;/em&gt; are identical in their properties, so why didn’t I just use one Attribute for both? This is&lt;br&gt;
because I may want to eventually do more with these attributes that&lt;br&gt;
are applicable more to one or the other, but not necessarily both.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Additionally, and importantly, through the use of another simple attribute, we mark the particular method in our code in which the weaver will inject calls to, so that we do not have to rely on a baked-in logging functionality, but rather, how profiled data is actually logged, is in full control of the developer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LoggingMethodOverride&lt;/strong&gt;: This can be applied to a method within the class, or inherited class, and the method can have any name. The method does however require a specific parameter signature. The parameters must be &lt;strong&gt;(string methodName, string parameters, long milliseconds)&lt;/strong&gt; This method will never be profiled itself, or else endless recursion would occur until you reach stack overflow. Note this is not a true override, as consuming classes do not inherit from a special base class, or implement an interface in which a specific logging method needs to be overridden. However, if you do not mark a method with the required signature with this Attribute, absolutely nothing will be logged.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Example&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;LoggingMethodOverride&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;    
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;LogIt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;methodName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;milliseconds&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    
    &lt;span class="p"&gt;{&lt;/span&gt;    
    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"LOGGING -&amp;gt; "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;methodName&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"("&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;parameters&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="s"&gt;") executed in: "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;milliseconds&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;    
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As stated, we can define our logging method with the &lt;em&gt;LoggerAttribute&lt;/em&gt; in a base class from which our other classes inherit, so that we have one definition per assembly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;ProfilerClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LoggingType&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CILWeaveProfiler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LoggingTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;All&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;    
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Program&lt;/span&gt;    
    &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;ProfilerMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LoggingType&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CILWeaveProfiler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LoggingTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;    
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    
    &lt;span class="p"&gt;{&lt;/span&gt;    
    &lt;span class="c1"&gt;// We do not want to profile this method    &lt;/span&gt;
    &lt;span class="nf"&gt;DoSomething&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;    
    &lt;span class="nf"&gt;DoSomethingElse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;123&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddMonths&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddYears&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;    
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;DoSomething&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;    
    &lt;span class="p"&gt;{&lt;/span&gt;    
    &lt;span class="c1"&gt;// Profiling of this method will inherit the Attribute of the Class since no method level Attribute is specified    &lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;ProfilerMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LoggingType&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CILWeaveProfiler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LoggingTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ParameterValuesOnly&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;    
    &lt;span class="k"&gt;static&lt;/span&gt;  &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;DoSomethingElse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;dates&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    
    &lt;span class="p"&gt;{&lt;/span&gt;    
    &lt;span class="c1"&gt;// For this method, we only want to profile Parameters    &lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;LoggingMethodOverride&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;    
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;LogIt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;methodName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;milliseconds&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    
    &lt;span class="p"&gt;{&lt;/span&gt;    
    &lt;span class="c1"&gt;// This method is marked with the Attribute of [LoggingMethodOverride], and the CIL will be modified    &lt;/span&gt;
    &lt;span class="c1"&gt;// in the other applicable methods to gather profile data and pass it to this method&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"LOGGING -&amp;gt; "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;methodName&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"("&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;parameters&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="s"&gt;") executed in: "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;milliseconds&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;    
    &lt;span class="p"&gt;}&lt;/span&gt;    
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Executing the IL Weaver on your Assembly&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;Included in the solution is the &lt;strong&gt;CILWeaver.Console&lt;/strong&gt; program which can be used as the basis for your IL Weaver which utilizes the &lt;strong&gt;CILWeaverProfiler&lt;/strong&gt; library. However with just a handful of lines of code you can quickly integrate the process into your own weaver app. Simply add a reference to the CLIWeaverProfiler, and get rolling.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;    &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;CILWeaveProfiler&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives you access to the &lt;strong&gt;Weaver&lt;/strong&gt; object which contains simple methods for executing the Disassembly, Modification, and Assembly process.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;    &lt;span class="c1"&gt;// Disassemble the assembly...&lt;/span&gt;
    &lt;span class="n"&gt;DisassembleInfo&lt;/span&gt; &lt;span class="n"&gt;dIL&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Disassemble&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[PATH &amp;amp; FILE NAME]"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;IL&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dIL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CIL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Parse the disassembled IL Code&lt;/span&gt;
    &lt;span class="n"&gt;Assembly&lt;/span&gt; &lt;span class="n"&gt;asm&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ParseILCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;newIL&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;asm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GenerateAssemblyILCode&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Display the modified IL Code&lt;/span&gt;
    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newIL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Assemble the modified IL Code            &lt;/span&gt;
    &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;success&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Assemble&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dIL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ReassemblyTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OverwriteOriginal&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;success&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s"&gt;"SUCCESS!"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Failed to reassemble"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Making Your Own Modifications to the IL Weaver&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Consult a list of CIL instruction such as &lt;a href="https://en.wikipedia.org/wiki/List_of_CIL_instructions"&gt;List of CIL instructions on Wikipedia&lt;/a&gt; and get familiar with what you are seeing in your IL code, so that you have a better understanding of how you need to make modifications.&lt;/p&gt;

&lt;p&gt;Unless you really feel comfortable with IL code, I must emphasize the usefulness of a data/text comparison tool, such as &lt;a href="https://winmerge.org/"&gt;WinMerge&lt;/a&gt; to aid in the process of writing the C# code to generate IL code.&lt;/p&gt;

&lt;p&gt;For an IL novice such as myself, the best way to determine what sort of IL code was needed to be generated, and where to put it, I found to be in the following process:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Write a program which contains all the code I would expect to see in my final product.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Build it, and disassemble to IL code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Save this IL code to a file somewhere.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Remove all the code that should not be in the original assembly (the code that will be injected later,)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Build it, and disassemble to IL code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Save this IL code to a file.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Finally, load my two versions of IL code into a tool such as the aforementioned WinMerge, and compare them to get a good idea of changes that need to be made.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sometimes after making IL changes, you may get ilasm to successfully assemble the code. However, after running the executable, you may receive a “&lt;em&gt;System.InvalidProgramException: Common Language Runtime detected an invalid program&lt;/em&gt;” This means that syntactically the code was good, but there is an issue with it that ilasm clearly did not detect. With this, and if examining the IL doesn't reveal the issue, you should be able to debug the IL in Visual Studio. A really old article (like 18 years old!) on how this might be able to be done is found &lt;a href="http://www.devcity.net/Articles/57/1/msil_3_debug.aspx"&gt;here&lt;/a&gt; I didn't actually attempt this however.&lt;/p&gt;

&lt;p&gt;Another suggestion that I came across was to use the &lt;strong&gt;&lt;a href="https://docs.microsoft.com/en-us/dotnet/framework/tools/peverify-exe-peverify-tool"&gt;PEVerify.exe&lt;/a&gt;&lt;/strong&gt; utility, however the results of this utility led me on a wild goose chase that wasted a ton of my time, and I was never able to get to the bottom of the issues I had. I discovered that using the utility PEVerify.exe, I consistently got the following 3 errors on a reassembled DLL, whether I modified its original disassembled IL code or do not. During my development process, at one point I was using this utility in my process for extra verification, and I ended up spending a lot of time assuming that something was wrong with my modified IL code in the wrong places, until I ran the utility on an assembly where I had simply disassembled a freshly built DLL to IL and then reassembled it back to a DLL without any modifications.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[MD]: Error: EntryPoint method has invalid number of arguments, expecting 3. [token:0x06000004]
[MD]: Error: EntryPoint method has invalid return type. [token:0x06000004]
[MD]: Error: EntryPoint method has invalid argument number 1. [token:0x06000004]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Despite the error messages above, the EXE consuming the DLL and its internals ran perfectly fine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Some Quick Tips: Issues I ran into developing this code&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;When injecting IL code into existing methods, the &lt;em&gt;sdloc&lt;/em&gt;, &lt;em&gt;ldloc&lt;/em&gt;, and &lt;em&gt;ldloc&lt;/em&gt; index values need to be adjusted accordingly, depending on code injection placement! In our case, it makes it somewhat straightforward that our code injections happen both at the beginning and ending of existing applicable methods. If you push and pull the wrong indexes at the wrong time, strange things can happen, and likely a hang or throw an unhandeled exception.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Make sure the &lt;em&gt;&lt;em&gt;maxstack&lt;/em&gt;&lt;/em&gt; values are adjusted appropriately based on the code you are injecting. If the modified application attempts to push more on to the stack than allocated in &lt;em&gt;maxstack&lt;/em&gt;, the application will crash. It is a good idea to set the &lt;em&gt;maxstack&lt;/em&gt; at a value that truly represents the max size of the items your method will push to the stack (as opposed to just putting some arbitrary high number there.)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This is what gave me the most grief…. In IL, a string doesn't like to be converted to a string. This seems obvious enough, but C# doesn't mind this, and will allow for code calling .ToString() on a string (the compiler makes adjustments for this in the IL). All other object types I have tested can be converted to a string without issue. In my code which concatenates all of the parameters as single string (thus essentially calling .ToString() on all parameters,) I needed to adjust my code generator to make an exception to this rule if the parameter type is already string. Let me elaborate on this...&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;As an example, lets say we have a method, with it’s first parameter being a string, and the parameter’s name is “str,” the following code block marked “No Good” was a pattern that works just fine on parameters of other types, but throws an error on string type parameters. Adjusting code to follow a different pattern for a string type parameter solves the problem:&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/* No Good for a string */&lt;br&gt;
IL_0011: ldc.i4.1&lt;br&gt;&lt;br&gt;
IL_0012: ldarga.s str&lt;br&gt;&lt;br&gt;
IL_0013: call instance string [System.Runtime]System.Object::ToString()&lt;br&gt;&lt;br&gt;
IL_0014: stelem.ref&lt;br&gt;&lt;br&gt;
IL_0015: dup

&lt;p&gt;/* Good for a string */&lt;br&gt;&lt;br&gt;
IL_0011: ldc.i4.1&lt;br&gt;&lt;br&gt;
IL_0012: ldarg.0&lt;br&gt;&lt;br&gt;
IL_0013: stelem.ref&lt;br&gt;&lt;br&gt;
IL_0014: dup&lt;br&gt;
&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  &lt;strong&gt;Summary&lt;/strong&gt;&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;To wrap things up here, I hope that what I have provided here within this article as well as the code in the associated &lt;a href="https://github.com/coreylasley/CILWeaverProfiler"&gt;GitHub&lt;/a&gt; solution can help to provide some insight as to how one might go about modifying a .NET executable post-build to inject additional functionality such as profiling. &lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>advanced</category>
      <category>ilweaving</category>
      <category>cil</category>
    </item>
    <item>
      <title>Poor Man’s Profiler: An Approach to Profiling .NET Code with Code Block Execution Timing and Parameter Logging</title>
      <dc:creator>Corey Lasley</dc:creator>
      <pubDate>Sat, 08 Feb 2020 02:07:42 +0000</pubDate>
      <link>https://dev.to/coreylasley/poor-man-s-profiler-an-approach-to-profiling-net-code-with-code-block-execution-timing-and-parameter-logging-5c3n</link>
      <guid>https://dev.to/coreylasley/poor-man-s-profiler-an-approach-to-profiling-net-code-with-code-block-execution-timing-and-parameter-logging-5c3n</guid>
      <description>&lt;p&gt;Applies to: .NET Standard 2.2+&lt;/p&gt;

&lt;p&gt;This article is based on my example class library project &lt;a href="https://github.com/coreylasley/PoorMansLogger"&gt;Poor Man's Profiler&lt;/a&gt; on &lt;a href="https://github.com/coreylasley/PoorMansLogger"&gt;GitHub&lt;/a&gt;. To see the internals of this class library, please grab it there.&lt;/p&gt;

&lt;h3&gt;
  
  
  Basic Profiling
&lt;/h3&gt;

&lt;p&gt;At some point in time most of us have likely used one of the following methods for basic timing of code execution.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="n"&gt;dt&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Threading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;TimeSpan&lt;/span&gt; &lt;span class="n"&gt;ts&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Execution took: "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TotalMilliseconds&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"ms"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;Stopwatch&lt;/span&gt; &lt;span class="n"&gt;sw&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Stopwatch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StartNew&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Threading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;sw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Stop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Execution took: "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;sw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ElapsedMilliseconds&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"ms"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is some really basic code that works well if all you want to know is the execution time of a given block of code. However, if you want to log multiple code blocks (especially within a single method,) and/or you want to log values of various variables, your code can start to get messy quick as it becomes littered with &lt;code&gt;DateTime&lt;/code&gt;/&lt;code&gt;TimeSpan&lt;/code&gt;/&lt;code&gt;Stopwatch&lt;/code&gt; declarations and calls to &lt;code&gt;Debug.WriteLine()&lt;/code&gt;. Additionally, if you want to be able to easily toggle this profiling code on or off, so you don’t have to comment it out or remove it all together when you don’t want it to run (like when the application is in production,) you are going to have to write some additional boilerplate code to handle this.&lt;/p&gt;

&lt;h3&gt;
  
  
  More Advanced Profiling
&lt;/h3&gt;

&lt;p&gt;There are several software vendors who provide some really powerful frameworks that can be utilized for profiling and logging code performance, with the most popular being &lt;a href="https://www.postsharp.net/"&gt;PostSharp&lt;/a&gt;. Such products most certainly have their place among a developer’s arsenal. In no way do I think my project here even remotely compares to the offerings of such products, especially considering my solution here is the work of a few meager hours of brainstorming and development. &lt;/p&gt;

&lt;p&gt;For the sake of this article, Let’s pretend that you have an idea of roughly where a problem might be, but don’t feel that it is necessary to purchase a license (of have the budget) for a product that isn’t going to be truly utilized.&lt;/p&gt;

&lt;p&gt;Enter what I have dubbed as the &lt;strong&gt;&lt;a href="https://github.com/coreylasley/PoorMansLogger"&gt;Poor Man's Profiler&lt;/a&gt;&lt;/strong&gt; (&lt;em&gt;Poor Man&lt;/em&gt;, as in, there are no licensing costs in this open source solution, which lacks the &lt;em&gt;rich&lt;/em&gt; features and high scalability of the big commercial products.) This is more or less a very simple idea I recently had, that sort of evolved and continues to evolve as I keep thinking of ways to enhance it.&lt;/p&gt;

&lt;p&gt;An &lt;strong&gt;AOP (Aspect Oriented Programming)&lt;/strong&gt; or &lt;strong&gt;IL Weaving&lt;/strong&gt; approach would likely be a better overall approach when writing our own logger that would keep the consuming application more in line with the &lt;strong&gt;DRY Principal&lt;/strong&gt; (i’ll explain this later.) In fact, AOP/ IL Weaving is exactly what the earlier mentioned PostSharp is known for having mastered. Of course this could be the direction we take in Poor Man’s Profiler, utilizing DispatchProxy, but for the sake of going through an evolutionary concept, I wanted the first version Poor Man’s Profiler to be fairly basic, so that we could see some pros and cons. &lt;/p&gt;

&lt;h3&gt;
  
  
  The End Goal
&lt;/h3&gt;

&lt;p&gt;So what was my goal here? I wanted to be able to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Time the executions of entire methods, and/or parts of method’s internals.&lt;/li&gt;
&lt;li&gt;Have the ability to log parameter/variable values easily.&lt;/li&gt;
&lt;li&gt;Identify both code block call frequency, and more importantly, repetitive code executions, whereas sometimes a block of code in itself when called once, isn’t necessarily causing a noticeable bottleneck, but when called multiple times unnecessarily, a performance issue begins to rears its ugly head.&lt;/li&gt;
&lt;li&gt;Easily enable/disable this profiling with minimal effort, so that the profiling code could be left intact, but not executed or even in existence while running in a Release build.&lt;/li&gt;
&lt;li&gt;Do the aforementioned with minimal code (as much as possible,) so as to not muck up and bloat the readability and flow of things that I wanted to profile.&lt;/li&gt;
&lt;li&gt;Take a stab at writing some code a little out of the ordinary.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Some Points of Caution
&lt;/h3&gt;

&lt;p&gt;The first generation of an idea is usually far from perfect, and the fist version of Poor Man’s Profiler is of no exception.&lt;/p&gt;

&lt;p&gt;Before we go any further, I must state that if you choose to use Poor Man’s Profiler in an application, it is coded to be a debug only logging option to help a developer gain better insight into things while troubleshooting code in debug mode. There is of course overhead with the use of Poor Man’s Profiler since it obviously adds more to instantiate and process, and depending on how it’s used, utilizes some reflection and causes some boxing. Interestingly enough however, I have come across a few AOP Logger implementations online, that rely on reflection and boxing as well.&lt;/p&gt;

&lt;p&gt;I found the performance hit to be surprisingly minor when not used excessively, in fact, relatively unnoticeable in most situations, even in more complex/lengthy logging situations. With that being said, lets discuss some of the cons of this approach. &lt;/p&gt;

&lt;h5&gt;
  
  
  Boxing
&lt;/h5&gt;

&lt;p&gt;So What is this “Boxing” thing that I speak of? Boxing is a computationally expensive process of converting a value type to the type of object. You may have seen this done in code, or have done it yourself on many occasions and didn't even realize it was a potential issue. The following demonstrates boxing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;123&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;object&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Relying on boxing is a big no-no in applications that you expect to see operate with the best  performance. &lt;a href="https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/types/boxing-and-unboxing"&gt;Microsoft’s documentation&lt;/a&gt; describes the issue well: &lt;em&gt;“Boxing is the process of converting a value type to the type object or to any interface type implemented by this value type. When the common language runtime (CLR) boxes a value type, it wraps the value inside a System.Object instance and stores it on the managed heap. Unboxing extracts the value type from the object.”&lt;/em&gt; If high-performance is one of the major goals of an application (which it should be,) you should limit code that converts to and from &lt;code&gt;object&lt;/code&gt; as much as possible.  &lt;/p&gt;

&lt;p&gt;So while I am breaking my own advice here (that is, avoid boxing,) Poor Man’s Profiler provides a way around allowing such code to execute when in Release mode, which will be discussed later.&lt;/p&gt;

&lt;h5&gt;
  
  
  The DRY Principal
&lt;/h5&gt;

&lt;p&gt;One of the concepts introduced in the 1999 work, &lt;a href="https://books.google.com/books?id=5wBQEp6ruIAC&amp;amp;printsec=frontcover&amp;amp;dq=the+pragmatic+programmer&amp;amp;hl=en&amp;amp;newbks=1&amp;amp;newbks_redir=0&amp;amp;sa=X&amp;amp;ved=2ahUKEwjp3aDe28DnAhVSjlkKHY3WCnIQ6AEwAHoECAIQAg#v=onepage&amp;amp;q=the%20pragmatic%20programmer&amp;amp;f=false"&gt;“The Pragmatic Programmer”&lt;/a&gt; is the DRY (Don’t Repeat Yourself) Principal, which is pretty much self-explanatory. As far as programming goes, it is always best practice to write code in a way that you are not duplicating code. One good reason for this is that if you have a block of code duplicated all over the place, and then something needs to change in that block of code, you will have a lot of work on your hands making changes everywhere that code block is used. &lt;/p&gt;

&lt;p&gt;As for Poor Man’s Profiler, you will find yourself duplicating some code wherever you want it to be used. This will consist of your declaration of the &lt;code&gt;DebuggLogger&lt;/code&gt; class, and generally two simple method calls wherever you wish to &lt;em&gt;Start&lt;/em&gt; and &lt;em&gt;Stop&lt;/em&gt; a code profile. Though it may not be a huge deal if used conservatively, a very thorough use, i.e. if you have the &lt;code&gt;StartDebug()&lt;/code&gt;/&lt;code&gt;StopDebug()&lt;/code&gt; method calls plastered all over a large application, it could prove to cause a lot of potential future keyboard pounding refactoring, that is, if anything is changed in a future release concerning the way these core methods are called.&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting Into the Code Behind Poor Man’s Profiler
&lt;/h3&gt;

&lt;p&gt;One instance of &lt;code&gt;DebugLogger&lt;/code&gt; class allows for the time monitoring and parameter logging of an unlimited number of code blocks, thus it is best to declare it at class level, where all methods in the class can use it.&lt;/p&gt;

&lt;h3&gt;
  
  
  The process of converting parameter values to a string
&lt;/h3&gt;

&lt;p&gt;Unlimited parameter values can be logged. This first version supports primitive types and Lists of primitive types (with the addition of &lt;code&gt;DateTime&lt;/code&gt; and &lt;code&gt;Timespan&lt;/code&gt;) which tend to be the most common parameters I see in applications. The &lt;code&gt;ParamValuesToString()&lt;/code&gt; method of the &lt;code&gt;Logger&lt;/code&gt; base class, of course could easily be modified to support other types. &lt;/p&gt;

&lt;p&gt;Dealing with Lists was a little uglier than I would have liked (see the the &lt;code&gt;ParamValuesToString()&lt;/code&gt; method of the &lt;code&gt;Logger&lt;/code&gt; base class,) and I have found no way to easily cast a boxed &lt;code&gt;object&lt;/code&gt; representing a &lt;code&gt;List&amp;lt;T&amp;gt;&lt;/code&gt; to an &lt;em&gt;actual&lt;/em&gt; &lt;code&gt;List&amp;lt;T&amp;gt;&lt;/code&gt; as the casting-to-type always needs to be known (i.e. “&lt;code&gt;List&amp;lt;T&amp;gt; tl = (List&amp;lt;T&amp;gt;)object;&lt;/code&gt;” obviously won’t work, and “&lt;code&gt;List tl = (List)object;&lt;/code&gt;” requires a type argument.) Our ultimate goal for logging is to extract the elements of a &lt;code&gt;List&amp;lt;T&amp;gt;&lt;/code&gt;  as strings, but because our &lt;code&gt;object&lt;/code&gt; is a boxed representation a &lt;code&gt;List&lt;/code&gt; of &lt;em&gt;any possible type&lt;/em&gt;, there is no good way to cast the &lt;code&gt;object&lt;/code&gt; to a &lt;code&gt;List&amp;lt;string&amp;gt;&lt;/code&gt;, as this cannot be done with an explicit cast. One trick I have seen used to get around this is to serialize the object to JSON, then Parse the JSON and loop through the items as strings. &lt;/p&gt;

&lt;p&gt;This will do the trick, but can be more difficult when working with Lists of more complex types. As far as performance goes, Initially I thought the performance of this approach was going to be horrendous, but with a quick test, I was surprised. The serialization process on a &lt;code&gt;List&lt;/code&gt; of 7 integers for example, seems to be very comparable in speed, to a direct cast from &lt;code&gt;object&lt;/code&gt; to &lt;code&gt;List&amp;lt;int&amp;gt;&lt;/code&gt; then to &lt;code&gt;List&amp;lt;string&amp;gt;&lt;/code&gt;, that is with the exception of the very first call to &lt;code&gt;JsonConvert.SerializeObject()&lt;/code&gt; which lazy loads several dependencies, and takes more than 25x the amount of time it does with ensuing calls.&lt;/p&gt;

&lt;p&gt;The following test, uses the Poor Man’s Profiler to compare these two ways to convert a &lt;code&gt;List&lt;/code&gt; of &lt;code&gt;int&lt;/code&gt; to a &lt;code&gt;List&lt;/code&gt; of &lt;code&gt;string&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;DebugLogger&lt;/span&gt; &lt;span class="n"&gt;dl&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;DebugLogger&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ListToStringListCompare&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ints&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;7&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="c1"&gt;// Box the ints object&lt;/span&gt;
    &lt;span class="kt"&gt;object&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ints&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;stringList&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;

    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Performing JSON Serialize/Parse to List&amp;lt;string&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StartDebug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"JSON Serialize"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// using Newtonsoft.Json;&lt;/span&gt;
    &lt;span class="c1"&gt;// using Newtonsoft.Json.Linq;&lt;/span&gt;
    &lt;span class="n"&gt;JObject&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;JObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{ items: "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;JsonConvert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SerializeObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"}"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;stringList&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"items"&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StopDebug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"JSON Serialize"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Performing Cast to List&amp;lt;int&amp;gt; -&amp;gt; List&amp;lt;string&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StartDebug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Direct Test/Cast"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;Type&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetType&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;))&lt;/span&gt; &lt;span class="n"&gt;stringList&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;)&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StopDebug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Direct Test/Cast"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Executing this 3x, we can see that after the first execution, both methods perform the same.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;******** Message  : Performing JSON Serialize/Parse to List&amp;lt;string&amp;gt;
******** Started  : Program -&amp;gt; JSON Serialize() ...
******** Completed: Program -&amp;gt; JSON Serialize() took [263ms] to execute.
******** Message  : Performing Direct Cast to List&amp;lt;int&amp;gt; -&amp;gt; List&amp;lt;string&amp;gt;
******** Started  : Program -&amp;gt; Direct Test/Cast() ...
******** Completed: Program -&amp;gt; Direct Test/Cast() took [5ms] to execute.

******** Message  : Performing JSON Serialize/Parse to List&amp;lt;string&amp;gt;
******** Started  : Program -&amp;gt; JSON Serialize() ...
******** Completed: Program -&amp;gt; JSON Serialize() took [2ms] to execute.
******** Message  : Performing Direct Cast to List&amp;lt;int&amp;gt; -&amp;gt; List&amp;lt;string&amp;gt;
******** Started  : Program -&amp;gt; Direct Test/Cast() ...
******** Completed: Program -&amp;gt; Direct Test/Cast() took [2ms] to execute.

******** Message  : Performing JSON Serialize/Parse to List&amp;lt;string&amp;gt;
******** Started  : Program -&amp;gt; JSON Serialize() ...
******** Completed: Program -&amp;gt; JSON Serialize() took [1ms] to execute.
******** Message  : Performing Direct Cast to List&amp;lt;int&amp;gt; -&amp;gt; List&amp;lt;string&amp;gt;
******** Started  : Program -&amp;gt; Direct Test/Cast() ...
******** Completed: Program -&amp;gt; Direct Test/Cast() took [1ms] to execute.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Using Poor Man’s Profiler in Your Application
&lt;/h3&gt;

&lt;p&gt;In its most basic form, its use looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;DebugLogger&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;DebugLogger&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Prefix&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Program"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MaxElementsIfNonNumericList&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MaxElementsIfNumericList&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MaxStringLength&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;Test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;123&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"This"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Is"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"A"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Test"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddDays&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="m"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;  

&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="c1"&gt;// Start a stopwatch on the method&lt;/span&gt;
   &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StartDebug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"TestMethod"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

   &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
   &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Start a stopwatch and log some values&lt;/span&gt;
      &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StartDebug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"loop"&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="c1"&gt;// Some code here ...&lt;/span&gt;

      &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StopDebug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"loop"&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StopDebug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"TestMethod"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Output window of the IDE will quickly display the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;******** Started  : Program -&amp;gt; TestMethod() ...
******** Started  : Program -&amp;gt; loop0(0, 123, ["This", "Is", "A", "Test"], ["2/5/2020 8:08:13 PM", "2/10/2020 8:08:13 PM"], [9, 8, 7, 6, 5, 4, 3, 2, 1]) ...
******** Completed: Program -&amp;gt; loop0() took [1ms] to execute.
******** Started  : Program -&amp;gt; loop1(1, 123, ["This", "Is", "A", "Test"], ["2/5/2020 8:08:13 PM", "2/10/2020 8:08:13 PM"], [9, 8, 7, 6, 5, 4, 3, 2, 1]) ...
******** Completed: Program -&amp;gt; loop1() took [1ms] to execute.
******** Started  : Program -&amp;gt; loop2(2, 123, ["This", "Is", "A", "Test"], ["2/5/2020 8:08:13 PM", "2/10/2020 8:08:13 PM"], [9, 8, 7, 6, 5, 4, 3, 2, 1]) ...
******** Completed: Program -&amp;gt; loop2() took [1ms] to execute.
******** Started  : Program -&amp;gt; loop3(3, 123, ["This", "Is", "A", "Test"], ["2/5/2020 8:08:13 PM", "2/10/2020 8:08:13 PM"], [9, 8, 7, 6, 5, 4, 3, 2, 1]) ...
******** Completed: Program -&amp;gt; loop3() took [1ms] to execute.
******** Started  : Program -&amp;gt; loop4(4, 123, ["This", "Is", "A", "Test"], ["2/5/2020 8:08:13 PM", "2/10/2020 8:08:13 PM"], [9, 8, 7, 6, 5, 4, 3, 2, 1]) ...
******** Completed: Program -&amp;gt; loop4() took [1ms] to execute.
******** Completed: Program -&amp;gt; TestMethod() took [18ms] to execute.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lets break this down a bit. Within the class level declaration of the &lt;code&gt;DebugLogger&lt;/code&gt; object named “logger” we have some properties being set:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;DebugLogger&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;DebugLogger&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Prefix&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Program"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MaxElementsIfNonNumericList&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MaxElementsIfNumericList&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MaxStringLength&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;code&gt;Prefix&lt;/code&gt;&lt;/strong&gt;: This is an optional string value that will precede the code block name with every log entry, this is helpful for helping to identify what class the profiler is currently logging from, if you so choose to use this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;MaxElementsIfNonNumericList&lt;/code&gt;&lt;/strong&gt;: Since the contents of Lists of primitive types will be written to the log in a comma delimited fashion in between brackets, we want a way to restrict the number of elements to actually log, in the event the List contains a lot of elements. This property applies to primitive types that are non-numeric. This value will restrict the number of elements to be logged. Specify 0 if you want all elements listed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;MaxElementsIfNumericList&lt;/code&gt;&lt;/strong&gt;: Works the same as the aforementioned property except it applies to Lists of primitive types that are numeric. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;MaxStringLength&lt;/code&gt;&lt;/strong&gt;: This determines at which length a string value in the log should be trimmed. This helps to avoid logging large strings that will then muddy up the logs. Specify 0 if strings should not be trimmed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;IndentNumber&lt;/code&gt;&lt;/strong&gt;: Which isn't shown in the code example above. This is used to set the number of TABS you want to precede the code block name (and Prefix if one is set). This can be useful if you have the Profiler running in different layers of the application. An example would be any properly abstracted, where you might want to apply an &lt;code&gt;IndentNumber&lt;/code&gt; on code blocks running in the Business Layer, to help display a sort of hierarchy in code execution.&lt;/p&gt;

&lt;h3&gt;
  
  
  Starting a Timer/StopWatch
&lt;/h3&gt;

&lt;p&gt;In the above code example, you could see that a string value was passed in with the calls to &lt;code&gt;StartDebug()&lt;/code&gt;/&lt;code&gt;StopDebug()&lt;/code&gt;. Behind the scenes, Poor Man’s Profiler holds a collection of &lt;code&gt;StopWatch&lt;/code&gt; items, and we must correlate which items to Stop from a Start based on a name.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StartDebug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"TestMethod"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StopDebug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"TestMethod"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively, an explicit name doesn't have to be passed in which essentially makes the code more generic, if null is passed as the first parameter, the name of the calling block will be the calling method name pulled from the Stack Trace (ahh reflection).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StartDebug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, because the name isn't going to be known, you will need to grab the &lt;code&gt;LastStartID&lt;/code&gt; so that it can later be used with a call to &lt;code&gt;StopDebug()&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Test2&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Start a stopwatch on the method, let StartDebug get the name&lt;/span&gt;
    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StartDebug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Since we didnt pass a name, lets get the ID so we can use it when stopping the stopwatch&lt;/span&gt;
    &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;p1&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LastStartID&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Some code here …                &lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StopDebug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your first observations of the code block above may be: &lt;em&gt;“Why is he calling &lt;code&gt;StartDebug()&lt;/code&gt; and then assigning a variable of type long with the value of &lt;code&gt;LastStartID&lt;/code&gt;? Why not just return the ID with the &lt;code&gt;StartDebug()&lt;/code&gt;?”&lt;/em&gt; The answer to that question is both simple, and somewhat frustrating (for a lack of better words.) This is because the &lt;code&gt;StartDebug()&lt;/code&gt; method, along with other various methods are marked with the &lt;code&gt;[Conditional(“Debug”)]&lt;/code&gt; attribute, which means that these methods as well as any code that calls them will be excluded when the code is compiled in Release mode. This is how we can guarantee that Poor Man’s Logger will not cause any performance degrading overhead when the application is run in production.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;frustrating&lt;/em&gt; aspect of this is that this attribute can only be applied to &lt;code&gt;void&lt;/code&gt; return methods, which means there is a little more code that needs to be written. When you think about this limitation it makes sense, because one would not want code that is setting a value to a variable to suddenly disappear in production code, as this no doubt would lead to all sorts of problems. &lt;/p&gt;

&lt;p&gt;My workaround here was to have a property in the &lt;code&gt;DebugLogging&lt;/code&gt; class that will simply default to &lt;code&gt;0&lt;/code&gt; if not assigned to. When code is compiled in Release mode, and all the Poor Man’s Profiler code vanishes, at worse there will be various long typed variables defined that will all simply be set to &lt;code&gt;0&lt;/code&gt; and never actually used. &lt;/p&gt;

&lt;h3&gt;
  
  
  Logging Parameters
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;StartDebug()&lt;/code&gt; method can also be called with an unlimited number of parameters values which will in turn be logged.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StartDebug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CodeBlock1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This of course is where most additional overhead comes into play, as the parameters passed in are all boxed into type &lt;code&gt;object&lt;/code&gt;, so that any type of object can be passed in. Additionally reflection is used to obtain the actual type of the object parameters to best determine how to render their values in the logs. To top it off, a lot of string concatenation is also used here, which is another process that isn't known for high performance, and another thing to avoid when your end goal is high-performance code. The more parameter values you add, the more overhead you add, thus, add parameters sparingly.&lt;/p&gt;

&lt;p&gt;Despite the use of performance killer code (where Microsoft’s Ben Watson would likely shake his head in disapproval) interestingly enough, in my tests, the performance reduction due to boxing, reflection, and string concatenation is rather insignificant for debugging purposes. However caution should be taken regardless, and since every application should strive to gain every fraction of a millisecond of speed that it can gain, we only allow this to be run in debug, which is why the &lt;code&gt;StartDebug()&lt;/code&gt;/&lt;code&gt;StartDebug()&lt;/code&gt; methods are given the aforementioned conditional attribute. They run when in debug mode, and disappear when in release mode.&lt;/p&gt;

&lt;p&gt;With the first release of this library, using the logger to log parameter values is most useful if the parameters are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Any &lt;code&gt;object&lt;/code&gt; with a primitive type (with the addition of &lt;code&gt;DateTime&lt;/code&gt; and &lt;code&gt;Timespan&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;An implementation of &lt;code&gt;IList&lt;/code&gt; of any primitive type (with the addition of &lt;code&gt;DateTime&lt;/code&gt;, &lt;code&gt;Timespan&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Any &lt;code&gt;object&lt;/code&gt; of a non-primitive type or &lt;code&gt;IList&lt;/code&gt; of a non-primitive type which overrides the &lt;code&gt;base.ToString()&lt;/code&gt; method (which provides useful info about the object).&lt;/li&gt;
&lt;li&gt;Any &lt;code&gt;object&lt;/code&gt; that does not meet the criteria above will simply be logged by its type name, or essentially the return of &lt;code&gt;base.ToString()&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Additional Methods
&lt;/h3&gt;

&lt;p&gt;To stay on the safe side, I strongly suggest always using &lt;code&gt;StartDebug()&lt;/code&gt; and &lt;code&gt;StopDebug()&lt;/code&gt;, however I have exposed two alternative methods called &lt;code&gt;Start()&lt;/code&gt; and &lt;code&gt;Stop()&lt;/code&gt; that can be used with a little less code, however come with the caveat of not being able to be automatically removed when compiling in Release mode. The major downfall here is that if you use &lt;code&gt;Start()&lt;/code&gt; and pass in parameter values, you will be triggering boxing, despite the fact that when in non-debug mode, the method calls will not actually be doing anything with these boxed objects, since the internals of these methods are marked with the precompiler directives to exclude code when not in debug mode. The benefit of using &lt;code&gt;Start()&lt;/code&gt; is that you can get the ID for which to be used with &lt;code&gt;Stop()&lt;/code&gt; from the call itself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;p1&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The benefit of using &lt;code&gt;Stop()&lt;/code&gt; is that a double is returned representing total milliseconds in the event that you want to do something with this value besides the logging that is already happening internally.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Stop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I want to reiterate though, that these method calls will remain in Release code, so unless you don’t really care (i.e top performance isn't necessary) or you have a plan to remove them manually, just stick with &lt;code&gt;StartDebug()&lt;/code&gt;/&lt;code&gt;StopDebug()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;There are a couple of other useful methods that are marked with the debug conditional, thus are safe to leave in code:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;WriteParamValuesToString()&lt;/code&gt; which takes an unlimited list of parameter values to be logged which may be useful if you want to periodically log various variable values in strategic areas of code.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;WriteMessage()&lt;/code&gt; which takes a string to be logged.&lt;/p&gt;

&lt;h3&gt;
  
  
  Making Sense of the Logs
&lt;/h3&gt;

&lt;p&gt;Since the current working implementation of Poor Man’s Profiler writes to the Output window of the IDE, its likely going to be difficult to make whole lot of sense of things, especially since other events and messages are going to be logged in the same location.&lt;/p&gt;

&lt;p&gt;It isn’t exactly pretty, but there is a way to use this log dump, and turn it into something of more use. &lt;/p&gt;

&lt;p&gt;If there is interest in this, I could always write a log parser/aggregation application in &lt;strong&gt;Angular&lt;/strong&gt; and/or &lt;strong&gt;Blazor&lt;/strong&gt; as the topic of an upcoming article.&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;This article was meant to discuss a simple approach to .NET code profiling that can be used to time code block executions as well as log parameter/variable values. As noted, there are vendors who have created far more powerful frameworks for this need, as well as there are other ways to go about accomplishing this goal through AOP/IL Weaving to help reduce code redundancy. &lt;/p&gt;

&lt;p&gt;Once again, this article is based on my example class library project that can be found on GitHub -&amp;gt; &lt;a href="https://github.com/coreylasley/PoorMansLogger"&gt;Poor Man's Profiler&lt;/a&gt;&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>dotnetcore</category>
      <category>codeprofiling</category>
    </item>
    <item>
      <title>An Old ASP.NET MVC Developer’s Transition to Angular</title>
      <dc:creator>Corey Lasley</dc:creator>
      <pubDate>Sat, 25 Jan 2020 01:25:44 +0000</pubDate>
      <link>https://dev.to/coreylasley/an-old-asp-net-mvc-developer-s-transition-to-angular-43o1</link>
      <guid>https://dev.to/coreylasley/an-old-asp-net-mvc-developer-s-transition-to-angular-43o1</guid>
      <description>&lt;h3&gt;
  
  
  Applies To
&lt;/h3&gt;

&lt;p&gt;Angular CLI: 7.3.9&lt;br&gt;&lt;br&gt;
Node: 10.1.0&lt;br&gt;&lt;br&gt;
OS: Windows 10 x64&lt;/p&gt;
&lt;h3&gt;
  
  
  Objectives
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;What is needed to get started developing with Angular.&lt;/li&gt;
&lt;li&gt;Why we need Node.js.&lt;/li&gt;
&lt;li&gt;Why we use NPM.&lt;/li&gt;
&lt;li&gt;Why we use the Angular CLI.&lt;/li&gt;
&lt;li&gt;Why VS Code instead of Visual Studio.&lt;/li&gt;
&lt;li&gt;How to create our first project.&lt;/li&gt;
&lt;li&gt;Understanding the basic structure of our project.&lt;/li&gt;
&lt;li&gt;Understanding navigation.&lt;/li&gt;
&lt;li&gt;How to build the project for deployment.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Heads Up!
&lt;/h3&gt;

&lt;p&gt;Given the target audience of this article, an ASP.NET MVC Developer who wants to get a grasp on Angular, I am going to attempt to draw some comparisons between MVC and Angular that are loose at best. This is my effort to help bridge a gap of understanding. Clearly, these two technologies are very different, but both follow the Model View Controller pattern. Because of this, my comparisons between ASP.NET MVC and Angular are meant only as a guide, and not true representations of each other.&lt;/p&gt;
&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;I am ashamed to admit it, but I got really comfortable where I was. I had lived in the world of ASP.NET since .NET was birthed back in 2002. For many years I did everything Web Forms, but eventually transitioned into MVC. The design pattern between Web Forms and MVC was dramatic, to say the least, and it took me a bit before MVC felt natural.&lt;/p&gt;

&lt;p&gt;So here I have been for many years, sitting in my comfort zone, writing and maintaining ASP.NET MVC web applications, with jQuery as my default client-side JavaScript framework, and Visual Studio, my IDE of choice.&lt;/p&gt;

&lt;p&gt;I was introduced to Angular through a job change into a very forward-thinking and cutting edge driven organization that had made the decision to slowly move away from MVC, and transition into Single Page Applications (SPA) with Angular.&lt;/p&gt;

&lt;p&gt;I suspect you may be here because like me, you found yourself facing a transition away from ASP.NET MVC to Angular. Being so ingrained in the ways of ASP.NET MVC, you may be feeling a bit overwhelmed at just how different things are in the world of Angular. The goal of this article is to try to help get you started on that transaction. &lt;/p&gt;
&lt;h3&gt;
  
  
  Tools Needed for the Job
&lt;/h3&gt;

&lt;p&gt;I noticed many "Getting Started with Angular" articles either assumed the reader had some knowledge about Angular’s prerequisites, or that the reader likely didn’t care and/or need to know about the details as long as the reader was told what to install. Many articles are quick “do this, then that” type articles, which have their place, but for someone like myself who was jumping into completely new territory, I was looking for something more in depth that could give me more background on things. &lt;/p&gt;

&lt;p&gt;So lets break things down into some detail! We will need the following in order to start developing Angular apps:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Node.js&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
An open-source, cross-platform JavaScript run-time environment which can be used for server side, client side, desktop &amp;amp; mobile applications. Node.js is comparable to the .NET run-time environment which executes C#, VB.NET and other supported languages. Node.js is the first thing we will need to install. This is used to serve our application and includes &lt;strong&gt;NPM&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NPM&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Stands for “Node Package Manager”. It is a package manager for JavaScript built into Node.js. We will have NPM after we install Node.js. NPM is comparable to what NuGet is for .NET. NPM is needed to install the &lt;strong&gt;Angular CLI&lt;/strong&gt; as well as various packages that will be used in the Angular app. NPM commands are prefixed with the term “npm”.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Angular CLI&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Stands for “Angular Command Line Interface”. It simplifies creating angular apps by automating operations with quick commands so we don’t need to manually install and configure dependencies. Angular CLI commands are prefixed with the term “ng” (&lt;em&gt;ng&lt;/em&gt; stands for a*ng*ular). For more information on Angular CLI &lt;a href="https://cli.angular.io/" rel="noopener noreferrer"&gt;click here&lt;/a&gt;. For a deep X 5 dive into the Angular compiler, see the following &lt;a href="https://blog.angularindepth.com/a-deep-deep-deep-deep-deep-dive-into-the-angular-compiler-5379171ffb7a" rel="noopener noreferrer"&gt;blog&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I highly recommend the following items to enhance our experience:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Visual Studio Code&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Is optional, but the preferred editor. You can download it &lt;a href="https://code.visualstudio.com/download" rel="noopener noreferrer"&gt;here&lt;/a&gt;. You may be asking yourself: &lt;em&gt;Why use Visual Studio Code when we have Visual Studio&lt;/em&gt;?&lt;/p&gt;

&lt;p&gt;One thing I noticed when attending my first Angular conference, &lt;a href="https://www.ng-conf.org/" rel="noopener noreferrer"&gt;NG-Conf 2019&lt;/a&gt;, was that among everyone I saw writing/reading code on their laptops, they were all using VS Code, both attendees, and presenters. I cannot say I saw a single instance of Visual Studio running on any machine there. I’m not a big fan of simply defaulting to something because “&lt;em&gt;everyone else is doing it,&lt;/em&gt;” so here is my best guess.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Visual Studio&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Visual Studio Code (VS Code)&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cross Platform&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Open Source&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cost&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;FREE (Community Edition)&lt;/td&gt;
&lt;td&gt;FREE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Size&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1 GB (bare minimum)&lt;/td&gt;
&lt;td&gt;210 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Memory Consumption&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Generally Higher&lt;/td&gt;
&lt;td&gt;Generally Lower&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;VS Code may not have all the bells and whistles that Visual Studio has, however, being cross-platform and open source means that learning and teaching Angular development is going to be much easier when we have a common IDE that is available to all.&lt;/p&gt;

&lt;p&gt;For us veteran Visual Studio users, there are tutorials out there for creating Angular apps in Visual Studio, however, it probably isn’t a bad idea to just start getting used to using VS Code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Angular Essentials&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
This is an extension for Visual Studio Code put together by &lt;a href="https://johnpapa.net/" rel="noopener noreferrer"&gt;John Papa&lt;/a&gt;, which is essentially a collection some of the most popular extensions.&lt;/p&gt;

&lt;p&gt;Once we have everything above ready to go, in order to execute NPM / Angular CLI commands we can (1) Open command prompt, PowerShell, Git Bash, or something similar, or (2) use the Terminal window in VS Code (which basically opens up the previous option within the VS Code environment)&lt;/p&gt;
&lt;h3&gt;
  
  
  Setting Things Up
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Install &lt;code&gt;Node.js&lt;/code&gt;. The installation can be downloaded &lt;a href="https://nodejs.org/en/download/" rel="noopener noreferrer"&gt;here&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;NPM&lt;/code&gt; is built in to Node.js, so we are good to go here.&lt;/li&gt;
&lt;li&gt;Install the &lt;code&gt;Angular CLI&lt;/code&gt;. Open up a command prompt and execute the following:
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;npm install -g @angular/cli&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A Basic Look Under the Hood&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When &lt;strong&gt;Node.js&lt;/strong&gt; and the &lt;strong&gt;Angular CLI&lt;/strong&gt; are installed, you might be curious about how they integrate with your favorite command line interface. Entering the following command will give us a semicolon delimited list of all of the global paths we have defined in our system:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo %path%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;The two applicable paths that were setup during installation of Node.js are the following:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;c:\Program Files\nodejs\npm.cmd&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;:: Created by npm, please don't edit manually.
@ECHO OFF

SETLOCAL

SET "NODE_EXE=%~dp0\node.exe"
IF NOT EXIST "%NODE_EXE%" (
  SET "NODE_EXE=node"
)

SET "NPM_CLI_JS=%~dp0\node_modules\npm\bin\npm-cli.js"
FOR /F "delims=" %%F IN ('CALL "%NODE_EXE%" "%NPM_CLI_JS%" prefix -g') DO (
  SET "NPM_PREFIX_NPM_CLI_JS=%%F\node_modules\npm\bin\npm-cli.js"
)
IF EXIST "%NPM_PREFIX_NPM_CLI_JS%" (
  SET "NPM_CLI_JS=%NPM_PREFIX_NPM_CLI_JS%"
)

"%NODE_EXE%" "%NPM_CLI_JS%" %*
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;C:\Users\[My Username]\AppData\Roaming\npm\npm.cmd&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@IF EXIST "%~dp0\node.exe" (
  "%~dp0\node.exe"  "%~dp0\node_modules\@angular\cli\bin\ng" %*
) ELSE (
  @SETLOCAL
  @SET PATHEXT=%PATHEXT:;.JS;=;%
  node  "%~dp0\node_modules\@angular\cli\bin\ng" %*
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will also need the following file after we install the Angular CLI:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;C:\Users\[My Username]\AppData\Roaming\npm\ng.cmd&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@IF EXIST "%~dp0\node.exe" (
  "%~dp0\node.exe"  "%~dp0\node_modules\npm\bin\npm-cli.js" %*
) ELSE (
  @SETLOCAL
  @SET PATHEXT=%PATHEXT:;.JS;=;%
  node  "%~dp0\node_modules\npm\bin\npm-cli.js" %*
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are the paths that allow the command prompt, PowerShell, Git Bash, etc. to know where they can find the &lt;code&gt;npm&lt;/code&gt; and &lt;code&gt;ng&lt;/code&gt; commands (which ultimately point to&lt;br&gt;
node.exe) no matter what directory we currently reside in, while putting our current directory in scope for the commands’ execution.&lt;/p&gt;
&lt;h3&gt;
  
  
  Get Comfortable with the Command Line
&lt;/h3&gt;

&lt;p&gt;In my early days as a developer (way back in the late 1990’s early 2000’s,) GUIs were all the rage. Getting away from command line interfaces was the thing most users wanted, and most developers strived to produce. Visual Studio has done a great job over the years of providing a GUI for virtually everything, from project creation to interacting with Git repositories. Since becoming a developer, command-line tools seem to be more popular now due to open source. This makes sense, because an application needs to work within multiple platforms. Creating a GUI to support a wide range of commands and options can be time consuming with little real gain.&lt;/p&gt;

&lt;p&gt;If you are anything like me, moving away from Visual Studio was definitely a move outside of my comfort zone. This was mostly due to shifting away from GUI's. GUI's provide menus, icons, and buttons to run commands. Whereas, you have to commit various commands to memory, or have a handy cheat sheet available, to use the command-line.&lt;/p&gt;

&lt;p&gt;But alas! I quickly discovered that the move wasn't as bad as I thought it would be.&lt;/p&gt;
&lt;h3&gt;
  
  
  Creating Our First Project
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Visual Studio&lt;/em&gt; users might expect to open up &lt;em&gt;VS Code&lt;/em&gt; and find a &lt;em&gt;File &amp;gt; New Project…&lt;/em&gt; menu item, and then complete a short wizard for setting up an Angular app, but this isn't how things are done in this general purpose lightweight IDE. In order to create a new Angular app, we need to use the Angular CLI. The Angular CLI will setup a basic project template with all of the basic files, configurations, and the structure needed to be able to immediatly run the application.&lt;/p&gt;

&lt;p&gt;In the command prompt we will first want to change directory to the root folder where we want our Angular app set up. An example would be:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd c:\Temp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Next, run the ng new command with the name of the app we want to create:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng new my-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;We will be prompted to add Angular routing or not. For this project, please answer &lt;strong&gt;yes&lt;/strong&gt;, since we will utilize this later. &lt;/p&gt;

&lt;p&gt;We will then be prompted for which stylesheet format to use, I recommend selecting &lt;code&gt;SCSS&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/media%2F51fc98f6f61ed9d39c1d44ca9a7e4931.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/media%2F51fc98f6f61ed9d39c1d44ca9a7e4931.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This will then create a new folder within the directory we are currently in, as&lt;br&gt;
well as all the files needed.&lt;/p&gt;

&lt;p&gt;*If we get an “Unexpected end of JSON input while parsing near” error after executing an &lt;em&gt;ng new&lt;/em&gt; command, something in our cache is likely corrupt. This was the case for me at one point, because I had previously installed things without understanding what I was doing, and things went stale. One way I was able to solve this was by executing the following command:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm cache clean --force
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Once this is completed, we need to change directory into our new application folder:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd my-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;We can now run the application with the following command:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng serve --open
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;This will start the server, and then open the application in the browser.&lt;/p&gt;

&lt;p&gt;When executing &lt;code&gt;ng serve&lt;/code&gt;, the local server fires up and runs until you stop it, usually by typing &lt;code&gt;[Ctrl][c]&lt;/code&gt; in the terminal window. One really nice feature of this local server is that it utilizes a File System Watcher mechanism (possibly &lt;a href="https://nodejs.org/api/fs.html#fs_fs_watchfile_filename_options_listener" rel="noopener noreferrer"&gt;fs.watchFile&lt;/a&gt; built into node.js) that detects when there are changes to files within your directory structure. When a change is detected, such as when a file is saved, the server automatically re-compiles the application, and then refreshes it within the browser.  &lt;/p&gt;
&lt;h3&gt;
  
  
  Understanding Our First Project
&lt;/h3&gt;

&lt;p&gt;To begin editing the code, we do the following: Within VS Code, on&lt;br&gt;
the menu, select File &amp;gt; Open Folder…&lt;/p&gt;

&lt;p&gt;When I opened up my first Angular project folder in VS Code, I was overwhelmed and confused by all of the files created, as you might be. There will be very little that will look familiar to the old ASP.NET MVC developer. Despite there being a lot to digest here, there really are only a handful of files that we need to be worried about, at least for now.&lt;/p&gt;

&lt;p&gt;The first thing we might notice, is that there are no core project and solution files that we are used to having associated with our .NET applications. When it comes to Angular development, everything simply resides within a directory structure. So rather than having Angular project files that keep track of the other files, references, etc. that belong to the project; files reside within the base directory and its subdirectories. This structure &lt;em&gt;is&lt;/em&gt; our project. Therefore, when we open up a project in VS Code, instead of opening up a file, we open up a directory.&lt;/p&gt;

&lt;p&gt;Let’s get acquainted with the following files:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;package.json&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
This file contains the list of node dependencies, and it can be &lt;em&gt;somewhat&lt;/em&gt; likened to a list of References in any ASP.NET project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;src/index.html&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
This file is basically a simple placeholder for our core Component. This is similar to the application-wide shared layout View in MVC (often named _layout). This is the core html that will be rendered for the application. Rather than adding additional html pages, you will use &lt;em&gt;Angular Components&lt;/em&gt; with &lt;a href="https://angular.io/guide/router" rel="noopener noreferrer"&gt;Angular Routing&lt;/a&gt; which will be discussed later.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!doctype html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;MyApp&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;base&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"icon"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"image/x-icon"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"favicon.ico"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;app-root&amp;gt;&amp;lt;/app-root&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Everything in here should look pretty standard, that is, with the exception of the non-standard &lt;code&gt;&amp;lt;app-root&amp;gt;&lt;/code&gt; tag (line 12.) We will talk more about this next since it relates to Angular Components.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;app/app.component.&lt;/strong&gt;*&lt;br&gt;&lt;br&gt;
You will see several files in the app folder that starts with &lt;em&gt;app.component.&lt;/em&gt; These files are all related to each other and make up an &lt;a href="https://angular.io/guide/architecture-components" rel="noopener noreferrer"&gt;Angular Component&lt;/a&gt;. For comparison purposes, a component would look most like an MVC View or Partial View. Instead of creating additional HTML files on the root (in addition to Index.html) you will be creating more Components.&lt;/p&gt;

&lt;p&gt;This particular component, however, is slightly different from other components you will create, because it is the root or parent component of the application and is generally associated with the &lt;em&gt;Index.html&lt;/em&gt;. All other components that you create will exist in a parent/child hierarchy under this component. In a way, you could think of this component as the application’s core View or Layout, whereas all other components you add to the project would be like Partial Views.&lt;/p&gt;

&lt;p&gt;The main component file is a &lt;a href="https://www.typescriptlang.org/" rel="noopener noreferrer"&gt;TypeScript&lt;/a&gt; file called &lt;strong&gt;app.component.ts&lt;/strong&gt;. This file is essentially the definition of the component where you set its various properties, wire up event handling, update the DOM, make calls to services, etc. This is like a Controller blended with a Model in MVC.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  title = 'my-app';
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A key thing to note here is the &lt;code&gt;@Component&lt;/code&gt; decorator section (line 3-7). This defines various properties of the component. When a project is first created with a default component, these three properties are established.&lt;/p&gt;

&lt;p&gt;Looking at line 4 you see the &lt;code&gt;selector&lt;/code&gt; property with a value of &lt;code&gt;‘app-root’&lt;/code&gt;. If you remember back to the &lt;strong&gt;&lt;code&gt;Index.html&lt;/code&gt;&lt;/strong&gt; file, there was that non-standard HTML tag &lt;code&gt;&amp;lt;app-root&amp;gt;&lt;/code&gt;. This means that the rendered content of this component is going to be placed where this &lt;code&gt;&amp;lt;app-root&amp;gt;&lt;/code&gt; tag resides in the &lt;code&gt;Index.html&lt;/code&gt;. Basically it is a placeholder for a component's content. Within MVC, this &lt;code&gt;&amp;lt;app-root&amp;gt;&lt;/code&gt; tag would be somewhat comparable to a &lt;code&gt;@RendyBody()&lt;/code&gt; in a Layout or placehold tags within components. It would be comparable to an &lt;code&gt;@Html.Partial()&lt;/code&gt; within a View.&lt;/p&gt;

&lt;p&gt;Looking at line 5 you see the &lt;code&gt;templateUrl&lt;/code&gt; property. Its value points to the &lt;strong&gt;&lt;code&gt;app.component.html&lt;/code&gt;&lt;/strong&gt; file. This file is where you can define the HTML that you want your component to render. Line 6 contains the &lt;code&gt;styleUrls&lt;/code&gt; property. It maps to the &lt;strong&gt;&lt;code&gt;app.component.css&lt;/code&gt;&lt;/strong&gt; file which contains the CSS for this specific component.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;src/app/app_module.ts&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
This is an important TypeScript file which is used to declare your components. If your components are not declared here, they will not be able to be consumed within your application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;dist&lt;/strong&gt; (Folder)&lt;br&gt;&lt;br&gt;
This is a folder that will not exist until you execute the &lt;code&gt;ng build&lt;/code&gt; command (I will discuss &lt;code&gt;ng build&lt;/code&gt; in detail later). This folder contains the output of the build and represents the content to be deployed to a web server. &lt;/p&gt;

&lt;p&gt;So, to recap a bit on the descriptions above, the following image shows the contents of an Angular 7 application, loosely compared to an MVC application:  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/media%2FAngularAndMVCCompared.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/media%2FAngularAndMVCCompared.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Get Comfortable with Angular CLI Commands
&lt;/h3&gt;

&lt;p&gt;It is important to note that there is a lot more to the Angular CLI than simply instantiating, building and serving your project. The old ASP.NET developer, like me, might be tempted to use VS Code’s File menu to add new items to the application. In some cases you might create files manually, but for many types of Angular items you are going to want to let the Angular CLI to do the work for you. Adding certain types of items often requires adding and modifying multiple files. The Angular CLI is here to save us a considerable amount of time and headache.&lt;/p&gt;

&lt;p&gt;An example of this would be adding a new component to our application. Lets say we want to add a new component called "about". To do this you would execute the following:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng generate component about
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;This will add a new folder within the &lt;code&gt;app&lt;/code&gt; folder representing a new component. It will generate default/template code for a &lt;code&gt;.css&lt;/code&gt;, &lt;code&gt;.html&lt;/code&gt;, &lt;code&gt;.spec.ts&lt;/code&gt;, and &lt;code&gt;.ts&lt;/code&gt; file for this component. Additionally it will modify &lt;code&gt;app.module.ts&lt;/code&gt; to declare this new component. &lt;/p&gt;
&lt;h3&gt;
  
  
  A Quick Introduction to Angular Routing and Navigation
&lt;/h3&gt;

&lt;p&gt;Not wanting to dig too deep into the rich features of Angular in this article, I feel that our time together here would be incomplete if I didn’t touch on Angular’s powerful routing capabilities. Routing is important for old ASP.NET developers who are used to writing applications that have mutiple “pages". In the world of ASP.NET MVC, we are used to having Controllers, Models, and Views to represent each page in our application. When it came to figuring out how to deal with multiple pages in Angular, my first thought was that our &lt;code&gt;Index.html&lt;/code&gt; was sort of like our &lt;code&gt;Home.chtml&lt;/code&gt; in MVC, and in order to create another page for something such as “About Us,” I would probably need to create an &lt;code&gt;AboutUs.html&lt;/code&gt; page. This didn’t feel right, especially since I became accustomed to thinking of the &lt;code&gt;Index.html&lt;/code&gt; more like our global layout/placeholder, so I asked my good friend and Angular expert, &lt;a href="https://wesleygrimes.com/" rel="noopener noreferrer"&gt;Wes Grimes&lt;/a&gt; about this. Wes told me to look at Routing. Well, it only took a quick scan at &lt;a href="https://angular.io/guide/router" rel="noopener noreferrer"&gt;Angular’s official documentation on this&lt;/a&gt;, and I got really excited. While Routing in ASP.NET MVC is pretty slick, Routing in Angular steps up the game!  &lt;/p&gt;

&lt;p&gt;Angular’s implementation of routing is where you assign paths that map to various components. These are essentially our Views. The default &lt;code&gt;app.component&lt;/code&gt; becomes the container for everything. When our URL matches a defined path, the router “directs” to the &lt;code&gt;app.component&lt;/code&gt;, and replaces the contents inside the &lt;code&gt;&amp;lt;router-outlet&amp;gt;&lt;/code&gt; tag with the rendered contents of the mapped component. In addition to this, the part that really got me pumped was instead of using &lt;code&gt;href&lt;/code&gt; attribute in anchor tags (which you can do), we instead use the &lt;code&gt;routerLink&lt;/code&gt; attribute. When the user clicks the link, the mapped component is simply swapped out in the DOM via lazy loading and the browser’s URL changes! There is no browser redirecting, and only the mapped component section is refreshed. This makes the flow seamless, dramatically speeds up navigation between “pages”, and reduces the amount of content coming down the pipe. It truly gives the end user the perception that the entire application exists on the same page (Well, I guess technically it does, but you know what I mean.)     &lt;/p&gt;

&lt;p&gt;So let’s break this down. If we remember back to earlier when we first created our application, I said we should select “yes” when asked if we wanted to set up Routing. This is where we are going to put this to use. &lt;/p&gt;

&lt;p&gt;Lets say we have a few components created to represent several pages. We will have a home component, an about component, and a page-not-found component. Within our &lt;code&gt;app.module.ts&lt;/code&gt; file, just under the &lt;code&gt;import&lt;/code&gt; lines, add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const appRoutes: Routes = [
  { path: 'about', component: AboutComponent },
  { path: 'home', component: HomeComponent },
  { path: '', component: HomeComponent },
  { path: '**', component: PageNotFoundComponent }
];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice the path values for each of these components. The 'about' and 'home' paths should be fairly obvious, but what about the '' path, and the path specified for the PageNotFoundComponent? As far as the '' path, this just means that if no particular path is defined, then route to the home component. As for the &lt;code&gt;**&lt;/code&gt; path, this simply means that if any other path is given that does not match one of the above, then route to the page-not-found component.&lt;/p&gt;

&lt;p&gt;Next, within the &lt;code&gt;@NgModule&lt;/code&gt; area we want to add the following within the &lt;code&gt;imports&lt;/code&gt; section:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;RouterModule.forRoot(
      appRoutes
    )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So it will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@NgModule({
  declarations: [
    AppComponent,
    PageNotFoundComponent,
    AboutContentComponent,
    HomeContentComponent
  ],
  imports: [
    RouterModule.forRoot(
      appRoutes
    ),
    BrowserModule,
    AppRoutingModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly, go to your &lt;code&gt;app.component.html&lt;/code&gt; and place the following tag wherever it is you would like your home, about, and page not found components to render.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;router-outlet&amp;gt;&amp;lt;/router-outlet&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, wherever you wish to place a link in any of your HTML, instead of using the standard anchor tag markup, it is going to look a little different. Lets say that we want to place a link to the about "page," our markup will look like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;routerLink=&lt;/span&gt;&lt;span class="s"&gt;"about"&lt;/span&gt; &lt;span class="na"&gt;routerLinkActive=&lt;/span&gt;&lt;span class="s"&gt;"active"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;About Us&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Navigation is as simple as that!&lt;/p&gt;

&lt;h3&gt;
  
  
  Building for Deployment
&lt;/h3&gt;

&lt;p&gt;For the last part of this article, I want to show you how to do an official build for deployment. There is so much more you can do, but lets wrap up this particular app.&lt;/p&gt;

&lt;p&gt;We can always run our application locally with the &lt;code&gt;ng serve&lt;/code&gt; command, but when it comes time to deploy our application, we need to perform a build. To do so, execute one of the following Angular CLI commands:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng build --prod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;or&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng b --prod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This will create a folder on the root called “dist”. This will contain your compiled application. The Angular CLI uses a JavaScript module bundler called Webpack. It compiles everything down to what the browsers understands: HTML, CSS, and JavaScript.&lt;/p&gt;

&lt;p&gt;At this point, you might think that you can simply use file explorer to browse to &lt;code&gt;C:\Temp\my-app\dist\my-app&lt;/code&gt; and double-click the &lt;code&gt;Index.html&lt;/code&gt; to see the application work, however when you do, you will likely see a blank page. The index.html loaded, but the JavaScript didn’t execute.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/media%2Fc238bef9193d613d1c854a77df84deda.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/media%2Fc238bef9193d613d1c854a77df84deda.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The problem here resides with &lt;em&gt;base-href&lt;/em&gt; mapping. If your application was sitting on the root of the system, the above build would run, however because it resides in a subfolder on the system, you need to specify the &lt;em&gt;base-href&lt;/em&gt; location in the build command:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng build --base-href "C:\Temp\my-app\dist\my-app\" --prod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Keep in mind that this also applies when deploying to a web server.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/media%2F422440141b218beff2aac436183a5bbd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/media%2F422440141b218beff2aac436183a5bbd.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;It is my hope that if you are an old ASP.NET MVC developer like me, who has been on the fence about checking out Angular, this article has given you some insight as to how things work, and helped to build some confidence in diving in to some Angular development. I am planning on a Part II in the near future. With this I will go into more depth with some things that you can do within your components.&lt;/p&gt;

</description>
      <category>aspnet</category>
      <category>angular</category>
      <category>mvc</category>
    </item>
  </channel>
</rss>
