<?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>Forem: Alexander Johnston</title>
    <description>The latest articles on Forem by Alexander Johnston (@alexanderjohnston).</description>
    <link>https://forem.com/alexanderjohnston</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%2F179093%2Faadece4e-2953-47f4-9aa3-eeb878932e7b.jpeg</url>
      <title>Forem: Alexander Johnston</title>
      <link>https://forem.com/alexanderjohnston</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/alexanderjohnston"/>
    <language>en</language>
    <item>
      <title>On Building Communities</title>
      <dc:creator>Alexander Johnston</dc:creator>
      <pubDate>Fri, 10 Apr 2020 19:08:33 +0000</pubDate>
      <link>https://forem.com/dealeron/on-building-communities-46n6</link>
      <guid>https://forem.com/dealeron/on-building-communities-46n6</guid>
      <description>&lt;p&gt;Here at DealerOn we have a special kind of environment of enabling each other to pursue our interests and contribute to the effort in a personal way. Part of that is shown through the numerous blog articles written here; each one done by a volunteer and the topics left completely open-ended for us to explore what we think is worth sharing. This principle extends into all our activities from internal hackathons, events, and even the way we share ideas with each other. There is a sense of community involvement which extends past the work itself and drives us.&lt;/p&gt;

&lt;p&gt;I first encountered C# early on in 2002 when it was still not even a year old as an official language. I was new to programming but my questions were taken seriously by helpful members of the community. Those moments of helpfulness are what stuck with me throughout my time with the language and I’ve seen the development community around it grow into the great ecosystem that it is today. While this isn’t unique to the .NET, it is an important quality in building a diverse platform.&lt;/p&gt;

&lt;p&gt;Along the way I have been lucky to be mentored by many of these talented individuals who are passionate about sharing their work for other people to use. The idea of being able to build tools for other people to use is what caught my interest and ultimately pushed me down a path to learning more. Despite this, it would still take me at least ten years to learn how to develop any original software in C#. The barriers to entry were too high early on and I never stumbled upon the right resources. &lt;/p&gt;

&lt;p&gt;Today, I see whole libraries of videos done by professionals and curated by sites like Pluralsight; there are numerous high quality guides for getting started on the Microsoft docs and blogs themselves; and even YouTube and social media sites like Reddit are now seeing thriving communities for learning how to develop. We have also seen a surge in cooperative development tools. Today I can use Live Share to connect with someone working on a cross-platform app without even leaving the IDE. I can watch them deploy that app to the cloud with a couple clicks and see it automatically provision a server in real time.&lt;/p&gt;

&lt;p&gt;With all of these new tools and the lower barriers to entry, I have seen the community come out in force to support learning opportunities. There are now innumerable IRC servers, Discord servers, forums, and other groups out there spending their time mentoring juniors on open-source projects. Not to mention that .NET Core now runs cross-platform, so we can collaborate with users of other operating systems. All of this means more libraries being built, better tutorials being written, with greater access to teachers for those who are new to programming.&lt;/p&gt;

&lt;p&gt;The future looks good for the .NET community and Microsoft has clearly been invested in supporting it. Later this year .NET 5 will launch and with it we will all surely have new API surfaces to learn; there will be the usual issues with assemblies and broken references. NuGet packages will need to be updated. StackOverflow will be full of weird issues that everyone keeps running into as they try to migrate their apps. Despite the growing pains, it is up to everyone to help each other out. It’s only through the collective effort of trying, failing, researching, and sharing that we all contribute our shared success.&lt;/p&gt;

&lt;p&gt;This has all been a long winded way to say that in a sense, building a community is about investing in individuals. It is not an easy task to build an environment where learning is the default and where failure is seen as an opportunity to improve. I believe that in many ways this philosophy exists at DealerOn and is influenced heavily by the larger .NET community. It’s important that we always ask ourselves how we can give back to the community and how we can make things easier for the next team who comes along. Thanks for listening.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
    </item>
    <item>
      <title>Exception Handling and Telemetry with PostSharp, Application Insights, and Grafana</title>
      <dc:creator>Alexander Johnston</dc:creator>
      <pubDate>Fri, 07 Jun 2019 13:01:01 +0000</pubDate>
      <link>https://forem.com/dealeron/exception-handling-and-telemetry-with-postsharp-application-insights-and-grafana-5bie</link>
      <guid>https://forem.com/dealeron/exception-handling-and-telemetry-with-postsharp-application-insights-and-grafana-5bie</guid>
      <description>PostSharp is a pattern-aware extension for C# which runs during the compilation stage.

&lt;p&gt;Whether you’re just getting started with .NET or have been using it for its lifetime, there are concerns every project has to face eventually. &lt;a href="https://dev.to/dealeron/automating-net-core-services-with-postsharp-and-aspect-oriented-code-2j8i"&gt;In a previous article&lt;/a&gt;, I discussed how PostSharp can be used to target concerns like logging and threading. Today, I will show you how we can apply these same principles to exception handling to send real-time telemetry to Application Insights.&lt;/p&gt;

&lt;h3&gt;
  
  
  Remarks
&lt;/h3&gt;

&lt;p&gt;Exception handling is a topic with depth far beyond the scope of this article. The code I reference here is not designed to be as fast or as efficient as possible. This is in the interest of showcasing each of the features and creating a usable demonstration which readers can then improve upon for their own purposes. You are always welcome to get in contact with me for clarification or advice on these topics; I also welcome you to point out errors, mistakes, or even make pull-requests to the repository as you see fit.&lt;/p&gt;

&lt;p&gt;My goal is to explore .NET Core cross-platform capabilities and show you how Exception Handling can be integrated with the following tools:&lt;/p&gt;

&lt;p&gt;· &lt;a href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/generic-host?view=aspnetcore-2.2"&gt;.NET Generic Host&lt;/a&gt; is an all-in-one package for handling configuration, dependency injection, logging, and other app startup concerns. If you want to host async services, then you can do it out of the box now with very little setup time. For us it will simplify a lot of the boilerplate needed to prototype interesting &lt;a href="https://en.wikipedia.org/wiki/Aspect-oriented_programming"&gt;AOP&lt;/a&gt; use-cases.&lt;/p&gt;

&lt;p&gt;· &lt;a href="https://docs.microsoft.com/en-us/azure/azure-monitor/app/app-insights-overview"&gt;Azure Application Insights&lt;/a&gt; is a big suite of services which focus on monitoring performance in real-time. You can send events, metrics, and all sorts off custom measurements up to Azure and then immediately query it through &lt;a href="https://docs.microsoft.com/en-us/azure/azure-monitor/log-query/log-query-overview"&gt;Log Analytics&lt;/a&gt;. The goal here will be to handle our exceptions by logging them up in the cloud where we can get regular snapshots of the application’s state.&lt;/p&gt;

&lt;p&gt;· &lt;a href="https://grafana.com/"&gt;Grafana&lt;/a&gt; is a wonderful, &lt;a href="https://github.com/grafana/grafana"&gt;open-source&lt;/a&gt; tool for creating dashboards which track metrics or visualize data as graphs. You can host it yourself but there is also a free and paid cloud-hosted option. The free option is ideal for prototyping and has all of the features we need for now.&lt;/p&gt;

&lt;p&gt;Using the power of a pattern-aware compiler, this cross-cutting concern can be seamlessly hooked up to an external monitoring service without adding &lt;code&gt;try {} catch {}&lt;/code&gt; blocks everywhere in your codebase. This lack of clutter helps to keep your code clear and understandable and reduces the number of concerns placed upon your team.&lt;/p&gt;

&lt;h3&gt;
  
  
  Before We Begin
&lt;/h3&gt;

&lt;p&gt;Readers who wish to follow along should take the following steps to set up their environment:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Download the &lt;a href="https://dotnet.microsoft.com/download"&gt;.NET Core SDK and Runtime&lt;/a&gt;. I will be using VS 2017 on .NET Core SDK 2.2.106&lt;/li&gt;
&lt;li&gt;Download the latest stable PostSharp Extension &lt;a href="https://marketplace.visualstudio.com/items?itemName=PostSharpTechnologies.PostSharp"&gt;from the VS Marketplace&lt;/a&gt;. Version 6.1.18 is used here.&lt;/li&gt;
&lt;li&gt;Clone the Semantic branch of &lt;a href="https://github.com/AlexanderJohnston/SharpCrafting/tree/Semantic"&gt;my SharpCrafting repository&lt;/a&gt; or follow my &lt;a href="https://dev.to/sohjsolwin/automating-net-core-services-with-postsharp-and-aspect-oriented-code-349g-temp-slug-7775299"&gt;previous article&lt;/a&gt; to build your own threaded Generic Host.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Understanding Pattern-Aware Exception Handling
&lt;/h3&gt;

&lt;p&gt;An exception handler typically requires you to use some form of &lt;code&gt;try { } catch { } finally { }&lt;/code&gt; statements which require every class to know its own context well enough to either bubble up, swallow, or handle an exception which occurs from within. An incorrectly handled exception can easily cause a service interruption or similarly poor experience for an end-user. This puts a burden of documentation and knowledge on any development team to understand the overall error-handling architecture outside the scope of any specific feature.&lt;/p&gt;

&lt;p&gt;For example, in one solution alone I have found several hundred instances of &lt;code&gt;try { }&lt;/code&gt; blocks. This can be rough if you run distributed, remote workers because the Exception may need to cross many boundaries without losing its original caller and state. Among those hundreds of &lt;code&gt;try { }&lt;/code&gt; blocks there will undoubtedly be one or two which fail to handle as originally intended due to the slow feature creep of business needs. If those needs ever change significantly then there is a risk that any one of the handlers will be overlooked for compatibility. This can cause swallowed exceptions or an undecipherable call stack. The possibility of incorrectly handling exceptions becomes a major obstacle against refactoring and thus a tough sell for teams and project managers.&lt;/p&gt;

&lt;p&gt;This is where aspect-oriented designs step in to provide a solution by consolidating your logic into a common place.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://doc.postsharp.net/exception-handling"&gt;Handling Exceptions&lt;/a&gt; is a primary feature of the PostSharp namespace and I recommend reading it before continuing. The following objects are provided to us for a basic implementation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;a href="https://doc.postsharp.net/t_postsharp_aspects_onexceptionaspect"&gt;OnExceptionAspect&lt;/a&gt; class which lives in &lt;a href="https://doc.postsharp.net/n_postsharp_aspects"&gt;PostSharp.Aspects&lt;/a&gt;. This defines an exception handler around a method which will intercept any thrown exceptions and can handle them at a higher level.&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://doc.postsharp.net/t_postsharp_aspects_methodexecutionargs"&gt;MethodExecutionArgs&lt;/a&gt; class which provides arguments containing advice for your handler. You can use these arguments to get the original exception, the arguments provided by the original caller to the intercepted method, and the flow behavior for execution.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The official &lt;a href="https://samples.postsharp.net/f/PostSharp.Samples.ExceptionHandling"&gt;PostSharp samples for Exception Handling&lt;/a&gt; are a great source to keep open alongside any documentation. I will borrow from the samples to show you an example of this implementation in action.&lt;/p&gt;

&lt;p&gt;The first example is the “Add Context On Exception” &lt;a href="https://samples.postsharp.net/f/PostSharp.Samples.ExceptionHandling/AddContextOnExceptionAttribute.cs.html"&gt;Attribute&lt;/a&gt;. When an exception is intercepted by this attribute it will append the value of parameters to the exception. Having access to the argument values when reading over the exception later in the logs can save time debugging. This is an exceptional feature to have if you’re dealing with a bug that can’t be reproduced easily. In many cases it would have saved me hours of time to just know which arguments caused an exception in the first place.&lt;/p&gt;

&lt;p&gt;This class has a few points of interest:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First, it inherits the &lt;a href="https://doc.postsharp.net/t_postsharp_aspects_onexceptionaspect"&gt;OnExceptionAspect&lt;/a&gt; class which provides an exception handler.&lt;/li&gt;
&lt;li&gt;Next, it intercepts exceptions thrown with &lt;code&gt;OnException( MethodExecutionArgs args )&lt;/code&gt; and tracks their state with the &lt;code&gt;MethodExecutionArgs&lt;/code&gt; mentioned earlier.&lt;/li&gt;
&lt;li&gt;Last, it builds a string containing the context including arguments, declaring type, generics, and method name. These are added to the Exception’s ”Context” index on the &lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.exception.data?view=netcore-2.2"&gt;Data property&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The second example from the official samples is the “Report And Swallow Exception” Attribute. This one interacts directly with the previous attribute by reading the ”Context” added by the handling performed in the &lt;code&gt;AddContextOnException&lt;/code&gt; attribute. A few things to note:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The aspect declares an [AspectTypeDependency] which is &lt;a href="https://doc.postsharp.net/aspect-dependencies"&gt;a way to handle aspect dependencies&lt;/a&gt; on the same target. In this case it declares that it must come after the &lt;code&gt;AddContextOnException&lt;/code&gt; attribute if applied to the same target.&lt;/li&gt;
&lt;li&gt;It checks to see if there is an &lt;code&gt;additionalContext&lt;/code&gt; by checking the Exception’s Data property for any information added earlier on via the &lt;code&gt;StringBuilder&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  Applying Our Understanding With Azure
&lt;/h3&gt;

&lt;p&gt;While these samples may seem basic, this is all you need to immediately integrate your applications with third party tools. I find that Application Insights is perfectly suited for a task like this since it is designed to have a low barrier to entry with a simple API. Let’s go over the next steps to see what our goals are and how we can implement them.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;An Azure account will be needed for this, but &lt;a href="https://azure.microsoft.com/en-us/free/"&gt;luckily it comes with a free trial&lt;/a&gt; and is quick to setup. If this is your first time then &lt;a href="https://azure.microsoft.com/en-us/resources/videos/sign-up-for-microsoft-azure/"&gt;I recommend this video&lt;/a&gt; which shows you how to complete the entire process in just a few seconds.&lt;/li&gt;
&lt;li&gt;Create a new Application Insights resource through Azure. Grab the &lt;strong&gt;“Instrumentation Key”&lt;/strong&gt; from the Overview page.&lt;/li&gt;
&lt;li&gt;Copy down your &lt;strong&gt;“Application ID”&lt;/strong&gt; from the &lt;strong&gt;“API Access”&lt;/strong&gt; menu of your Application Insights resource.&lt;/li&gt;
&lt;li&gt;Create an API key and copy it down as well. This can be done in the same &lt;strong&gt;“API Access”&lt;/strong&gt; menu. Provide it all three options [Read Telemetry, Write Annotations, and Authenticate SDK].&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OC1wUWr2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/tl8pj8e7pctsw3tw14wf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OC1wUWr2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/tl8pj8e7pctsw3tw14wf.png" alt=""&gt;&lt;/a&gt;Example of the Azure API key for Application ID.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1fJ5uztM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/y02eyollk0o2l97gd7g4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1fJ5uztM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/y02eyollk0o2l97gd7g4.png" alt=""&gt;&lt;/a&gt;Example of the Azure API key for Instrumentation and Subscription.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--83Ns7l8c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/whihlygtbav199u5zvop.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--83Ns7l8c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/whihlygtbav199u5zvop.png" alt=""&gt;&lt;/a&gt;Example of creating an API key in Azure.&lt;/p&gt;

&lt;p&gt;We’ll use these pieces of information later to integrate our real-time metrics with Grafana. For now, store those keys in a safe place and let’s revisit our code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Integrating PostSharp With Azure
&lt;/h3&gt;

&lt;p&gt;The goal here will be to write custom events to Azure describing an exception every time one is handled. We can restrict this to just two classes, one for Azure and one for the Exception Handler, by utilizing the &lt;a href="https://doc.postsharp.net/t_postsharp_aspects_onexceptionaspect"&gt;OnExceptionAspect&lt;/a&gt; which we learned about earlier from the PostSharp samples. First, let’s write an Aspect to do the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Catch an exception.&lt;/li&gt;
&lt;li&gt;Read the arguments.&lt;/li&gt;
&lt;li&gt;Read the target name.&lt;/li&gt;
&lt;li&gt;Read the Exception type and its message.&lt;/li&gt;
&lt;li&gt;Mark a custom event with these properties on Azure and log them locally.&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Let’s break down this class to see where Azure was included specifically:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;We can see here that the Azure integration allows us to pass a dictionary of properties (similar to a JSON structure) into the custom event and all we have to do is give it a context. In this case the context is an “Exception”. That’s all there is to it! The only other configuration we need to connect to Azure is to add two files to our project. &lt;code&gt;Monitor.cs&lt;/code&gt; and &lt;code&gt;ApplicationInsights.config&lt;/code&gt;&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;In the above code we just need to replace &lt;strong&gt;“Your Key Here”&lt;/strong&gt; with the Instrumentation Key we pulled from Azure earlier. Then we add this &lt;code&gt;ApplicationInsights.config&lt;/code&gt; file to the folder containing our &lt;code&gt;.csproj&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;In the &lt;code&gt;Monitor&lt;/code&gt; class, we set developer mode to true which will allow the telemetry to be uploaded in near real-time so that we can test it quickly.&lt;/p&gt;

&lt;p&gt;Again, replace &lt;strong&gt;“Your Key Here”&lt;/strong&gt; with the &lt;strong&gt;“Instrumentation Key”&lt;/strong&gt; provided by Azure. &lt;strong&gt;Please note&lt;/strong&gt; : readers should store their keys in User Secrets or somewhere more secure. This code is used for examples only so please do not commit your keys to your repository directly!&lt;/p&gt;

&lt;p&gt;At this point the aspect is ready to send data to Application Insights. Decorate any method with [ServiceExceptionDetour] if you’re using the code provided here and then throw an exception from that decorated method. For example:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Here you can see that I am using the lovely &lt;code&gt;ExceptionGremlin&lt;/code&gt; from the &lt;a href="https://github.com/houseofcat/Library"&gt;HouseOfCat Library&lt;/a&gt;. &lt;a href="https://houseofcat.io/"&gt;The author&lt;/a&gt; provides a number of useful tools in there like basic exception fuzzing. Every time I throw from within this method, &lt;code&gt;CauseException&lt;/code&gt;, it will be routed through the Exception Handler and have its data passed to Azure. You will also notice that it is decorated as an &lt;code&gt;[EntryPoint]&lt;/code&gt; which means that it is safely entered from many threads in an actor model despite being private. It is important to &lt;a href="https://doc.postsharp.net/aspect-lifetime"&gt;understand the lifetime and scope of aspects&lt;/a&gt; when used in this way. For our purposes though we can disregard any performance issues because Exceptions are already expensive and we’re not trying to be graceful here.&lt;/p&gt;

&lt;h3&gt;
  
  
  Log Analytics
&lt;/h3&gt;

&lt;p&gt;If you navigate to &lt;a href="https://docs.microsoft.com/en-us/azure/azure-monitor/log-query/log-query-overview"&gt;Log Analytics&lt;/a&gt; on your Application Insights resource then you’ll be able to query the customEvents table to see if everything worked. You should have customDimensions on each record which contains the data you attached to the event from the Exception when it was handled.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IZYWht8I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/24tvt1uginmkhyma32in.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IZYWht8I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/24tvt1uginmkhyma32in.png" alt=""&gt;&lt;/a&gt;This image shows how to reach Log Analytics from an Azure resource.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WV5g4FlB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/suintse1q3mvam418hwe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WV5g4FlB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/suintse1q3mvam418hwe.png" alt=""&gt;&lt;/a&gt;An example data structure for an Application Insights custom event.&lt;/p&gt;

&lt;p&gt;If you are new to Log Analytics then I recommend checking out the official &lt;a href="https://app.pluralsight.com/library/courses/kusto-query-language-kql-from-scratch/table-of-contents"&gt;Kusto Query Language (KQL) From Scratch&lt;/a&gt; tutorial on &lt;a href="https://docs.microsoft.com/en-us/visualstudio/subscriptions/vs-pluralsight"&gt;Pluralsight&lt;/a&gt;. Here is an example query for our current set of custom events:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  Grafana
&lt;/h3&gt;

&lt;p&gt;Finally, we can integrate our Log Analytics store with Grafana to produce beautiful, real-time dashboards for our exceptions. If you’re new to Grafana then you can &lt;a href="https://grafana.com/get?signup"&gt;sign up for a free instance&lt;/a&gt; which is hosted as a container up in the company’s cloud. You can also host an instance on your own machine if you’d like to make it a dedicated resource.&lt;/p&gt;

&lt;p&gt;Once you have signed up then you will need to set up your dashboard to work with Azure.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install the Azure Monitor plugin on your instance of Grafana.&lt;/li&gt;
&lt;li&gt;Open your dashboard and navigate to Configuration &amp;gt; Data Sources. Add a data source for Azure Monitor.&lt;/li&gt;
&lt;li&gt;Fill out the two fields “API Key” and “Application ID” for Application Insights. We retrieved these keys earlier when we set up our Azure resource.&lt;/li&gt;
&lt;li&gt;Click “Save &amp;amp; Test” to check if the connection is working.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;From here you can begin utilizing KQL queries to make new visualizations. Here are some examples of what can be constructed alongside the queries and settings I used to build them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pBSlkvai--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ftaknbqh2r9gnl8vd5pp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pBSlkvai--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ftaknbqh2r9gnl8vd5pp.png" alt=""&gt;&lt;/a&gt;An example of Grafana visuals showing a stable system.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--q9IYzxAM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/1quq32wd513tn0qhuety.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--q9IYzxAM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/1quq32wd513tn0qhuety.png" alt=""&gt;&lt;/a&gt;An example of Grafana visuals displaying an unstable system.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RC9iCPhr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/p1ej78hxtlotftgtjukn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RC9iCPhr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/p1ej78hxtlotftgtjukn.png" alt=""&gt;&lt;/a&gt;An example image showing what a critical alert might look like.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bar Chart&lt;/strong&gt; :&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Gauge &amp;amp; Annotation&lt;/strong&gt; :&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  Where Can I Go From Here?
&lt;/h3&gt;

&lt;p&gt;At this point you can watch your data flow into the Grafana dashboard in real-time! This pipeline can now be used to track any sort of metric you want. PostSharp has a comprehensive suite of tools for you to &lt;a href="https://doc.postsharp.net/method-decorator"&gt;inject behaviors before and after execution&lt;/a&gt; on &lt;a href="https://doc.postsharp.net/method-interception"&gt;methods&lt;/a&gt;, &lt;a href="https://doc.postsharp.net/location-interception"&gt;properties / fields&lt;/a&gt;, and &lt;a href="https://doc.postsharp.net/event-interception"&gt;events&lt;/a&gt;. Anywhere you want to gather metrics without re-writing your old classes is a place to consider using an Aspect to provide that advice.&lt;/p&gt;

&lt;p&gt;Instead of writing out to Log Analytics, consider writing your events to &lt;a href="https://eventstore.org/"&gt;EventStore&lt;/a&gt; which allows you to build an immutable timeline to be used as a source of truth later to reason about your events. The overhead on EventStore is exceptionally low to the point where it may be easier to scale this form of Exception Handling by writing to EventStore and then reading it into Azure from a separate service.&lt;/p&gt;

&lt;p&gt;While there are many unconventional options, the goal here is simply to automate the boring stuff. Rather than chase down exceptions you can instead intercept them and handle them a deterministic way with advice provided by Attributes. How you handle them is up to your situation and needs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Credit
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.nuget.org/packages?q=totem"&gt;Totem&lt;/a&gt; was used in this repository. It provides a way to host your assemblies on an event-sourcing timeline and integrates with most common development scenarios. This package is still in preview right now but I recommend you add it to your favorites and keep an eye on it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/houseofcat/Library"&gt;HouseOfCat Library&lt;/a&gt; was used for exception generation here. I recommend checking out their Rabbit MQ library if you utilize message queues regularly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Final Remarks
&lt;/h3&gt;

&lt;p&gt;The entire &lt;a href="https://github.com/AlexanderJohnston/SharpCrafting/tree/Semantic"&gt;source code&lt;/a&gt; for this project is available on GitHub if you’d like to clone it and play around with the solution. Feel free to modify or redistribute it as needed. You can always find a copy of it on the Semantic branch.&lt;/p&gt;

&lt;p&gt;Hopefully this article conveyed the power of Aspect Oriented Programming in the .NET Core architecture. This is a learning process for all of us and I invite you to share or collaborate any time. Thank you for taking the time to read.&lt;/p&gt;





&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/AlexanderJohnston"&gt;
        AlexanderJohnston
      &lt;/a&gt; / &lt;a href="https://github.com/AlexanderJohnston/SharpCrafting"&gt;
        SharpCrafting
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Exploring PostSharp AOP with .NET Core Generic Host
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
SharpCrafting&lt;/h1&gt;
&lt;p&gt;Exploring PostSharp AOP with .NET Core Generic Host.
See &lt;a href="https://medium.com/dealeron-dev/automating-net-core-services-with-postsharp-and-aspect-oriented-code-a8a51d8d84ec" rel="nofollow"&gt;my article on Medium&lt;/a&gt; for a detailed explanation.&lt;/p&gt;
&lt;h1&gt;
Requirements&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.postsharp.net/essentials" rel="nofollow"&gt;PostSharp Essentials&lt;/a&gt; or &lt;a href="https://www.postsharp.net/purchase" rel="nofollow"&gt;Ultimate&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Visual Studio 2017&lt;/li&gt;
&lt;li&gt;.NET Core SDK 2.1 and C# 7.3&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;
Goals&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Demonstrate cross-platform .NET Core services which are threaded for a multi-core computer and wrapped with logging.&lt;/li&gt;
&lt;li&gt;Create an example of utilizing PostSharp with the Generic Host in a console app.&lt;/li&gt;
&lt;li&gt;Explore the benefits of Aspect Oriented Programming by masking the boundaries solved through use of PostSharp.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/AlexanderJohnston/SharpCrafting"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


</description>
      <category>aop</category>
      <category>programming</category>
      <category>logging</category>
      <category>patterns</category>
    </item>
    <item>
      <title>Automating .NET Core Services with PostSharp and Aspect-Oriented Code</title>
      <dc:creator>Alexander Johnston</dc:creator>
      <pubDate>Fri, 08 Feb 2019 14:01:00 +0000</pubDate>
      <link>https://forem.com/dealeron/automating-net-core-services-with-postsharp-and-aspect-oriented-code-2j8i</link>
      <guid>https://forem.com/dealeron/automating-net-core-services-with-postsharp-and-aspect-oriented-code-2j8i</guid>
      <description>&lt;p&gt;If you’re writing software targeting .NET then there’s a good chance you’re using Object-Oriented principles to do your work. In the process you may run into design patterns which you find yourself often repeating. Some of these patterns start as an abstract need such as “I want to log what my code is doing”. In practice this is easy to solve but as your solutions grow in scope you may find yourself spending a significant amount of time just deciding where and how to log your program’s state. Eventually you may want to change the logging pattern but that will require a significant amount of changes to the source.&lt;/p&gt;

&lt;p&gt;While many people have solved this in an Object-Oriented way, these cross-cutting concerns will eventually add up to significant time sinks for any development team. They also present an architectural challenge later down the line when you need to make a significant change. You will have to walk back through all of that boilerplate code at some point when you want to add new log sinks, monitors, or internal log exception handlers. This problem comes up again on many common concerns such as security, caching, threading, rate limiting, and even alerting a GUI that some viewable object has been updated.&lt;/p&gt;

&lt;p&gt;Aspect-Oriented designs are focused on targeting those concerns by dealing with the problem in one place and then applying that solution everywhere in your code where it is needed. What I am trying to show here is a way to purposefully hide away those concerns after investing the time to fully model them out. By spending some extra time considering our approach to logging or threading then we can write Aspects which are more like qualities that can be assigned to areas of code. Once you write a [Log] attribute, then you can decide a class or a method will be logged simply by tagging it with the attribute. Later on the compiler does the rest of the work by going back over and adding the missing code where those Aspects are declared.&lt;/p&gt;

&lt;p&gt;As a quick note before I get into the main example, Microsoft released &lt;a href="https://blogs.msdn.microsoft.com/dotnet/2018/12/04/announcing-net-core-3-preview-1-and-open-sourcing-windows-desktop-frameworks/" rel="noopener noreferrer"&gt;.NET Core 3 Preview 1&lt;/a&gt; last month and with it comes support for native Windows desktop namespaces. While this article deals with .NET Core 2.1, you can recompile it at any time under netcoreapp3.0 as a project target and it will support a wider surface of types, including UWP libraries, without any extra configuration.&lt;/p&gt;

&lt;h3&gt;
  
  
  Remarks
&lt;/h3&gt;

&lt;p&gt;This article is an attempt to cover certain difficult topics which vary in design from one business to the next. The code I will reference is written to be as short as possible, not fast or efficient. This is in the interest of showcasing each of the features and creating a usable demonstration.&lt;/p&gt;

&lt;p&gt;The goal here is to explore the cross-platform capabilities of the .NET Generic Host when combined with the power of a pattern-aware compiler. By wrapping the platform and runtime concerns around the generic host it becomes possible to seamlessly link almost any part of the .NET library for any platform. This doesn’t mean you can run a UWP library on Linux, but you won’t have to rewrite any code if you want to run that library when it detects Windows 10 as the OS.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.postsharp.net/" rel="noopener noreferrer"&gt;PostSharp&lt;/a&gt; is a pattern-aware compiler extension for Visual Studio and will be featured heavily throughout the article. If you don’t have a license and want to follow along with the code then there is still a solution. The free &lt;a href="https://www.postsharp.net/essentials" rel="noopener noreferrer"&gt;Essentials&lt;/a&gt; version of this framework covers up to ten classes which is enough to implement the full program in this article. You will also need to &lt;a href="https://marketplace.visualstudio.com/items?itemName=PostSharpTechnologies.PostSharp" rel="noopener noreferrer"&gt;download the extension&lt;/a&gt; for Visual Studio 2017.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hosting Services
&lt;/h3&gt;

&lt;p&gt;I spent the past couple months getting a handle on the new &lt;a href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/generic-host?view=aspnetcore-2.2" rel="noopener noreferrer"&gt;.NET Core Generic Host&lt;/a&gt; which is familiar to anyone who has worked in ASP.NET Core web applications. The host can also be used in console applications as well to handle built-in app configuration, dependency injection, and logging. Let’s take a moment to see how the service hosting fits into this design.&lt;/p&gt;

&lt;p&gt;The goal is to create a small application which can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Host common services and load native classes based on OSVersion.&lt;/li&gt;
&lt;li&gt;Automatically wrap logging around the entire solution.&lt;/li&gt;
&lt;li&gt;Automatically thread the services for a multi-core computer.&lt;/li&gt;
&lt;li&gt;Validate architecture so that bugs throw exceptions in a deterministic way.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now because I have spent a lot of time working on ETL solutions I tend to map out the flow of my program and look at what my goals are from a high level. Below I’ve drawn out just some basic shapes to illustrate what the structure is and try to see where the boundaries are going to be. These boundaries are important because they represent areas where concerns cross over and cut into the concerns of individual objects. When using AOP in a project I always find it helps to clearly define where those boundaries are because the goal is to hide how they work. You’ll have to excuse my MS Paint aesthetic here:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffiph3mdtor2ur46g0d4y.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffiph3mdtor2ur46g0d4y.png"&gt;&lt;/a&gt;Immutable (Frozen) Runtime and Platform areas which host Services wrapped in an Actor Threading Model.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Program:&lt;/strong&gt; A console app with &lt;code&gt;Main()&lt;/code&gt; in this example.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Runtime:&lt;/strong&gt; This will be the top level for all of the PostSharp wrappers and the constructor for the rest of the program. This should launch the service host.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Platform:&lt;/strong&gt; This contains any methods needed to load native classes and provide a thread-safe reference to the Host in case any inter-service communication needs to be implemented.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Frozen:&lt;/strong&gt; Both of the previous layers will be frozen which provides some of the same guarantees as an immutable object. This will be covered later on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hosting:&lt;/strong&gt; The .NET Generic Host builder.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Services:&lt;/strong&gt; The services will be wrapped with an Actor model ensuring that they can run on a multi-core computer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Log Output
&lt;/h3&gt;

&lt;p&gt;Throughout this exercise you will see several examples of log output which describes the state of the program in a specific template. I’ve marked some of them here as an example of what the values represent.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzsbgat1glu4v9ei8z2pg.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzsbgat1glu4v9ei8z2pg.png"&gt;&lt;/a&gt;Console log output generated automatically by PostSharp&lt;/p&gt;

&lt;h3&gt;
  
  
  Program
&lt;/h3&gt;

&lt;p&gt;First, let’s start with a new .NET Core 2.1 console app.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Next we need to add PostSharp to the project. If you have &lt;a href="https://marketplace.visualstudio.com/items?itemName=PostSharpTechnologies.PostSharp" rel="noopener noreferrer"&gt;the extension for Visual Studio&lt;/a&gt; then you can right click on the project and add PostSharp to it through the menu. You can also use the Package Manager Console to run Install-Package PostSharp&lt;br&gt;&lt;br&gt;
You will also need to add the following NuGet packages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PostSharp.Patterns.Common The bulk of the code contracts and aspects.&lt;/li&gt;
&lt;li&gt;PostSharp.Patterns.Diagnostics Tracing, logging, and diagnostics.&lt;/li&gt;
&lt;li&gt;PostSharp.Patterns.Diagnostics.Serilog Automatically inject Serilog.&lt;/li&gt;
&lt;li&gt;PostSharp.Patterns.Threading Threading models, dispatching, and deadlock detection.&lt;/li&gt;
&lt;li&gt;Serilog Logging framework.&lt;/li&gt;
&lt;li&gt;Serilog.Sinks.Console and Serilog.Enrichers.Thread for the sink.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now that we have our packages, let’s drop down one layer away from Program for now. I suggest a sealed runtime layer with static properties and an isolated, non-static entry-point. This allows the runtime to be instantiated as an object with its own threading model which can then launch onto a platform compatible with the caller’s context. The static properties are isolated away from the entry point and can then be used to attach async monitors or metrics later on.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now that we have a basic structure, we can talk about threading models. PostSharp provides three major features in &lt;a href="https://doc.postsharp.net/threading-models" rel="noopener noreferrer"&gt;PostSharp.Patterns.Threading&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Threading Models&lt;/strong&gt; : A threading model is a design pattern that gives &lt;a href="https://doc.postsharp.net/threading-model-compatibility" rel="noopener noreferrer"&gt;guarantees that your code executes safely&lt;/a&gt; on a multi-core computer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Thread Dispatching&lt;/strong&gt; : Custom attributes &lt;a href="https://doc.postsharp.net/p_postsharp_patterns_threading_dispatchedattribute_fireandforget" rel="noopener noreferrer"&gt;DispatchedAttribute&lt;/a&gt; and &lt;a href="https://doc.postsharp.net/t_postsharp_patterns_threading_backgroundattribute" rel="noopener noreferrer"&gt;BackgroundAttribute&lt;/a&gt; cause the execution of a method to be dispatched to the UI thread or to a background thread, respectively.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deadlock Detection&lt;/strong&gt; : Detects &lt;a href="https://doc.postsharp.net/deadlock-detection" rel="noopener noreferrer"&gt;deadlocks at run time&lt;/a&gt; and throws an exception instead of allowing your application to freeze.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Threading models are named solutions to recurring problems and can be considered a design pattern which we will inject at compile time. Defects are discovered by validating the code both during build and while running. If the application is improperly threaded then it will fail in a deterministic way inside of these models. Without this assurance, race conditions or deadlocks tend to show up randomly and can corrupt data without any warning.&lt;/p&gt;

&lt;p&gt;The primary threading model we will be looking at is the &lt;a href="https://doc.postsharp.net/actor" rel="noopener noreferrer"&gt;Actor model&lt;/a&gt;. Actors are services which run with their own state and a mailbox to receive messages in synchronous order. Their execution is more complex than this image describes, but they can be thought of as independent objects which run asynchronously against a queue of messages.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo0a2l87m997fi11o32th.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo0a2l87m997fi11o32th.png"&gt;&lt;/a&gt;Actors do not map one-to-one with threads but it is helpful for illustrating execution.&lt;/p&gt;

&lt;p&gt;The second threading model being used is the &lt;a href="https://doc.postsharp.net/freezable" rel="noopener noreferrer"&gt;Freezable&lt;/a&gt; threading model. An immutable object can be safely accessed from multiple threads but the restrictions of immutability often makes configuration difficult. By using &lt;a href="https://doc.postsharp.net/freezable" rel="noopener noreferrer"&gt;Freezable&lt;/a&gt; objects we can define at what point in time the object becomes immutable while still benefiting from mutability during creation.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now let’s wrap the &lt;a href="https://github.com/AlexanderJohnston/SharpCrafting/blob/master/SharpCrafting/Runtime.cs" rel="noopener noreferrer"&gt;Runtime&lt;/a&gt; class with a frozen model.&lt;/p&gt;

&lt;p&gt;To freeze an object we need to decorate it with an aspect called &lt;a href="https://doc.postsharp.net/freezable" rel="noopener noreferrer"&gt;[Freezable]&lt;/a&gt;. To enforce most threading models, PostSharp relies on the &lt;a href="https://doc.postsharp.net/aggregatable" rel="noopener noreferrer"&gt;[Aggregatable]&lt;/a&gt; attribute; this &lt;a href="https://doc.postsharp.net/aggregatable-adding" rel="noopener noreferrer"&gt;specifies that a class has its Parent/Child&lt;/a&gt; relationship explicitly defined. Any properties which are not children should be marked as a &lt;a href="https://doc.postsharp.net/t_postsharp_patterns_model_referenceattribute" rel="noopener noreferrer"&gt;[Reference]&lt;/a&gt;. Any methods which return the same value for each input and make no observable state changes can be marked as &lt;a href="https://doc.postsharp.net/t_postsharp_patterns_model_pureattribute" rel="noopener noreferrer"&gt;[Pure]&lt;/a&gt; to inform PostSharp that they are safe in a threaded context. I opted to include [NotNull] to indicate which properties are available from the entry point.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now that the &lt;a href="https://github.com/AlexanderJohnston/SharpCrafting/blob/master/SharpCrafting/Runtime.cs" rel="noopener noreferrer"&gt;Runtime&lt;/a&gt; class has been updated we can move on to the &lt;a href="https://github.com/AlexanderJohnston/SharpCrafting/blob/master/SharpCrafting/GenericPlatform.cs" rel="noopener noreferrer"&gt;Platform&lt;/a&gt;. While developing for a cross-platform application on .NET Core, it’s helpful to have a layer where concerns of the platform can be safely handled. Let’s take a look at some functions you might see here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GenericHost Creating the &lt;a href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/generic-host?view=aspnetcore-2.2" rel="noopener noreferrer"&gt;.NET generic host&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;GetNativeClass Services may need to load platform-specific implementations and this will provide the correct type.&lt;/li&gt;
&lt;li&gt;Crash If we are going to inject threading models safely then services also need a way to crash if state becomes fatal.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You will see the following patterns on the &lt;a href="https://github.com/AlexanderJohnston/SharpCrafting/blob/master/SharpCrafting/GenericPlatform.cs" rel="noopener noreferrer"&gt;Platform&lt;/a&gt; code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://doc.postsharp.net/t_postsharp_patterns_contracts_requiredattribute" rel="noopener noreferrer"&gt;[Required]&lt;/a&gt; Throws if null is passed in so that the responsibility belongs to the caller.&lt;/li&gt;
&lt;li&gt;INativeClass Serves as an interface to load and terminate native classes after importing them.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.Crash()&lt;/code&gt; Allows native platform classes to call for immediate debugging or termination if a fatal state is reached. It is marked with [&lt;a href="https://www.jetbrains.com/help/resharper/Contract_Annotations.html" rel="noopener noreferrer"&gt;ContractAnnotation (“=&amp;gt; halt”)&lt;/a&gt;] which specifies that for any given input the output will be a halted state. This allows the IDE to emit warnings appropriately.&lt;/li&gt;
&lt;li&gt;GenericHost Will be decorated with &lt;a href="https://doc.postsharp.net/t_postsharp_patterns_model_referenceattribute" rel="noopener noreferrer"&gt;[Reference]&lt;/a&gt; instead of &lt;a href="https://doc.postsharp.net/aggregatable-adding" rel="noopener noreferrer"&gt;[Child]&lt;/a&gt; which doesn’t guarantee thread safety anymore at the boundary but also doesn’t force the host to implement a compatible model.&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now we have a &lt;a href="https://github.com/AlexanderJohnston/SharpCrafting/blob/master/SharpCrafting/Runtime.cs" rel="noopener noreferrer"&gt;Runtime&lt;/a&gt; with a thread safe entry point and a Platform which can load native classes. At this point we can go ahead and use the .NET Generic Host, specifically &lt;a href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/generic-host?view=aspnetcore-2.2" rel="noopener noreferrer"&gt;HostBuiler&lt;/a&gt; to configure services and host them.&lt;/p&gt;

&lt;p&gt;Several packages are helpful for using the &lt;a href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/generic-host?view=aspnetcore-2.2" rel="noopener noreferrer"&gt;HostBuilder&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-2.2" rel="noopener noreferrer"&gt;Microsoft.Extensions.Configuration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-2.2" rel="noopener noreferrer"&gt;Microsoft.Extensions.Configuration.CommandLine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-2.2" rel="noopener noreferrer"&gt;Microsoft.Extensions.Configuration.EnvironmentVariables&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-2.2" rel="noopener noreferrer"&gt;Microsoft.Extensions.Configuration.Json&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-2.2" rel="noopener noreferrer"&gt;Microsoft.Extensions.DependencyInjection&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/?view=aspnetcore-2.2" rel="noopener noreferrer"&gt;Microsoft.Extensions.Hosting&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/aspnet/Extensions/tree/9bc79b2f25a3724376d7af19617c33749a30ea3a" rel="noopener noreferrer"&gt;Microsoft.Extensions.Options.ConfigurationExtensions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;.Start()&lt;/code&gt; method is decorated with a &lt;a href="https://github.com/AlexanderJohnston/SharpCrafting/blob/master/SharpCrafting/Aspects/SingleEntryMethodAttribute.cs" rel="noopener noreferrer"&gt;[SingleEntryMethod]&lt;/a&gt; attribute which automatically intercepts the method and returns null if it has been called more than once. This permits us to leave a reference to the Generic Host inside of the Platform without worrying about this method being called later on. Because this class is being intercepted, we can decorate it with the &lt;a href="https://doc.postsharp.net/threading-waiving-verification" rel="noopener noreferrer"&gt;[ExplicitlySynchronized]&lt;/a&gt; aspect which informs PostSharp not to verify the safety of this class.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/AlexanderJohnston/SharpCrafting/blob/master/SharpCrafting/Aspects/SingleEntryMethodAttribute.cs" rel="noopener noreferrer"&gt;[SingleEntryMethod]&lt;/a&gt; is a custom aspect written with PostSharp. To create one of these we only need to &lt;a href="https://doc.postsharp.net/aspect-serialization" rel="noopener noreferrer"&gt;decorate a class&lt;/a&gt; with &lt;a href="https://doc.postsharp.net/aspect-serialization" rel="noopener noreferrer"&gt;[PSerializable]&lt;/a&gt; and then inherit from any of the &lt;a href="https://doc.postsharp.net/n_postsharp_aspects" rel="noopener noreferrer"&gt;PostSharp aspects&lt;/a&gt;. In this case we want to intercept calls at the boundary of the decorated method which is a feature provided by &lt;a href="https://doc.postsharp.net/method-interception" rel="noopener noreferrer"&gt;MethodInterceptionAspect&lt;/a&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;As you can see in the Generic Host, one service was registered called &lt;a href="https://github.com/AlexanderJohnston/SharpCrafting/blob/master/SharpCrafting/TimingService.cs" rel="noopener noreferrer"&gt;TimingService&lt;/a&gt;. Let’s set that class up now. This will use the &lt;a href="https://doc.postsharp.net/actor" rel="noopener noreferrer"&gt;[Actor]&lt;/a&gt; threading model with a few new attributes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://doc.postsharp.net/actor" rel="noopener noreferrer"&gt;[Actor]&lt;/a&gt; Generates code which prevents fields of an actor from being accessed from an invalid context. Requires &lt;a href="https://doc.postsharp.net/aggregatable-adding" rel="noopener noreferrer"&gt;[Aggregatable]&lt;/a&gt; parent/child decoration as well as the following two aspects.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://doc.postsharp.net/actor" rel="noopener noreferrer"&gt;[Reentrant]&lt;/a&gt; This attribute declares that an async method can be safely re-entered on each await statement. For the actor model, this means other methods can be invoked while waiting. This must be applied to all async actor methods.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://doc.postsharp.net/threading-waiving-verification" rel="noopener noreferrer"&gt;[ExplicitlySynchronized]&lt;/a&gt; Opts out of the threading model by declaring that the object is handling its own safety.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://doc.postsharp.net/t_postsharp_patterns_threading_entrypointattribute" rel="noopener noreferrer"&gt;[EntryPoint]&lt;/a&gt; This specifies that the method can be invoked from threads which do not currently have access to the object. This means an event handler, background task, or callback can safely enter the threading model. Only needs to be applied to private methods.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;a href="https://github.com/AlexanderJohnston/SharpCrafting/blob/master/SharpCrafting/TimingService.cs" rel="noopener noreferrer"&gt;TimingService&lt;/a&gt; class also inherits from &lt;a href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-2.2" rel="noopener noreferrer"&gt;IHostedService&lt;/a&gt; which integrates with the .NET Generic Host &lt;a href="https://docs.microsoft.com/en-us/dotnet/standard/microservices-architecture/multi-container-microservice-net-applications/background-tasks-with-ihostedservice" rel="noopener noreferrer"&gt;which is covered by this MSDN article&lt;/a&gt;. Each of these services will have &lt;code&gt;StartAsync()&lt;/code&gt; called in the order they were registered during configuration earlier in the &lt;a href="https://github.com/AlexanderJohnston/SharpCrafting/blob/master/SharpCrafting/GenericHost.cs" rel="noopener noreferrer"&gt;GenericHost&lt;/a&gt; class. The queue reverses this order when &lt;code&gt;StopAsync()&lt;/code&gt; is called, starting with the last service registered and working its way back through the queue.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;In the interest of keeping this example small we’re going to cheat here and just use a few Timer objects to run on threads and report back. This should illustrate that our class is appropriately using the threading model. These aren’t technically native namespaces either, but calling out to platform-specific code will work exactly the same way without any configuration.&lt;/p&gt;

&lt;p&gt;With that in mind we need to implement the &lt;a href="https://github.com/AlexanderJohnston/SharpCrafting/blob/master/SharpCrafting/Win32NT/NativeTimers.cs" rel="noopener noreferrer"&gt;NativeTimers&lt;/a&gt; class which is imported from the &lt;a href="https://github.com/AlexanderJohnston/SharpCrafting/blob/master/SharpCrafting/GenericPlatform.cs" rel="noopener noreferrer"&gt;Platform&lt;/a&gt; into &lt;a href="https://github.com/AlexanderJohnston/SharpCrafting/blob/master/SharpCrafting/TimingService.cs" rel="noopener noreferrer"&gt;TimingService&lt;/a&gt; after &lt;code&gt;StartAsync()&lt;/code&gt; is called.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/AlexanderJohnston/SharpCrafting/blob/master/SharpCrafting/Win32NT/NativeTimers.cs" rel="noopener noreferrer"&gt;NativeTimers&lt;/a&gt; will need to be &lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.platformid?view=netframework-4.7.2" rel="noopener noreferrer"&gt;placed under a namespace compatible&lt;/a&gt; with the platform this code is running on. In my case I am running on Windows 10 17134 which will return &lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.platformid?view=netframework-4.7.2" rel="noopener noreferrer"&gt;“Win32NT”&lt;/a&gt; as the Platform. A list of potential platforms is &lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.platformid?view=netcore-2.2" rel="noopener noreferrer"&gt;provided by Microsoft&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MacOSX&lt;/li&gt;
&lt;li&gt;Unix&lt;/li&gt;
&lt;li&gt;Win32NT&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;At this point we have created the following areas of code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/AlexanderJohnston/SharpCrafting/blob/master/SharpCrafting/Runtime.cs" rel="noopener noreferrer"&gt;Runtime&lt;/a&gt; Entered from Program, configures logging and then sets up the platform.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/AlexanderJohnston/SharpCrafting/blob/master/SharpCrafting/GenericPlatform.cs" rel="noopener noreferrer"&gt;Platform&lt;/a&gt; Contains methods for loading native types and starts the generic host.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/AlexanderJohnston/SharpCrafting/blob/master/SharpCrafting/GenericHost.cs" rel="noopener noreferrer"&gt;Generic Host&lt;/a&gt; .NET Core Generic Host which configures and creates services.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/AlexanderJohnston/SharpCrafting/blob/master/SharpCrafting/TimingService.cs" rel="noopener noreferrer"&gt;TimingService&lt;/a&gt; An example service being threaded with the Actor model.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/AlexanderJohnston/SharpCrafting/blob/master/SharpCrafting/Win32NT/NativeTimers.cs" rel="noopener noreferrer"&gt;NativeTimers&lt;/a&gt; An example being loaded natively by the Timing Service.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now we just need to inject the logging wrapper and freeze our layers, starting with the &lt;code&gt;.Entry()&lt;/code&gt; function in Runtime.&lt;/p&gt;

&lt;p&gt;You will see the following patterns here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://doc.postsharp.net/logging" rel="noopener noreferrer"&gt;LoggingServices.DefaultBackend&lt;/a&gt; This is the PostSharp logging back end. By setting our logger here we can then inject it later on.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Post.Cast&amp;lt;T, IFreezable&amp;gt;( object ).Freeze()&lt;/code&gt; This is the call to freeze an object and mark it as immutable.&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;VerboseLogger()&lt;/code&gt; implementation and &lt;a href="https://github.com/AlexanderJohnston/SharpCrafting/blob/master/SharpCrafting/ConsoleExtensions.cs" rel="noopener noreferrer"&gt;BlueConsole&lt;/a&gt; theme:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Last we just need to call the Runtime from the program and inject logging into the assembly.&lt;/p&gt;

&lt;p&gt;Create a new &lt;a href="https://github.com/AlexanderJohnston/SharpCrafting/blob/master/SharpCrafting/GlobalAspects.cs" rel="noopener noreferrer"&gt;GlobalAspects.cs&lt;/a&gt; class without any using or namespace declarations. Include these lines:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This will wrap all Public, Private, Internal, and Protected members with the &lt;a href="https://doc.postsharp.net/t_postsharp_patterns_diagnostics_logattribute" rel="noopener noreferrer"&gt;[Log]&lt;/a&gt; attribute from the assembly level.&lt;/p&gt;

&lt;p&gt;Now just call the runtime from Program and watch it run.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;If everything is set up correctly then we should be able to watch the entire flow of execution print out to the console.&lt;/p&gt;

&lt;p&gt;We expect to see something like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generic Host starts up and creates the services.&lt;/li&gt;
&lt;/ul&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc7n5riqbboda9cjvmtcu.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc7n5riqbboda9cjvmtcu.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Services access AppConfig which creates the Platform.&lt;/li&gt;
&lt;/ul&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7zjcd0nvcace9bftaunm.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7zjcd0nvcace9bftaunm.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Services start asynchronously and ask for native types from the Platform.&lt;/li&gt;
&lt;/ul&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjofystzohj32xhujfq1r.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjofystzohj32xhujfq1r.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Native Timers class is constructed and three timers are set.&lt;/li&gt;
&lt;/ul&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4nkbx614shb5sa0pun3u.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4nkbx614shb5sa0pun3u.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Application starts.&lt;/li&gt;
&lt;/ul&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F948qrlfgeg1xaq5d4ny9.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F948qrlfgeg1xaq5d4ny9.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Timers callback to the private 1[EntryPoint]1 on 1WriteTime()1.&lt;/li&gt;
&lt;/ul&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flzbwgv6i1kwcyqug3aum.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flzbwgv6i1kwcyqug3aum.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you’ve been following along up to this point then you now can launch native classes onto services hosted cross-platform with the logging and threading handled.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where can we go from here?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Calling any libraries or namespaces from the services will automatically pipe the log statements if those libraries also implement Serilog, whether or not they have a custom log handler. This can be made compatible with other loggers as well.&lt;/li&gt;
&lt;li&gt;State machines will automatically be maintained by PostSharp so that asynchronous code is threaded safely. You can see these decorated in the logs above. The services are able to call into asynchronous code from other frameworks as well; this means a UWP .NET Framework 4.7.1 class library can be called from .NET Standard 2.0 library referenced by a service running under .NET Core 3.0. This so far has worked without any needed configuration for me other than to compile the console application under &lt;code&gt;&amp;lt;TargetFramework&amp;gt;netcoreapp3.0&amp;lt;/TargetFramework&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Asynchronous log monitors can be attached to Serilog with the ability to call back into Runtime or Platform as needed. These can be used to monitor flow, handle dropped log events, and handle deterministic internal logger exceptions.&lt;/li&gt;
&lt;li&gt;An Event-Sourcing timeline, Inter-Process Communication Channel, or API can all be attached to the service actor model. Each actor can write events back to a central source asynchronously while guaranteeing the messages are threaded properly.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Final Remarks
&lt;/h3&gt;

&lt;p&gt;I will attach &lt;a href="https://github.com/AlexanderJohnston/SharpCrafting" rel="noopener noreferrer"&gt;the source code&lt;/a&gt; for this entire project below if you’d like to clone it and play around with the solution. Feel free to modify or redistribute it as needed.&lt;/p&gt;

&lt;p&gt;Hopefully this article was able to show you the power of Aspect Oriented Programming when combined with the new .NET Core architecture to provide highly extensible service hosting on many platforms.&lt;/p&gt;

&lt;p&gt;If you ever have questions related to PostSharp or .NET Core then feel free to comment or get in touch with me any time.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/AlexanderJohnston" rel="noopener noreferrer"&gt;
        AlexanderJohnston
      &lt;/a&gt; / &lt;a href="https://github.com/AlexanderJohnston/SharpCrafting" rel="noopener noreferrer"&gt;
        SharpCrafting
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Exploring PostSharp AOP with .NET Core Generic Host
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;SharpCrafting&lt;/h1&gt;

&lt;/div&gt;
&lt;p&gt;Exploring PostSharp AOP with .NET Core Generic Host.
See &lt;a href="https://medium.com/dealeron-dev/automating-net-core-services-with-postsharp-and-aspect-oriented-code-a8a51d8d84ec" rel="nofollow noopener noreferrer"&gt;my article on Medium&lt;/a&gt; for a detailed explanation.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Requirements&lt;/h1&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.postsharp.net/essentials" rel="nofollow noopener noreferrer"&gt;PostSharp Essentials&lt;/a&gt; or &lt;a href="https://www.postsharp.net/purchase" rel="nofollow noopener noreferrer"&gt;Ultimate&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Visual Studio 2017&lt;/li&gt;
&lt;li&gt;.NET Core SDK 2.1 and C# 7.3&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Goals&lt;/h1&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Demonstrate cross-platform .NET Core services which are threaded for a multi-core computer and wrapped with logging.&lt;/li&gt;
&lt;li&gt;Create an example of utilizing PostSharp with the Generic Host in a console app.&lt;/li&gt;
&lt;li&gt;Explore the benefits of Aspect Oriented Programming by masking the boundaries solved through use of PostSharp.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/AlexanderJohnston/SharpCrafting" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;





</description>
      <category>aop</category>
      <category>programming</category>
      <category>dotnetcore</category>
      <category>patterns</category>
    </item>
  </channel>
</rss>
