<?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: Peter Bons</title>
    <description>The latest articles on DEV Community by Peter Bons (@expecho).</description>
    <link>https://dev.to/expecho</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%2F67820%2F89221360-1d67-4a5f-b76f-3e949eb74ecf.png</url>
      <title>DEV Community: Peter Bons</title>
      <link>https://dev.to/expecho</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/expecho"/>
    <language>en</language>
    <item>
      <title>Forget MCP, Use OpenAPI for AI Agent tools</title>
      <dc:creator>Peter Bons</dc:creator>
      <pubDate>Tue, 30 Sep 2025 11:32:19 +0000</pubDate>
      <link>https://dev.to/expecho/forget-mcp-use-openapi-for-external-operations-4gc4</link>
      <guid>https://dev.to/expecho/forget-mcp-use-openapi-for-external-operations-4gc4</guid>
      <description>&lt;p&gt;This blog post demonstrates how to build an AI agent using dotnet and  a Semantic Kernel plugin that calls web APIs to access external data instead of using an &lt;a href="https://github.com/mcp" rel="noopener noreferrer"&gt;MCP server&lt;/a&gt; based on an OpenAPI document.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Ok, you got me, it's a clickbait post title. But hear me out. If you are in to Language Models you cannot ignore the &lt;strong&gt;widespread enthusiasm that &lt;a href="https://modelcontextprotocol.io/docs/getting-started/intro" rel="noopener noreferrer"&gt;MCP&lt;/a&gt; brought&lt;/strong&gt;. Lots of MCP servers popped up and support is widely available. From your favorite AI infused code editor to one of the many Copilots Microsoft is trying to sell you, &lt;strong&gt;everywhere you can plug them in&lt;/strong&gt;. And it is not a bad thing, they can add great value to your AI agents and workflows. But there is also a dark side to the success story. First of all, a lot of MCP servers are intended to run locally and because of that, they can pose &lt;strong&gt;a real &lt;a href="https://www.prompt.security/blog/top-10-mcp-security-risks" rel="noopener noreferrer"&gt;security risk&lt;/a&gt;&lt;/strong&gt;. Second, not all of them are maintained and updated well. And what if you already invested in opening up your software by providing web APIs? That is what this post is all about. We will build an agent that can transform an &lt;strong&gt;OpenAPI document&lt;/strong&gt; into a &lt;strong&gt;set of tools&lt;/strong&gt; the model can call using the &lt;a href="https://learn.microsoft.com/en-us/semantic-kernel/concepts/plugins/adding-openapi-plugins?pivots=programming-language-csharp" rel="noopener noreferrer"&gt;Semantic Kernel OpenAPI capabilities&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting the ingredients right
&lt;/h2&gt;

&lt;p&gt;For this scenario we will build an agent that can help us answering questions about &lt;strong&gt;flight status&lt;/strong&gt; and realtime flight data using te &lt;a href="https://aviationstack.com/" rel="noopener noreferrer"&gt;Aviationstack API&lt;/a&gt;. You can sign up for a free access key in under a minute. After that, you can &lt;strong&gt;grab their OpenAPI document&lt;/strong&gt; from &lt;a href="https://docs.apilayer.com/aviationstack/docs/aviationstack-api-v-1-0-0" rel="noopener noreferrer"&gt;here&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F4sqbrzzw2nxl8zlier2y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F4sqbrzzw2nxl8zlier2y.png" alt="Downloading the OpenAPI document" width="800" height="109"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We also need &lt;strong&gt;a model to talk to&lt;/strong&gt;. You can run one in the cloud, use &lt;a href="https://huggingface.co/" rel="noopener noreferrer"&gt;Hugging Face&lt;/a&gt;, Microsoft &lt;a href="https://learn.microsoft.com/en-us/azure/ai-foundry/foundry-local/get-started" rel="noopener noreferrer"&gt;Foundry Local&lt;/a&gt; or something else but I choose* to use the &lt;code&gt;qwen3&lt;/code&gt; model through &lt;a href="https://ollama.com/" rel="noopener noreferrer"&gt;Ollama&lt;/a&gt;: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Ollama&lt;/strong&gt; is the easiest way to get up and running with large language models such as gpt-oss, Gemma 3, DeepSeek-R1, Qwen3 and more..&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once installed, download and run the model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;ollama&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pull&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;qwen3&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;ollama&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;serve&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The following should show up, verifying it's running. Time to note the port number, we will need it later.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🟢 Mtime=2025-09-29T18:51:05.926+02:00 level=INFO source=routes.go:1332 msg="server config" env="map[CUDA_VISIBLE_DEVICES: GPU_DEVICE_ORDINAL: HIP_VISIBLE_DEVICES: HSA_OVERRIDE_GFX_VERSION: HTTPS_PROXY: HTTP_PROXY: NO_PROXY: OLLAMA_CONTEXT_LENGTH:4096 OLLAMA_DEBUG:INFO OLLAMA_FLASH_ATTENTION:false OLLAMA_GPU_OVERHEAD:0 &lt;strong&gt;OLLAMA_HOST:&lt;a href="http://127.0.0.1:11434" rel="noopener noreferrer"&gt;http://127.0.0.1:11434&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now that we have the prerequisites in place, it is time to move on to some code. By the way, I am using a dotnet 10 single file application for this blogpost.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;Actually I tried different models like phi-4-mini, Llama3.1 and several others but Qwen3 provided the most consistent results and always succeeded to make the proper tool calls. Thing is, you get the best result by trying out the various models as all behave different depending on the use case.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the agent
&lt;/h2&gt;

&lt;p&gt;We start by setting up &lt;a href="https://learn.microsoft.com/en-us/semantic-kernel/overview/" rel="noopener noreferrer"&gt;Semantic Kernel&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Semantic Kernel is a lightweight, open-source development kit that lets you easily build AI agents and integrate the latest AI models into your C#, Python, or Java codebase.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;package&lt;/span&gt; &lt;span class="n"&gt;Microsoft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SemanticKernel&lt;/span&gt;&lt;span class="err"&gt;@&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;span class="n"&gt;package&lt;/span&gt; &lt;span class="n"&gt;Microsoft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SemanticKernel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Connectors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Ollama&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="m"&gt;1.65&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;alpha&lt;/span&gt;
&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;package&lt;/span&gt; &lt;span class="n"&gt;Microsoft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SemanticKernel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Plugins&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OpenApi&lt;/span&gt;&lt;span class="err"&gt;@&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;span class="n"&gt;package&lt;/span&gt; &lt;span class="n"&gt;Microsoft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Extensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DependencyInjection&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="m"&gt;10.0&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;rc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="m"&gt;1.25451&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="m"&gt;107&lt;/span&gt;
&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;package&lt;/span&gt; &lt;span class="n"&gt;Microsoft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Extensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="m"&gt;10.0&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;preview&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="m"&gt;7.25380&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="m"&gt;108&lt;/span&gt;

&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;property&lt;/span&gt; &lt;span class="n"&gt;PublishAot&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;

&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Web&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Extensions.DependencyInjection&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Extensions.Logging&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.SemanticKernel&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.SemanticKernel.ChatCompletion&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.SemanticKernel.Connectors.Ollama&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.SemanticKernel.Plugins.OpenApi&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Kernel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateBuilder&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;ollamaEndpoint&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;Uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"http://127.0.0.1:11434"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;modelId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"qwen3"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;loggerFactory&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;LoggerFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetMinimumLevel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LogLevel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Information&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;AddConsole&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddSingleton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;loggerFactory&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddOllamaChatCompletion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;modelId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ollamaEndpoint&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;kernel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the foundation in place it is time to move on and import the OpenAPI document. Semantic Kernel has the ability to &lt;strong&gt;turn the document into a plugin&lt;/strong&gt; that can be called by the model. The plugin will then call the web API and pass the result back to the model. You can load the OpenAPI document &lt;strong&gt;from file or by url&lt;/strong&gt;. It also provides a callback method that can be used to &lt;strong&gt;authenticate&lt;/strong&gt; against the api by setting the authorization header for example. In our case, the aviationstack api expects an &lt;code&gt;access_key&lt;/code&gt; in the request:&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;await&lt;/span&gt; &lt;span class="n"&gt;kernel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ImportPluginFromOpenApiAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"flight_api"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;@"Z:\Sources\dotnet10\ai\openapi-trimmed.yaml"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;executionParameters&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;OpenApiFunctionExecutionParameters&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;AuthCallback&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AuthenticateRequestAsyncCallback&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;AuthenticateRequestAsyncCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HttpRequestMessage&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;queryParts&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HttpUtility&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ParseQueryString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RequestUri&lt;/span&gt;&lt;span class="p"&gt;!.&lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;queryParts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"access_key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"1052d67e5de98f2c58f664e1e5a30a12"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;uriBuilder&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;UriBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RequestUri&lt;/span&gt;&lt;span class="p"&gt;!)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Query&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;queryParts&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="p"&gt;};&lt;/span&gt;
    &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RequestUri&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;uriBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Uri&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;$"Requesting: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RequestUri&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CompletedTask&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;em&gt;(yes, I included a real &amp;amp; valid access key but it is rate limited on the free tier so you're welcome to use it and try if it succeeds)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So lets add a way to prompt the model and ask some questions!&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;OllamaPromptExecutionSettings&lt;/span&gt; &lt;span class="n"&gt;executionSettings&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;FunctionChoiceBehavior&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FunctionChoiceBehavior&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Auto&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;chatGPT&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kernel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetRequiredService&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IChatCompletionService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;history&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;ChatHistory&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;history&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddSystemMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Use a made up value for the access_key parameter."&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;"You can now enter messages to send to the model. Type 'exit' to quit."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;while&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;ReadLine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"exit"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;history&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddUserMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&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;assistantResponse&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;Empty&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;chatGPT&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetStreamingChatMessageContentsAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;history&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;executionSettings&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;kernel&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;assistantResponse&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Content&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;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Content&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;history&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddAssistantMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;assistantResponse&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;h2&gt;
  
  
  Play Time!
&lt;/h2&gt;

&lt;p&gt;So, let's ask a question: &lt;em&gt;when is the next flight departure from AMS with destination CDG?&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The next scheduled flight from Amsterdam (AMS) to Charles de Gaulle (CDG) is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Flight:&lt;/strong&gt; Aeromexico AM6192&lt;br&gt;
&lt;strong&gt;Departure:&lt;/strong&gt; September 29, 2025 at 11:35 AM (AMS)&lt;br&gt;
&lt;strong&gt;Arrival:&lt;/strong&gt; September 29, 2025 at 12:55 PM (CDG)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Flight Status:&lt;/strong&gt; Scheduled&lt;br&gt;
&lt;strong&gt;Estimated Arrival Delay:&lt;/strong&gt; 46 minutes&lt;br&gt;
&lt;strong&gt;Departure Delay:&lt;/strong&gt; 77 minutes&lt;/p&gt;

&lt;p&gt;This is the earliest flight found for your route. Let me know if you need further details!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you take a look at the response from the LLM you will see it reasons about what parameter values to use when calling the tool:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;[..]&lt;br&gt;
So the function call would be to flight_api_Flights with access_key, dep_iata=AMS, arr_iata=CDG, flight_status=scheduled, limit=1. That should get the next scheduled flight from AMS to CDG. If there's no scheduled flight, maybe check for active ones. But the user is asking for the next flight, so scheduled is the right status. Let's proceed with that.&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;info: Microsoft.SemanticKernel.KernelFunction[0]&lt;br&gt;
      &lt;strong&gt;Function flight_api-Flights invoking&lt;/strong&gt;.&lt;br&gt;
&lt;em&gt;Requesting: &lt;a href="https://api.aviationstack.com/v1/flights?access_key=1052d67e5de98f2c58f664e1e5a30a12&amp;amp;limit=1&amp;amp;flight_status=scheduled&amp;amp;dep_iata=AMS&amp;amp;arr_iata=CDG" rel="noopener noreferrer"&gt;https://api.aviationstack.com/v1/flights?access_key=1052d67e5de98f2c58f664e1e5a30a12&amp;amp;limit=1&amp;amp;flight_status=scheduled&amp;amp;dep_iata=AMS&amp;amp;arr_iata=CDG&lt;/a&gt;&lt;/em&gt;&lt;br&gt;
&lt;strong&gt;info:&lt;/strong&gt; Microsoft.SemanticKernel.KernelFunction[0]&lt;br&gt;
      Function flight_api-Flights succeeded.&lt;br&gt;
&lt;strong&gt;info:&lt;/strong&gt; Microsoft.SemanticKernel.KernelFunction[0]&lt;br&gt;
      Function flight_api-Flights completed. Duration: 0.6109388s&lt;br&gt;
&lt;br&gt;
Okay, let me process the user's query and the tool response. The user asked for the first next flight from AMS to CDG. The tool call used the Flights endpoint with the parameters access_key, dep_iata=AMS, arr_iata=CDG, flight_status=scheduled, and limit=1. The response from the tool shows a flight scheduled for 2025-09-29, departing AMS at 11:35 and arriving at CDG at 12:55. The airline is Aeromexico, flight number AM6192.&lt;br&gt;
[..]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As instructed, it used a dummy API key which is replaced by Semantic Kernel with the real value when the request is about to be made to demonstrate how you could handle more complex authentication scenarios.&lt;/p&gt;

&lt;p&gt;The full model output can be found &lt;a href="https://1drv.ms/t/c/e7c07309b5330772/Eb3-iun6MaJCudbZWLKEjfkBWkLxU-pN6ZVOsYUBsXfiPQ?e=pSNONO" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trimming large OpenAPI documents
&lt;/h2&gt;

&lt;p&gt;Most times you are calling a &lt;strong&gt;subset of the endpoints&lt;/strong&gt; available. Take the Microsoft Graph API for example, the OpenAPI document is &lt;a href="https://raw.githubusercontent.com/microsoftgraph/msgraph-metadata/refs/heads/master/openapi/v1.0/openapi.yaml" rel="noopener noreferrer"&gt;very large&lt;/a&gt; resulting in &lt;strong&gt;too much functions&lt;/strong&gt; available for the model to work with. Luckily for us there is tooling for that. I used &lt;a href="https://github.com/microsoft/OpenAPI.NET/tree/main/src/Microsoft.OpenApi.Hidi" rel="noopener noreferrer"&gt;Microsoft Hidi&lt;/a&gt; to transform the document by specifying only the operations I am interested in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;hidi&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;transform&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;\openapi.yaml&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;yaml&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-o&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;\openapi-trimmed.yaml&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;3.0&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nt"&gt;--op&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Flights&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;Routes&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command above creates a new yaml file based on the original, excluding all endpoints except the Flights and Routes operations endpoints. &lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;We have seen how easy it is to convert an OpenAPI document into a set of tools that a model can call and how to handle authentication. There are still enough points we haven't touched yet like &lt;strong&gt;error handling&lt;/strong&gt;, for example I hit some rate limits that the model couldn't handle.&lt;/p&gt;

&lt;p&gt;When you already have a set of well defined APIs it is a &lt;strong&gt;very fast and easy way&lt;/strong&gt; to integrate them into your agents.&lt;/p&gt;

&lt;p&gt;Full source can be found &lt;a href="https://gist.github.com/Expecho/4d6f568b3741b114d48641fd91957f08" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Any questions or comments? Drop them below!&lt;/p&gt;

</description>
      <category>semantickernel</category>
      <category>dotnet</category>
      <category>mcp</category>
      <category>llm</category>
    </item>
    <item>
      <title>Give your AI Agent Vibe Coding Superpowers using .Net 10</title>
      <dc:creator>Peter Bons</dc:creator>
      <pubDate>Sun, 22 Jun 2025 10:57:08 +0000</pubDate>
      <link>https://dev.to/expecho/give-your-llm-vibe-coding-superpowers-using-net-10-24fe</link>
      <guid>https://dev.to/expecho/give-your-llm-vibe-coding-superpowers-using-net-10-24fe</guid>
      <description>&lt;p&gt;This blog post demonstrates how to build an AI agent using dotnet that is capable of writing and executing C# code to perform complex tasks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;It is an exciting time to live in when it comes to generative AI. Long gone are the days when an LLM is merely capable of generating responses based on the data they are trained on. Nowadays they are capable of doing much more by &lt;strong&gt;giving them the proper tools&lt;/strong&gt; for example. Initiatives like the &lt;a href="https://modelcontextprotocol.io/introduction" rel="noopener noreferrer"&gt;Model Context Protocol (&lt;strong&gt;MCP&lt;/strong&gt;)&lt;/a&gt; are driving a new era and &lt;a href="https://mcpservers.org/" rel="noopener noreferrer"&gt;MCP servers&lt;/a&gt; are popping up everywhere.&lt;/p&gt;

&lt;p&gt;Another term you might have heard of is &lt;a href="https://en.wikipedia.org/wiki/Vibe_coding" rel="noopener noreferrer"&gt;"&lt;strong&gt;vibe coding&lt;/strong&gt;"&lt;/a&gt;. According to ChatGPT it means:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Vibe coding with AI is like whispering your app dreams to a super-fast coder who never sleeps—you describe what you want (“make the button red,” “add cat purring”), and the AI writes it. You review, tweak, rinse, repeat… no need to grok every line. It’s part brainstorming session, part code genie — fast, fun, and sometimes buggy magic! 😜&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And, in other news, Microsoft has already &lt;strong&gt;started working on .Net 10&lt;/strong&gt;. Lots  of &lt;strong&gt;new goodies and stuff&lt;/strong&gt; but one thing that stands out is the ability to do something like &lt;code&gt;dotnet run app.cs&lt;/code&gt;. Yes, that's right: &lt;a href="https://devblogs.microsoft.com/dotnet/announcing-dotnet-run-app/" rel="noopener noreferrer"&gt;&lt;strong&gt;single file applications&lt;/strong&gt; are finally coming our way&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With those &lt;strong&gt;3 ingredients&lt;/strong&gt;, LLMs, tool calling and .Net 10, we can create our own &lt;strong&gt;vibe coding agent&lt;/strong&gt; to accomplish tasks that go beyond answering simple questions based on the data it is trained on. So let's get dive in! For the magic we will use the &lt;code&gt;Microsoft.Extensions.AI&lt;/code&gt; &lt;a href="https://learn.microsoft.com/en-us/dotnet/ai/microsoft-extensions-ai" rel="noopener noreferrer"&gt;libraries&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up the stage
&lt;/h2&gt;

&lt;p&gt;Let's start with importing some required packages and setting up the chat client. I use a model hosted on &lt;a href="https://learn.m'icrosoft.com/en-us/azure/ai-foundry/what-is-azure-ai-foundry" rel="noopener noreferrer"&gt;Azure AI Foundry&lt;/a&gt; but it can be any model hosted anywhere as long as it supports tool calling.&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="err"&gt;#&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;package&lt;/span&gt; &lt;span class="n"&gt;Azure&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OpenAI&lt;/span&gt;
&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;package&lt;/span&gt; &lt;span class="n"&gt;Microsoft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Extensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AI&lt;/span&gt;
&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;package&lt;/span&gt; &lt;span class="n"&gt;Microsoft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Extensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="m"&gt;10.0&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;preview&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="m"&gt;5.25277&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="m"&gt;114&lt;/span&gt;
&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;package&lt;/span&gt; &lt;span class="n"&gt;Microsoft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Extensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OpenAI&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="m"&gt;9.5&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;preview&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="m"&gt;1.25265&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="m"&gt;7&lt;/span&gt;

&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Azure.AI.OpenAI&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Extensions.AI&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Extensions.Logging&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.ClientModel&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Diagnostics&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;runId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NewGuid&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;azureOpenAIEndpoint&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"https://&amp;lt;your-endpoint&amp;gt;.cognitiveservices.azure.com/"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;azureOpenAIModelId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"gpt-4.1"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;loggerFactory&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;LoggerFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetMinimumLevel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LogLevel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Information&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;AddConsole&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;client&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;ChatClientBuilder&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;AzureOpenAIClient&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;Uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;azureOpenAIEndpoint&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;ApiKeyCredential&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;lt;your-api-key&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetChatClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;azureOpenAIModelId&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;AsIChatClient&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseLogging&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;loggerFactory&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseFunctionInvocation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;loggerFactory&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So now we got the basic stuff, what's next? We already know that LLMs are capable of writing code, so that is covered. However, we need to give the LLM &lt;strong&gt;code execution capabilities&lt;/strong&gt; as well if we want to succeed. Let's write a &lt;strong&gt;tool&lt;/strong&gt; for that. In the code below we have defined a method that takes a &lt;code&gt;string&lt;/code&gt; for input, write that string to a file and execute the code using &lt;code&gt;dotnet run&lt;/code&gt;. There is some ceremony to be able to track the different executions in there as well so we can see how &lt;strong&gt;the code evolves&lt;/strong&gt; when the model encounters compile time or runtime errors.&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;var&lt;/span&gt; &lt;span class="n"&gt;chatOptions&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;ChatOptions&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Tools&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;AIFunctionFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&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;code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&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;loggerFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CodeExecution"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;codeFileName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="s"&gt;$"c:\temp\{DateTime.Now.ToString("&lt;/span&gt;&lt;span class="n"&gt;HHmmssfff&lt;/span&gt;&lt;span class="s"&gt;")}-{runId}.cs"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteAllText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;codeFileName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;process&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;Process&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;StartInfo&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;ProcessStartInfo&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;FileName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"dotnet"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;Arguments&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;$"run &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;codeFileName&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;RedirectStandardOutput&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;

        &lt;span class="n"&gt;process&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;span class="n"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WaitForExit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromMinutes&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StandardOutput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadToEnd&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;LogInformation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Code execution output: {Output}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Execute the provided code."&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 general idea is that we provide the LLM with a tool using &lt;code&gt;ChatOptions&lt;/code&gt;, ask the LLM to perform a task using a prompt and have it &lt;strong&gt;automatically invoke the tool&lt;/strong&gt; if it thinks it is needed to generate an answer. We enable this by calling &lt;code&gt;UseFunctionInvocation&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now all we need is a system prompt that explains the model how to handle a given task. Finally, we need a prompt defining the task at hand:&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;var&lt;/span&gt; &lt;span class="n"&gt;history&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;ChatMessage&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChatRole&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="s"&gt;"""
&lt;/span&gt;        &lt;span class="n"&gt;Write&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;answer&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; 

        &lt;span class="n"&gt;If&lt;/span&gt; &lt;span class="n"&gt;you&lt;/span&gt; &lt;span class="n"&gt;need&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;NuGet&lt;/span&gt; &lt;span class="n"&gt;package&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;specify&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;package&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt; &lt;span class="n"&gt;like&lt;/span&gt; &lt;span class="k"&gt;this&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;span class="n"&gt;package&lt;/span&gt; &lt;span class="n"&gt;PackageName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;Some&lt;/span&gt; &lt;span class="n"&gt;examples&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;span class="n"&gt;package&lt;/span&gt; &lt;span class="n"&gt;Humanizer&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="m"&gt;9.5&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;preview&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="m"&gt;1.25265&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="m"&gt;7&lt;/span&gt;
        &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;package&lt;/span&gt; &lt;span class="n"&gt;SemanticKernel&lt;/span&gt;
        &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;package&lt;/span&gt; &lt;span class="n"&gt;Newtonsoft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Json&lt;/span&gt;

        &lt;span class="n"&gt;A&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt; &lt;span class="n"&gt;block&lt;/span&gt; &lt;span class="n"&gt;should&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;required&lt;/span&gt; &lt;span class="n"&gt;NuGet&lt;/span&gt; &lt;span class="n"&gt;packages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;followed&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt; &lt;span class="n"&gt;more&lt;/span&gt; &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;statements&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;followed&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
        &lt;span class="n"&gt;You&lt;/span&gt; &lt;span class="n"&gt;can&lt;/span&gt; &lt;span class="n"&gt;directly&lt;/span&gt; &lt;span class="n"&gt;write&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt; &lt;span class="n"&gt;statements&lt;/span&gt; &lt;span class="n"&gt;without&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;program&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;with&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

        &lt;span class="err"&gt;###&lt;/span&gt; &lt;span class="n"&gt;Example&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
        &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;package&lt;/span&gt; &lt;span class="n"&gt;Humanizer&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="m"&gt;1.2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;
        &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;package&lt;/span&gt; &lt;span class="n"&gt;SomePackage&lt;/span&gt;

        &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&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;"123"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Humanize&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

        &lt;span class="err"&gt;###&lt;/span&gt; &lt;span class="n"&gt;Example&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
        &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;package&lt;/span&gt; &lt;span class="n"&gt;Microsoft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Extensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Console&lt;/span&gt;

        &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.IO&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadAllTextAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"c:\\temp\\file.txt"&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;text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="err"&gt;###&lt;/span&gt;

        &lt;span class="n"&gt;Write&lt;/span&gt; &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="n"&gt;execute&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;answer&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;Do&lt;/span&gt; &lt;span class="k"&gt;not&lt;/span&gt; &lt;span class="n"&gt;ask&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;just&lt;/span&gt; &lt;span class="n"&gt;complete&lt;/span&gt; &lt;span class="n"&gt;all&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;steps&lt;/span&gt; &lt;span class="n"&gt;below&lt;/span&gt;
        &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="n"&gt;writing&lt;/span&gt; &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="n"&gt;executing&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt; &lt;span class="n"&gt;without&lt;/span&gt; &lt;span class="n"&gt;asking&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;clarification&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt; &lt;span class="n"&gt;consent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

        &lt;span class="s"&gt;"""),
&lt;/span&gt;    &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChatRole&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"""
&lt;/span&gt;        &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;Fetch&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;csv&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//raw.githubusercontent.com/fgeorges/star-wars-dataset/refs/heads/master/csv/films/films.csv'&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;Analyze&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="n"&gt;determine&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;delimiter&lt;/span&gt; &lt;span class="n"&gt;used&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;csv&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;Keep&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;mind&lt;/span&gt; &lt;span class="n"&gt;that&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="n"&gt;columns&lt;/span&gt; &lt;span class="n"&gt;may&lt;/span&gt; &lt;span class="n"&gt;contain&lt;/span&gt; &lt;span class="n"&gt;commas&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;well&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;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="s"&gt;"A New Hope, Episode IV"&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="n"&gt;Determine&lt;/span&gt; &lt;span class="n"&gt;which&lt;/span&gt; &lt;span class="n"&gt;columns&lt;/span&gt; &lt;span class="n"&gt;are&lt;/span&gt; &lt;span class="n"&gt;present&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;csv&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="n"&gt;what&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;columns&lt;/span&gt; &lt;span class="n"&gt;contain&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="n"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;movies&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="n"&gt;release&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Newest&lt;/span&gt; &lt;span class="n"&gt;first&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;Write&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;docx&lt;/span&gt; &lt;span class="n"&gt;word&lt;/span&gt; &lt;span class="n"&gt;document&lt;/span&gt; &lt;span class="n"&gt;at&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="err"&gt;\\&lt;/span&gt;&lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="err"&gt;\\&lt;/span&gt;&lt;span class="n"&gt;star_wars_movie&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;docx&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="n"&gt;per&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;following&lt;/span&gt; &lt;span class="n"&gt;information&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;release&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;
            &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;
            &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;
        &lt;span class="s"&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;If we take a closer look at the system prompt you'll see that it has &lt;strong&gt;clear instructions&lt;/strong&gt; on how to reference NuGet packages and how to structure the code, accompanied with some examples. The reason for this is that LLMs are trained on lots of existing C# code that is written &lt;em&gt;before&lt;/em&gt; .Net 10 was introduced. Without that it will generate an old school &lt;code&gt;Program&lt;/code&gt; class with a &lt;code&gt;Main&lt;/code&gt; method and won't be able to reference packages. It took &lt;strong&gt;some prompt tweaking&lt;/strong&gt; to &lt;em&gt;"unlearn the old way"&lt;/em&gt; of writing a simple program.&lt;/p&gt;

&lt;p&gt;The final step is to &lt;strong&gt;feed the model the prompts&lt;/strong&gt; and wait for it  to complete its vibe coding session. 😄&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;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetResponseAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;history&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chatOptions&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;$"LLM response: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Reviewing the performance
&lt;/h2&gt;

&lt;p&gt;The whole code file can be found as a gist &lt;a href="https://gist.github.com/Expecho/0f0e30a7097676ea777bec47b764e994" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Save it and then run the code using &lt;code&gt;dotnet run vibecoding_agent.cs&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If everything is ok you will see one or more files popping up in &lt;code&gt;C:\Temp&lt;/code&gt;. If the LLM is in a good mood it will be just one but more often it needs &lt;strong&gt;a few iterations&lt;/strong&gt; before a correct code file is written. Since the model is fed with the output of the &lt;code&gt;dotnet run&lt;/code&gt; command it can detect compile time and runtime errors and rewrite the code to handle that.&lt;/p&gt;

&lt;p&gt;The output of &lt;code&gt;dotnet run&lt;/code&gt; is the response of the LLM, my last execution resulted in this response:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;LLM response: &lt;strong&gt;Analysis and Results:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Delimiter:&lt;/strong&gt; The delimiter used in the CSV is a comma (,).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Columns present:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;title&lt;/li&gt;
&lt;li&gt;episode_id&lt;/li&gt;
&lt;li&gt;opening_crawl&lt;/li&gt;
&lt;li&gt;director&lt;/li&gt;
&lt;li&gt;producer&lt;/li&gt;
&lt;li&gt;release_date&lt;/li&gt;
&lt;li&gt;created&lt;/li&gt;
&lt;li&gt;edited&lt;/li&gt;
&lt;li&gt;url&lt;/li&gt;
&lt;li&gt;desc&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Data in Columns:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;title:&lt;/strong&gt; The movie title (e.g. "A New Hope").&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;episode_id:&lt;/strong&gt; The Star Wars episode number.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;opening_crawl:&lt;/strong&gt; The long Star Wars intro text that appears at the start of the film.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;director:&lt;/strong&gt; Film director name(s).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;producer:&lt;/strong&gt; Producer name(s).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;release_date:&lt;/strong&gt; Release date of the movie (e.g. "1977-05-25").&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;created&lt;/strong&gt;, &lt;strong&gt;edited:&lt;/strong&gt; Timestamps (likely for internal dataset management).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;url:&lt;/strong&gt; URL reference for the film.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;desc:&lt;/strong&gt; Another description, but appears redundant with opening_crawl.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Word Document Output:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The movies are ordered by release date, newest first, and written one per page. Each page includes release date, title, and description (using opening_crawl).&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;File written:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;code&gt;c:/temp/star_wars_movie.docx&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Summary of document:&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The document contains 7 movies, each on its own page, with release date, title, and description.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let me know if you want to see the content or need a different format!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The full output, including the final word document and all the iterations can be found &lt;a href="https://1drv.ms/f/c/e7c07309b5330772/EgzBSP2FZohMnJHhbGx97RYBrHt-EHheT2g2_Oc-f4BdiQ?e=3urUIh" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;I've tried different models and the &lt;strong&gt;results vary&lt;/strong&gt;. Some models stop half way, present the code to the user and &lt;strong&gt;ask whether to continue or not&lt;/strong&gt;. Others will write the code but ask you to execute it, they seems to ignore the tools presented even though they are capable of tool calling. It takes some &lt;strong&gt;trial and error&lt;/strong&gt; to craft a good prompt and fix this behavior.&lt;/p&gt;

&lt;p&gt;Interesting as it might be, it comes with a &lt;strong&gt;strong warning&lt;/strong&gt;: the code should only ever run in an isolated, sandboxed environment because there is absolutely no guarantee that no &lt;strong&gt;malicious code&lt;/strong&gt; is executed or &lt;strong&gt;flawed dependencies&lt;/strong&gt; are used. &lt;/p&gt;

&lt;p&gt;So where does that leave us? What would be the &lt;strong&gt;use case&lt;/strong&gt; for these kind of agents? I don't know. I was inspired by &lt;a href="https://microsoft.github.io/autogen-for-net/" rel="noopener noreferrer"&gt;AutoGen for .Net&lt;/a&gt;, which has the capability to &lt;a href="https://microsoft.github.io/autogen-for-net/articles/Run-dotnet-code.html" rel="noopener noreferrer"&gt;run code snippets&lt;/a&gt;. I think .Net 10 helps &lt;strong&gt;lower the barrier&lt;/strong&gt; to create Agents with coding capabilities.&lt;/p&gt;

&lt;p&gt;So, &lt;strong&gt;what do you think?&lt;/strong&gt; Do you see this as a useful feature or .. ? I am really curious about your opinion, so don't hesitate to drop a comment below!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>csharp</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Monitoring non-web apps using Azure Application Insights (Part 2: Basic Instrumentation)</title>
      <dc:creator>Peter Bons</dc:creator>
      <pubDate>Thu, 08 Aug 2019 09:54:58 +0000</pubDate>
      <link>https://dev.to/expecho/monitoring-non-web-apps-using-azure-application-insights-part-2-basic-instrumentation-2fcj</link>
      <guid>https://dev.to/expecho/monitoring-non-web-apps-using-azure-application-insights-part-2-basic-instrumentation-2fcj</guid>
      <description>&lt;p&gt;Welcome to the second post of this series covering the monitoring of non-web apps using Azure Application Insights.&lt;/p&gt;

&lt;p&gt;In the &lt;a href="https://dev.to/expecho/monitoring-non-website-applications-using-azure-application-insights-part-1--42oa"&gt;previous post&lt;/a&gt; we created an Application Insights resource using the Azure Portal and we integrated Application Insights into a simple console application. As a result we got live monitoring of our application as shown below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fexpecho.blob.core.windows.net%2Fblogposts%2FLiveMetricsStream-Basic.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fexpecho.blob.core.windows.net%2Fblogposts%2FLiveMetricsStream-Basic.PNG" alt="Live Metric Stream" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now it is time to add instrumentation to our code. The Application Insights SDK allows these entities to be tracked:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Page Views&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Exceptions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Requests&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Traces&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Dependencies&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Metrics&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Events&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you add Application Insights to a web application the whole tracking of page views, request, dependencies etc. is done automatically. Unfortunately, when building a Console, WPF or WinForms application we need to manually create telemetry items and send them using the &lt;a href="https://docs.microsoft.com/en-us/azure/azure-monitor/app/api-custom-events-metrics" rel="noopener noreferrer"&gt;SDK&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;To send telemetry to Application Insights we need a &lt;code&gt;TelemetryClient&lt;/code&gt;. There are several ways to create a telemetry item but there is one important thing to keep in mind. The real power of Application Insights is the ability to relate telemetry items. You do want to know what requests belong to what page view, what request triggered a dependency call and what was happening when an exception was thrown. We will come back to this later, let us first send some telemetry. We will extend the console application we created in the previous post.&lt;/p&gt;

&lt;p&gt;Say we add a method like this to the &lt;code&gt;Program&lt;/code&gt; class of the console application:&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;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;MakeHttpRequestAsync&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;httpClient&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;HttpClient&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;httpClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetStringAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"http://www.blank.org"&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;result&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;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HttpRequestException&lt;/span&gt; &lt;span class="n"&gt;ex&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;"Error getting text."&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;Given the code above I would like Application Insights to track that the method is called and how long it takes to execute. I would also be very happy to be able to see the &lt;code&gt;HttpRequestException&lt;/code&gt; being logged in Application Insights. Finally, I would be thrilled to know how long the call to the external dependency call to &lt;a href="http://www.blank.org" rel="noopener noreferrer"&gt;http://www.blank.org&lt;/a&gt; took. Also, if an exception other than an &lt;code&gt;HttpRequestException&lt;/code&gt; occurs, I would like to mark the method call as being failed.&lt;/p&gt;

&lt;p&gt;So, lets extend the method and use a &lt;code&gt;TelemetryClient&lt;/code&gt; to track the various telemetry items:&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;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;MakeHttpRequestAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;telemetryClient&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;TelemetryClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TelemetryConfiguration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Active&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;operation&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; 
                 &lt;span class="n"&gt;telemetryClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StartOperation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;RequestTelemetry&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MakeHttpRequestAsync&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;httpClient&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;HttpClient&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;httpClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetStringAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"http://www.blank.org"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;telemetryClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TrackTrace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"The http call returned '&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&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;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;result&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;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HttpRequestException&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;telemetryClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TrackException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ex&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;"Error getting text."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;catch&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;operation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Telemetry&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="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;throw&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We then modify the code of the &lt;code&gt;Main&lt;/code&gt; method in the &lt;code&gt;Program&lt;/code&gt; class created in the &lt;a href="https://dev.to/expecho/monitoring-non-website-applications-using-azure-application-insights-part-1--42oa"&gt;previous post&lt;/a&gt; to call this 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="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&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="n"&gt;ConsoleKeyInfo&lt;/span&gt; &lt;span class="n"&gt;keyInfo&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;ConsoleKeyInfo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keyInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;ConsoleKey&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Q&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;MakeHttpRequest&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
         &lt;span class="n"&gt;keyInfo&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;ReadKey&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;"Press any key to run again or Q to exit."&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;ReadKey&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;Let's walk through the code. We first create an instance of &lt;code&gt;TelemetryClient&lt;/code&gt; and we initialize it with a &lt;code&gt;TelemetryConfiguration.Active&lt;/code&gt;. This will apply the configuration as defined in the file &lt;code&gt;ApplicationInsights.config&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next, we start an operation to track the method call as a Request telemetry item in Application Insights using &lt;a href="https://docs.microsoft.com/en-us/azure/azure-monitor/app/api-custom-events-metrics#operation-context" rel="noopener noreferrer"&gt;&lt;code&gt;TelemetryClient.StartOperation()&lt;/code&gt;&lt;/a&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;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;operation&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; 
             &lt;span class="n"&gt;telemetryClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StartOperation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;RequestTelemetry&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MakeHttpRequestAsync&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the operation gets disposed at the end of the using block the total duration from start to end is calculated and the Request item is send to Application Insights.&lt;/p&gt;

&lt;p&gt;Next, in addition to tracking entities like Exceptions or Requests you can also log some arbitrary text in Application Insights using a Trace telemetry item. This is done using the line &lt;code&gt;telemetryClient.TrackTrace($"The http call returned '{result}'");&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In case of an exception we are able to handle we can log the exception in Application Insights. This is done by calling &lt;code&gt;telemetryClient.TrackException(ex);&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Finally, when an exception occurs that we cannot handle we can mark the call to the method as being failed by setting the value of the &lt;code&gt;Success&lt;/code&gt; property of the &lt;code&gt;RequestTelemetry&lt;/code&gt; to false. To get to the &lt;code&gt;RequestTelemetry&lt;/code&gt; of the Operation initiated by calling &lt;code&gt;TelemetryClient.StartOperation()&lt;/code&gt; we can use the &lt;code&gt;Telemetry&lt;/code&gt; property:&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;operation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Telemetry&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="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we re-throw the exception so the caller can deal with it. &lt;/p&gt;

&lt;p&gt;Before launching the application, open a tab in your browser and navigate to the Live Metrics Stream in Application Insights.&lt;/p&gt;

&lt;p&gt;Now, if we were to run the application we would see the telemetry appear in Application Insights. Note that it can take a few seconds before the Live Metrics Stream is initialized and a few more moments for telemetry items to appear in the portal: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fexpecho.blob.core.windows.net%2Fblogposts%2Fai-search.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fexpecho.blob.core.windows.net%2Fblogposts%2Fai-search.png" alt="Results in portal" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If we click on the request we get a more detailed view.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fexpecho.blob.core.windows.net%2Fblogposts%2Fai-search-result.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fexpecho.blob.core.windows.net%2Fblogposts%2Fai-search-result.png" alt="Results in portal" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can notice the telemetry items are grouped together. The portal will show you that the outgoing Http call originated from the request. That is the benefit of using `&lt;code&gt;TelemetryClient.StartOperation()&lt;/code&gt; as opposed to doing something like &lt;code&gt;telemetryClient.TrackRequest(...);&lt;/code&gt;. Once an operation is started all telemetry items that are sent in the scope of the operation are linked together.&lt;/p&gt;

&lt;p&gt;Furthermore we you can see that the outgoing Http call is detected by Application Insights and automatically logged. This is done by the &lt;code&gt;DependencyTrackingTelemetryModule&lt;/code&gt;. Application Insights can track more than http calls as seen &lt;a href="https://docs.microsoft.com/en-us/azure/azure-monitor/app/asp-net-dependencies#automatically-tracked-dependencies" rel="noopener noreferrer"&gt;in the docs&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fexpecho.blob.core.windows.net%2Fblogposts%2Fai-tracked-dependencies.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fexpecho.blob.core.windows.net%2Fblogposts%2Fai-tracked-dependencies.png" alt="Dependency Tracking" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The cool thing is, the telemetry created by the application is also captured by the Live Metrics Stream!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fexpecho.blob.core.windows.net%2Fblogposts%2Flive-metrics-anim.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fexpecho.blob.core.windows.net%2Fblogposts%2Flive-metrics-anim.gif" alt="Live Metric Stream" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The bad thing however, is the amount of code involved in instrumenting an application like this. Imagine having to write this code for each and every method you want to instrument. In the next blog post I will show you a way to make life a bit easier when it comes to this so stay tuned. I promise it won't take as long as it took for me to write this second part :-)&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>azure</category>
      <category>devops</category>
      <category>monitoring</category>
    </item>
    <item>
      <title>Service Fabric Remoting: Interception &amp; Custom Headers</title>
      <dc:creator>Peter Bons</dc:creator>
      <pubDate>Wed, 09 Jan 2019 19:46:45 +0000</pubDate>
      <link>https://dev.to/expecho/service-fabric-remoting-interception--custom-headers--3800</link>
      <guid>https://dev.to/expecho/service-fabric-remoting-interception--custom-headers--3800</guid>
      <description>&lt;p&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/service-fabric/" rel="noopener noreferrer"&gt;Service Fabric&lt;/a&gt; is a distributed systems platform for packaging, deploying, and managing stateless and stateful distributed applications and containers at large scale. Service Fabric runs on Windows and Linux, on any cloud, any datacenter, across geographic regions, or on your laptop.&lt;/p&gt;

&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;In this post we will learn two things that can make life easier to support advanced scenarios when using &lt;a href="https://docs.microsoft.com/en-us/azure/service-fabric/service-fabric-reliable-services-communication-remoting" rel="noopener noreferrer"&gt;Service Remoting&lt;/a&gt; for communication between services and actors. We will do this by making use of a &lt;a href="https://www.nuget.org/packages/ServiceFabric.Remoting.CustomHeaders/" rel="noopener noreferrer"&gt;simple library&lt;/a&gt; I created. It provides you with the ability to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Intercept service fabric remoting messages so you can take action when the call is about to be made and after it has been delivered.&lt;/li&gt;
&lt;li&gt;Add custom headers to the remoting messages. This can be used to, for example, add a trace identifier for call tracing &amp;amp; logging purposes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Message Interception
&lt;/h1&gt;

&lt;p&gt;Messages can be intercepted on both the sending side and the receiving side&lt;/p&gt;

&lt;h3&gt;
  
  
  Client-side message interception
&lt;/h3&gt;

&lt;p&gt;On the receiving side messages can be intercepted using the &lt;code&gt;BeforeHandleRequestResponseAsync&lt;/code&gt; and &lt;code&gt;AfterHandleRequestResponseAsync&lt;/code&gt; extension points when creating a service listener:&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;protected&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ServiceInstanceListener&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;CreateServiceInstanceListeners&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;yield&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;ServiceInstanceListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;FabricTransportServiceRemotingListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&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;ExtendedServiceRemotingMessageDispatcher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// Optional, log the call before being handled&lt;/span&gt;
                &lt;span class="n"&gt;BeforeHandleRequestResponseAsync&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reqInf&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;sw&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;Stopwatch&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;Start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                    &lt;span class="n"&gt;ServiceEventSource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ServiceMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                            &lt;span class="s"&gt;$"BeforeHandleRequest &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;reqInf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Service&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;reqInf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Method&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FromResult&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;object&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;sw&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="c1"&gt;// Optional, log the call after being handled&lt;/span&gt;
                &lt;span class="n"&gt;AfterHandleRequestResponseAsync&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;respInf&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;sw&lt;/span&gt; &lt;span class="p"&gt;=&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="n"&gt;respInf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                    &lt;span class="n"&gt;ServiceEventSource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ServiceMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                            &lt;span class="s"&gt;$"AfterHandleRequest &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;respInf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Method&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; 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;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CompletedTask&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Server-side message interception
&lt;/h3&gt;

&lt;p&gt;On the sending side messages can be intercepted using the &lt;code&gt;BeforeSendRequestResponseAsync&lt;/code&gt; and &lt;code&gt;AfterSendRequestResponseAsync&lt;/code&gt; extension points when creating the &lt;code&gt;ExtendedServiceRemotingClientFactory&lt;/code&gt; on constructor of the &lt;code&gt;ServiceProxyFactory&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;proxyFactory&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;ServiceProxyFactory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;// or ActorProxyFactory in case of actors&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ExtendedServiceRemotingClientFactory&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;FabricTransportServiceRemotingClientFactory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;remotingCallbackMessageHandler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
            &lt;span class="n"&gt;customHeadersProvider&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Optional, log the call before being handled&lt;/span&gt;
        &lt;span class="n"&gt;BeforeSendRequestResponseAsync&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reqInf&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;sw&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;Stopwatch&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;Start&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;$"BeforeSendRequest &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;reqInf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Method&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FromResult&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;object&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;sw&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="c1"&gt;// Optional, log the call after being handled&lt;/span&gt;
        &lt;span class="n"&gt;AfterSendRequestResponseAsync&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;respInf&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;sw&lt;/span&gt; &lt;span class="p"&gt;=&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="n"&gt;respInf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;duration&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="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;$"AfterSendRequest &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;respInf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Method&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; took &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;duration&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;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CompletedTask&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;h1&gt;
  
  
  Custom Headers
&lt;/h1&gt;

&lt;p&gt;Custom headers can be used to pass data between the sender and the receiver like tracing information or security context data. Using the &lt;code&gt;BeforeHandleRequestResponseAsync&lt;/code&gt; and &lt;code&gt;AfterHandleRequestResponseAsync&lt;/code&gt; actions additional logging can be applied monitor the flow between remoting calls.&lt;/p&gt;
&lt;h3&gt;
  
  
  Prepare the Reliable Service
&lt;/h3&gt;

&lt;p&gt;Modify the service and create a listener that can handle the requests:&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;protected&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ServiceInstanceListener&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;CreateServiceInstanceListeners&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;yield&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;ServiceInstanceListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;FabricTransportServiceRemotingListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&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;ExtendedServiceRemotingMessageDispatcher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&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;h3&gt;
  
  
  Adding custom headers (the caller)
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;customHeaders&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;CustomHeaders&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"Header1"&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="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"Header2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NewGuid&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;serviceUri&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;Uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"fabric:/ServiceFabric.Remoting.CustomHeaders.DemoApplication/DemoService"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;proxyFactory&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;ServiceProxyFactory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; 
                    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ExtendedServiceRemotingClientFactory&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;FabricTransportServiceRemotingClientFactory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;remotingCallbackMessageHandler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
                            &lt;span class="n"&gt;customHeaders&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;proxy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;proxyFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateServiceProxy&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IDemoService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;serviceUri&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;There is an overload of the Create method that accepts a Func. This is useful in scenarios where the created proxy factory or proxy is reused. Since creating a proxy factory is expensive this is the preferred way if you need dynamic header values. The func is invoked on every request made using the proxy.&lt;/p&gt;
&lt;h3&gt;
  
  
  Reading custom headers (the callee)
&lt;/h3&gt;

&lt;p&gt;The receiving service or actor can extract the values in the custom headers using the &lt;code&gt;RemotingContext&lt;/code&gt; class:&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;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&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="nf"&gt;SayHello&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;remotingContext&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="nf"&gt;Join&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;RemotingContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Keys&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;k&lt;/span&gt; &lt;span class="p"&gt;=&amp;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;k&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;RemotingContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&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;ServiceEventSource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ServiceMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
            &lt;span class="s"&gt;$"SayHelloToActor got context: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;remotingContext&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Got the following message headers: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;remotingContext&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h1&gt;
  
  
  What is next?
&lt;/h1&gt;

&lt;p&gt;More documentation and a demo Service Fabric application can be found at this repository:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Expecho" rel="noopener noreferrer"&gt;
        Expecho
      &lt;/a&gt; / &lt;a href="https://github.com/Expecho/ServiceFabric-Remoting-CustomHeaders" rel="noopener noreferrer"&gt;
        ServiceFabric-Remoting-CustomHeaders
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      This package allows injecting custom message headers into remoting messages (Actors and Reliable Services, V2 remoting only) at runtime. The headers are available client side to read. It also provides message interception using BeforeHandleRequestResponseAsync and AfterHandleRequestResponseAsync to act on remoting events.
    &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;ServiceFabric.Remoting.CustomHeaders&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;This package allows injecting custom headers into remoting messages (Actors and Reliable Services, V2 remoting only) at runtime. The headers are available client side to read
It also provides message interception using BeforeHandleRequestResponseAsync and AfterHandleRequestResponseAsync to act on remoting events.&lt;/p&gt;
&lt;p&gt;Common used classes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/Expecho/ServiceFabric-Remoting-CustomHeaders/blob/master/src/ServiceFabric.Remoting.CustomHeaders/CustomHeaders.cs" rel="noopener noreferrer"&gt;CustomHeaders&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Expecho/ServiceFabric-Remoting-CustomHeaders/blob/master/src/ServiceFabric.Remoting.CustomHeaders/RemotingContext.cs" rel="noopener noreferrer"&gt;RemotingContext&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;NuGet&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://www.nuget.org/packages/ServiceFabric.Remoting.CustomHeaders" rel="nofollow noopener noreferrer"&gt;Download the NuGet package&lt;/a&gt; &lt;a href="https://www.nuget.org/packages/ServiceFabric.Remoting.CustomHeaders/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/ebbb55552d7653892ff3a70f91f1e744495ddddb18d4c4698b0e109ec4122d00/687474703a2f2f696d672e736869656c64732e696f2f6e756765742f762f536572766963654661627269632e52656d6f74696e672e437573746f6d486561646572732e7376673f7374796c653d666c6174" alt="NuGet Status"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Examples&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;This repository includes a Service Fabric application for demonstration purposes. A &lt;a href="https://github.com/Expecho/ServiceFabric-Remoting-CustomHeaders/blob/master/src/Demo/Program.cs" rel="noopener noreferrer"&gt;Console Application&lt;/a&gt; is used to access the application and shows the usage of the package.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Usage scenarios&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;Custom headers can be used to pass data between the sender and the receiver like tracing information or security context data. Using the BeforeHandleRequestResponseAsync and AfterHandleRequestResponseAsync actions additional logging can be applied monitor the flow between remoting calls.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;How to use&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Prepare Reliable Services&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;Modify the service and create a listener that can handle the requests&lt;/p&gt;
&lt;div class="highlight highlight-source-cs notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;protected&lt;/span&gt; &lt;span class="pl-k"&gt;override&lt;/span&gt; &lt;span class="pl-smi"&gt;IEnumerable&lt;/span&gt;&lt;span class="pl-c1"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-smi"&gt;ServiceInstanceListener&lt;/span&gt;&lt;span class="pl-c1"&gt;&amp;gt;&lt;/span&gt; &lt;span class="pl-en"&gt;CreateServiceInstanceListeners&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;
&lt;span class="pl-kos"&gt;{&lt;/span&gt;
    &lt;span class="pl-k"&gt;yield&lt;/span&gt; &lt;span class="pl-k"&gt;return&lt;/span&gt; &lt;span class="pl-k"&gt;new&lt;/span&gt; &lt;span class="pl-smi"&gt;ServiceInstanceListener&lt;/span&gt;&lt;/pre&gt;…
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Expecho/ServiceFabric-Remoting-CustomHeaders" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


</description>
      <category>azure</category>
      <category>servicefabric</category>
      <category>microservices</category>
      <category>csharp</category>
    </item>
    <item>
      <title>Reporting Metrics Using .Net (Core) EventSource and EventCounter</title>
      <dc:creator>Peter Bons</dc:creator>
      <pubDate>Sun, 06 Jan 2019 14:22:54 +0000</pubDate>
      <link>https://dev.to/expecho/reporting-metrics-using-net-core-eventsource-and-eventcounter-23dn</link>
      <guid>https://dev.to/expecho/reporting-metrics-using-net-core-eventsource-and-eventcounter-23dn</guid>
      <description>&lt;p&gt;Hardly anybody argues the importance of instrumenting your code and there are some built-in log options in the .Net Framework, not to mention countless great 3rd party libraries like Nlog, Serilog and Log4Net. But when it comes to reporting metrics (Think: requests per minute, usage, message rate and things like that) the built-in support is very limited. Of course we have the Performance Counters but they cannot be used cross-platform as they are Windows only. Luckily there is a relative simple way to report metrics using the EventSource class that is cross-platform and a part of the Framework so there is no need for external dependencies.  &lt;/p&gt;

&lt;h1&gt;
  
  
  Introducing EventCounters
&lt;/h1&gt;

&lt;p&gt;ETW (Event Tracing for Windows) and the &lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.tracing.eventsource?view=netframework-4.7.2" rel="noopener noreferrer"&gt;&lt;code&gt;EventSource&lt;/code&gt;&lt;/a&gt; class have long been a part of the .Net Framework. EventSources are heavily used by the framework itself, and by a lot of (3rd party) libraries as well. It allows you to use structured logging in your application code with a minimal performance overhead. The data can be collected in-process or out-of-process using tools like &lt;a href="https://github.com/Microsoft/perfview" rel="noopener noreferrer"&gt;PerfView&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this blogpost we will take a closer look to the not so well-known &lt;code&gt;EventCounter&lt;/code&gt; class that lets us define and report metrics using an &lt;code&gt;EventSource&lt;/code&gt;. I specifically want to show how you can read those counters in-process using an &lt;code&gt;EventListener&lt;/code&gt; as this is not very well &lt;a href="https://github.com/dotnet/corefx/issues/30988" rel="noopener noreferrer"&gt;documented&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As a starter, let us see what the CoreFx team has to say about EventCounters (taken from their &lt;a href="https://github.com/dotnet/corefx/blob/master/src/System.Diagnostics.Tracing/documentation/EventCounterTutorial.md" rel="noopener noreferrer"&gt;tutorial&lt;/a&gt;): &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;While EventSource is fast, logging too many events for very frequent events is still a performance hit. In this tutorial, we will introduce EventCounter, a mechanism for measuring performance for very frequent events.&lt;/p&gt;

&lt;p&gt;For event that happen very frequently (for example, if it happen every few milliseconds), in general, you will want the performance overhead per event to be very low (e.g. less than a millisecond), otherwise it is going to cost a significant performance overhead. Logging an event, at the end of the day, need to write something to the disk. If the disk is not fast enough, you will lost events. We need a solution other than logging the event itself.&lt;/p&gt;

&lt;p&gt;When dealing with large number of events, knowing the measure per event is not very useful either. Most of the time all we need is just some statistics out of it. So we could crank the statistics within the process itself and then write an event once in a while to report the statistics, that's what EventCounter will do for us. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Sounds great, doesn't it? It is a matter of defining and reporting metrics and the framework will do the aggregation and calculation in memory. All we need to do is to specify the interval at which the data is outputted.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Recipe
&lt;/h1&gt;

&lt;p&gt;First, we need to define an &lt;code&gt;EventSource&lt;/code&gt; that will contain the &lt;code&gt;EventCounter&lt;/code&gt; instances. You can dynamically create &lt;code&gt;EventCounter&lt;/code&gt; instances at runtime but, due to a bug I documented &lt;a href="https://github.com/dotnet/corefx/issues/30904" rel="noopener noreferrer"&gt;here&lt;/a&gt;, you will have the create at least one &lt;code&gt;EventCounter&lt;/code&gt; instance in the constructor.&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;EventSource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"My-CustomMetricsEventSource-Minimal"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;sealed&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CustomMetricsEventSource&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;EventSource&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;EventCounter&lt;/span&gt; &lt;span class="n"&gt;methodDurationCounter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;Dictionary&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;,&lt;/span&gt; &lt;span class="n"&gt;EventCounter&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;dynamicCounters&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;Dictionary&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;,&lt;/span&gt; &lt;span class="n"&gt;EventCounter&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;CustomMetricsEventSource&lt;/span&gt; &lt;span class="n"&gt;Log&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;CustomMetricsEventSource&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;CustomMetricsEventSource&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;methodDurationCounter&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;EventCounter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;methodDurationCounter&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ReportMethodDurationInMs&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;methodDurationCounter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteMetric&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="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ReportMetric&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;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&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;dynamicCounters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryGetValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="n"&gt;EventCounter&lt;/span&gt; &lt;span class="n"&gt;counterInstance&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;counterInstance&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;EventCounter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;dynamicCounters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;counterInstance&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;counterInstance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteMetric&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;value&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;We will use &lt;code&gt;CustomMetricsEventSource&lt;/code&gt; to log our metrics in a console application. But we also need a listener that picks up the logged metrics and sends them to a destination. In this example we will write the data to the console using a custom implementation of an &lt;code&gt;EventListener&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;internal&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CustomMetricsEventListener&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;EventListener&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnEventWritten&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EventWrittenEventArgs&lt;/span&gt; &lt;span class="n"&gt;eventData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;counterData&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;eventData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToEventCounterData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Only write to console if actual data has been reported&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;counterData&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;Count&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="k"&gt;return&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;$"Counter &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;counterData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; reported values "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
            &lt;span class="s"&gt;$"Min: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;counterData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Min&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="s"&gt;$"Max: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;counterData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Max&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="s"&gt;$"Count &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;counterData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Count&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="s"&gt;$"Mean &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;counterData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Mean&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="s"&gt;$"StandardDeviation: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;counterData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StandardDeviation&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="s"&gt;$"IntervalSec: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;counterData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IntervalSec&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="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 code listened above uses the &lt;code&gt;ToEventCounterData&lt;/code&gt; method. This is actually an extension method. It returns an &lt;code&gt;EventCounterData&lt;/code&gt; instance which makes it easier to work with the reported metric data:&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;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EventWrittenEventArgsExtensions&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;IsEventCounter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;EventWrittenEventArgs&lt;/span&gt; &lt;span class="n"&gt;eventData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;eventData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EventName&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"EventCounters"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;EventCounterData&lt;/span&gt; &lt;span class="nf"&gt;ToEventCounterData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;EventWrittenEventArgs&lt;/span&gt; &lt;span class="n"&gt;eventData&lt;/span&gt;&lt;span class="p"&gt;)&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;eventData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsEventCounter&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&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;EventCounterData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eventData&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;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EventCounterData&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;EventCounterData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EventWrittenEventArgs&lt;/span&gt; &lt;span class="n"&gt;eventData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IDictionary&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;,&lt;/span&gt; &lt;span class="kt"&gt;object&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;)&lt;/span&gt; &lt;span class="n"&gt;eventData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Payload&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;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Name"&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="n"&gt;Mean&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Mean"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="n"&gt;StandardDeviation&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"StandardDeviation"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="n"&gt;Count&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Count"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="n"&gt;IntervalSec&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"IntervalSec"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="n"&gt;Min&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Min"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="n"&gt;Max&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Max"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;Mean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;StandardDeviation&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Count&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;IntervalSec&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;Min&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;Max&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&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;Finally we can create the console application that will call &lt;code&gt;CustomMetricsEventSource&lt;/code&gt; to log metric values. The &lt;code&gt;CustomMetricsEventListener&lt;/code&gt; is constructed in such a way that the metrics are outputted once per second. &lt;/p&gt;

&lt;p&gt;It is important to understand that it is the configuration of the &lt;code&gt;CustomMetricsEventListener&lt;/code&gt; that determines the metric reporting interval. This is done by passing a numeric value specifying the interval in seconds to the &lt;code&gt;EventCounterIntervalSec&lt;/code&gt; argument.&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;class&lt;/span&gt; &lt;span class="nc"&gt;Program&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;reader&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;CustomMetricsEventListener&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;arguments&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;Dictionary&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;,&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="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"EventCounterIntervalSec"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"1"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;EnableEvents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CustomMetricsEventSource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;EventLevel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LogAlways&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;EventKeywords&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="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;random&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;Random&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;i&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;i&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;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;SleepingBeauty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;200&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;ReadKey&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;SleepingBeauty&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;sleepTimeInMs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;stopwatch&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;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="n"&gt;sleepTimeInMs&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;Stop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="n"&gt;CustomMetricsEventSource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReportMethodDurationInMs&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="n"&gt;ElapsedMilliseconds&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;CustomMetricsEventSource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReportMetric&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"someCounter"&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;Millisecond&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;When we run the program we will see the metric values being reported to the console:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Counter methodDurationCounter reported values Min: 23, Max: 215, Count 8, Mean 113,125, StandardDeviation: 64,10429, IntervalSec: 1,026394&lt;/p&gt;

&lt;p&gt;Counter someCounter reported values Min: 87, Max: 982, Count 9, Mean 603,1111, StandardDeviation: 269,2832, IntervalSec: 1,026394&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Do mind that the metrics will always be reported at the specified interval (using &lt;code&gt;EventCounterIntervalSec&lt;/code&gt;) even if no call to the &lt;code&gt;WriteMetric&lt;/code&gt; method of an &lt;code&gt;EventCounter&lt;/code&gt; instance is made. All numeric values, except &lt;em&gt;IntervalSec&lt;/em&gt;, will have the default value 0.&lt;/p&gt;

&lt;p&gt;You can find the whole working example in my GitHub repository:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Expecho" rel="noopener noreferrer"&gt;
        Expecho
      &lt;/a&gt; / &lt;a href="https://github.com/Expecho/Blog" rel="noopener noreferrer"&gt;
        Blog
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Placeholder for code I blogged about, see
    &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;Blog&lt;/h1&gt;

&lt;/div&gt;

&lt;p&gt;Placeholder for code &lt;a href="https://dev.to/expecho" rel="nofollow"&gt;I blogged about&lt;/a&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Folders in this repository&lt;/h3&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Metrics: Reporting Metrics Using .Net (Core)&lt;/li&gt;
&lt;/ul&gt;

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


&lt;h1&gt;
  
  
  What is next?
&lt;/h1&gt;

&lt;p&gt;Of course, reporting those values to the console does not add much value, it is up to you to send the data to  your own logging backend. You could for example send them as custom metrics to Application Insights using the &lt;a href="https://docs.microsoft.com/en-us/azure/azure-monitor/app/eventcounters" rel="noopener noreferrer"&gt;EventCounterCollectionModule&lt;/a&gt;, log to your ELK stack or whatever log system you are using.&lt;/p&gt;

&lt;p&gt;I really wish reporting metrics gets a bit more attention since having metrics data available is very important in order to have a detailed insight in how your application is behaving. For example, you can use metrics to scale in or out or get insights in the usage of certain parts of your application. Most logging frameworks I know of do not cater for metrics.&lt;/p&gt;

&lt;p&gt;There was a lot of discussion about whether or not the support writing metric using the new &lt;code&gt;ILogger&lt;/code&gt; interface of .Net Core but in the end there is no support for it right know. More details about the how and the why can be read in the issue created for this discussion:&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/aspnet/Logging/issues/708" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Add support for reporting application metrics via logging
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#708&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/anurse" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars3.githubusercontent.com%2Fu%2F7574%3Fv%3D4" alt="anurse avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/anurse" rel="noopener noreferrer"&gt;anurse&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/aspnet/Logging/issues/708" rel="noopener noreferrer"&gt;&lt;time&gt;Sep 19, 2017&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;Overview&lt;/h2&gt;
&lt;p&gt;We want to enable applications to emit arbitrary named metrics and have them captured by telemetry/logging systems (App Insights, Elasticsearch/ELK, etc.) as well as other metrics systems (Statsd, InfluxDB, etc.). An abstraction is desired in order to allow applications to emit metrics without being coupled to the destination of the metrics, particularly with features like App Insights auto-lightup where the app doesn't directly depend upon App Insights.&lt;/p&gt;
&lt;h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;Proposal&lt;/h2&gt;
&lt;p&gt;We will add support for metrics reporting to &lt;code&gt;ILogger&lt;/code&gt;. It will be done via a new companion interface &lt;code&gt;IMetricsLogger&lt;/code&gt;, which loggers may &lt;strong&gt;optionally&lt;/strong&gt; implement. Applications can emit metrics through this interface (see API below), and logger providers which support metrics can receive and process those metrics. Metrics are &lt;code&gt;(name, value)&lt;/code&gt; tuples, where &lt;code&gt;value&lt;/code&gt; is always floating point number. Metrics are expected to be viewed in aggregate, hence it doesn't make sense to use a generic data type like &lt;code&gt;object&lt;/code&gt; for the metric, so metric values are always &lt;code&gt;double&lt;/code&gt;s. Supporting arbitrary types of metric values is a non-goal. Reporting metrics should be as efficient as possible, especially in the case where no logger provider is registered to listen for them, or they are filtered out.&lt;/p&gt;
&lt;h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;Why add to &lt;code&gt;ILogger&lt;/code&gt;?&lt;/h3&gt;
&lt;p&gt;Initially, I considered developing a new abstraction for Metrics. However, I encountered a few concerns:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;We would need to develop a structure for naming/organizing metrics (likely using type/namespace names as a base)&lt;/li&gt;
&lt;li&gt;We would need to develop a structure for filtering metrics (by categories, names, granularities, etc.)&lt;/li&gt;
&lt;li&gt;Many telemetry systems provide support for both log and metric collection, and would have to provide a new system&lt;/li&gt;
&lt;li&gt;Consumers have to pull in two different diagnostics reporters from DI (&lt;code&gt;ILogger&amp;lt;T&amp;gt;&lt;/code&gt;, &lt;code&gt;IMetricReporter&amp;lt;T&amp;gt;&lt;/code&gt;, etc.)&lt;/li&gt;
&lt;li&gt;This would create Yet Another Diagnostics Abstraction (on top of EventSource, EventCounters, DiagnosticSource, Perf Counters, yada yada yada (see what I did there? ;P))&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The fact that 1 and 2 above already exist in the Logging pipeline, and many metric sinks are also logging sinks, led to the idea of integrating metrics into Logging rather than creating a completely new abstraction.&lt;/p&gt;
&lt;p&gt;The main reason why we would &lt;strong&gt;not&lt;/strong&gt; want to add this to &lt;code&gt;ILogger&lt;/code&gt; would be a risk&lt;/p&gt;
&lt;h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;The API&lt;/h2&gt;
&lt;h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;&lt;code&gt;IMetricLogger&lt;/code&gt;
&lt;/h3&gt;
&lt;p&gt;Optional companion interface for &lt;code&gt;ILogger&lt;/code&gt; implementations to indicate their support for metrics. The &lt;code&gt;ILogger&lt;/code&gt; instances returned by &lt;code&gt;ILoggerProvider&lt;/code&gt; are expected to implement this interface &lt;em&gt;if and only if&lt;/em&gt; they wish to receive metrics.&lt;/p&gt;
&lt;div class="highlight highlight-source-cs js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;namespace&lt;/span&gt; &lt;span class="pl-en"&gt;Microsoft&lt;/span&gt;.&lt;span class="pl-en"&gt;Extensions&lt;/span&gt;.&lt;span class="pl-en"&gt;Logging&lt;/span&gt;
{
    &lt;span class="pl-k"&gt;public&lt;/span&gt; &lt;span class="pl-k"&gt;interface&lt;/span&gt; &lt;span class="pl-en"&gt;IMetricLogger&lt;/span&gt;
    {
        &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;///&lt;/span&gt; &amp;lt;&lt;span class="pl-ent"&gt;&lt;span class="pl-ent"&gt;summary&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;///&lt;/span&gt; Define a new metric with the provided name and return an &amp;lt;&lt;span class="pl-ent"&gt;&lt;span class="pl-ent"&gt;see&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-e"&gt;&lt;span class="pl-e"&gt;cref&lt;/span&gt;&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;IMetric&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;/&amp;gt; that can be used to report values for that metric.&lt;/span&gt;
        &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;///&lt;/span&gt; &amp;lt;/&lt;span class="pl-ent"&gt;&lt;span class="pl-ent"&gt;summary&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;///&lt;/span&gt; &amp;lt;&lt;span class="pl-ent"&gt;&lt;span class="pl-ent"&gt;param&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-e"&gt;&lt;span class="pl-e"&gt;name&lt;/span&gt;&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;name&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;&amp;gt;The name of the metric to define&amp;lt;/&lt;span class="pl-ent"&gt;&lt;span class="pl-ent"&gt;param&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;///&lt;/span&gt; &amp;lt;&lt;span class="pl-ent"&gt;&lt;span class="pl-ent"&gt;returns&lt;/span&gt;&lt;/span&gt;&amp;gt;An &amp;lt;&lt;span class="pl-ent"&gt;&lt;span class="pl-ent"&gt;see&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-e"&gt;&lt;span class="pl-e"&gt;cref&lt;/span&gt;&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;IMetric&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;/&amp;gt; that can be used to report values for the metric&amp;lt;/&lt;span class="pl-ent"&gt;&lt;span class="pl-ent"&gt;returns&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="pl-en"&gt;IMetric&lt;/span&gt; &lt;span class="pl-en"&gt;DefineMetric&lt;/span&gt;(&lt;span class="pl-k"&gt;string&lt;/span&gt; &lt;span class="pl-smi"&gt;name&lt;/span&gt;);
    }
}&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;&lt;code&gt;IMetric&lt;/code&gt;
&lt;/h3&gt;
&lt;p&gt;Interface that allows metric data to be reported. Metric values&lt;/p&gt;
&lt;div class="highlight highlight-source-cs js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;namespace&lt;/span&gt; &lt;span class="pl-en"&gt;Microsoft&lt;/span&gt;.&lt;span class="pl-en"&gt;Extensions&lt;/span&gt;.&lt;span class="pl-en"&gt;Logging&lt;/span&gt;
{
    &lt;span class="pl-k"&gt;public&lt;/span&gt; &lt;span class="pl-k"&gt;interface&lt;/span&gt; &lt;span class="pl-en"&gt;IMetric&lt;/span&gt;
    {
        &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;///&lt;/span&gt; &amp;lt;&lt;span class="pl-ent"&gt;&lt;span class="pl-ent"&gt;summary&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;///&lt;/span&gt; Record a new value for this metric.&lt;/span&gt;
        &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;///&lt;/span&gt; &amp;lt;/&lt;span class="pl-ent"&gt;&lt;span class="pl-ent"&gt;summary&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;///&lt;/span&gt; &amp;lt;&lt;span class="pl-ent"&gt;&lt;span class="pl-ent"&gt;param&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-e"&gt;&lt;span class="pl-e"&gt;name&lt;/span&gt;&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;value&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;&amp;gt;The value to record for this metric&amp;lt;/&lt;span class="pl-ent"&gt;&lt;span class="pl-ent"&gt;param&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="pl-k"&gt;void&lt;/span&gt; &lt;span class="pl-en"&gt;RecordValue&lt;/span&gt;(&lt;span class="pl-k"&gt;double&lt;/span&gt; &lt;span class="pl-smi"&gt;value&lt;/span&gt;);
    }
}&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;&lt;code&gt;LoggerMetricsExtensions&lt;/code&gt;
&lt;/h3&gt;
&lt;p&gt;Provides an extension method on &lt;code&gt;ILogger&lt;/code&gt; to enable consumers to emit metrics, even if the underlying logger provider doesn't support it (of course, the metrics will be ignored in that case).&lt;/p&gt;
&lt;div class="highlight highlight-source-cs js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;namespace&lt;/span&gt; &lt;span class="pl-en"&gt;Microsoft&lt;/span&gt;.&lt;span class="pl-en"&gt;Extensions&lt;/span&gt;.&lt;span class="pl-en"&gt;Logging&lt;/span&gt;
{
    &lt;span class="pl-k"&gt;public&lt;/span&gt; &lt;span class="pl-k"&gt;static&lt;/span&gt; &lt;span class="pl-k"&gt;class&lt;/span&gt; &lt;span class="pl-en"&gt;LoggerMetricsExtensions&lt;/span&gt;
    {
        &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;///&lt;/span&gt; &amp;lt;&lt;span class="pl-ent"&gt;&lt;span class="pl-ent"&gt;summary&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;///&lt;/span&gt; Define a new metric with the provided name and return an &amp;lt;&lt;span class="pl-ent"&gt;&lt;span class="pl-ent"&gt;see&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-e"&gt;&lt;span class="pl-e"&gt;cref&lt;/span&gt;&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;IMetric&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;/&amp;gt; that can be used to report values for that metric.&lt;/span&gt;
        &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;///&lt;/span&gt; &amp;lt;/&lt;span class="pl-ent"&gt;&lt;span class="pl-ent"&gt;summary&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;///&lt;/span&gt; &amp;lt;&lt;span class="pl-ent"&gt;&lt;span class="pl-ent"&gt;remarks&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;///&lt;/span&gt; If none of the registered logger providers support metrics, values recorded by this metric will be lost.&lt;/span&gt;
        &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;///&lt;/span&gt; &amp;lt;/&lt;span class="pl-ent"&gt;&lt;span class="pl-ent"&gt;remarks&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;///&lt;/span&gt; &amp;lt;&lt;span class="pl-ent"&gt;&lt;span class="pl-ent"&gt;param&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-e"&gt;&lt;span class="pl-e"&gt;name&lt;/span&gt;&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;name&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;&amp;gt;The name of the metric to define&amp;lt;/&lt;span class="pl-ent"&gt;&lt;span class="pl-ent"&gt;param&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;///&lt;/span&gt; &amp;lt;&lt;span class="pl-ent"&gt;&lt;span class="pl-ent"&gt;returns&lt;/span&gt;&lt;/span&gt;&amp;gt;An &amp;lt;&lt;span class="pl-ent"&gt;&lt;span class="pl-ent"&gt;see&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-e"&gt;&lt;span class="pl-e"&gt;cref&lt;/span&gt;&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;IMetric&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;/&amp;gt; that can be used to report values for the metric&amp;lt;/&lt;span class="pl-ent"&gt;&lt;span class="pl-ent"&gt;returns&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="pl-k"&gt;public&lt;/span&gt; &lt;span class="pl-k"&gt;static&lt;/span&gt; &lt;span class="pl-en"&gt;IMetric&lt;/span&gt; &lt;span class="pl-en"&gt;DefineMetric&lt;/span&gt;(&lt;span class="pl-k"&gt;this&lt;/span&gt; &lt;span class="pl-en"&gt;ILogger&lt;/span&gt; &lt;span class="pl-smi"&gt;logger&lt;/span&gt;, &lt;span class="pl-k"&gt;string&lt;/span&gt; &lt;span class="pl-smi"&gt;name&lt;/span&gt;)
        {
            &lt;span class="pl-k"&gt;if&lt;/span&gt;(&lt;span class="pl-smi"&gt;logger&lt;/span&gt; &lt;span class="pl-k"&gt;is&lt;/span&gt; &lt;span class="pl-en"&gt;IMetricLogger&lt;/span&gt; &lt;span class="pl-smi"&gt;metricLogger&lt;/span&gt;)
            {
                &lt;span class="pl-k"&gt;return&lt;/span&gt; &lt;span class="pl-smi"&gt;metricLogger&lt;/span&gt;.&lt;span class="pl-en"&gt;DefineMetric&lt;/span&gt;(&lt;span class="pl-smi"&gt;name&lt;/span&gt;);
            }
            &lt;span class="pl-k"&gt;return&lt;/span&gt; &lt;span class="pl-smi"&gt;NullMetric&lt;/span&gt;.&lt;span class="pl-smi"&gt;Instance&lt;/span&gt;;
        }
    }
}&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;&lt;code&gt;MetricValueExtensions&lt;/code&gt;
&lt;/h3&gt;
&lt;p&gt;Extension methods for &lt;code&gt;IMetric&lt;/code&gt; to support other common metric value types (as mentioned above, the underlying type is still &lt;code&gt;double&lt;/code&gt;, so the value must be representable as a &lt;code&gt;double&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Suggestion: We could have a &lt;code&gt;.Time()&lt;/code&gt; API that returns an &lt;code&gt;IDisposable&lt;/code&gt; which uses a Stopwatch to do the timing for you as well. That would be easy to add later though.&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight highlight-source-cs js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;using&lt;/span&gt; &lt;span class="pl-en"&gt;System&lt;/span&gt;;

&lt;span class="pl-k"&gt;namespace&lt;/span&gt; &lt;span class="pl-en"&gt;Microsoft&lt;/span&gt;.&lt;span class="pl-en"&gt;Extensions&lt;/span&gt;.&lt;span class="pl-en"&gt;Logging&lt;/span&gt;
{
    &lt;span class="pl-k"&gt;public&lt;/span&gt; &lt;span class="pl-k"&gt;static&lt;/span&gt; &lt;span class="pl-k"&gt;class&lt;/span&gt; &lt;span class="pl-en"&gt;MetricValueExtensions&lt;/span&gt;
    {
        &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;///&lt;/span&gt; &amp;lt;&lt;span class="pl-ent"&gt;&lt;span class="pl-ent"&gt;summary&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;///&lt;/span&gt; Record a new value for this metric.&lt;/span&gt;
        &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;///&lt;/span&gt; &amp;lt;/&lt;span class="pl-ent"&gt;&lt;span class="pl-ent"&gt;summary&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;///&lt;/span&gt; &amp;lt;&lt;span class="pl-ent"&gt;&lt;span class="pl-ent"&gt;remarks&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;///&lt;/span&gt; This is a convenience method that will convert the &amp;lt;&lt;span class="pl-ent"&gt;&lt;span class="pl-ent"&gt;see&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-e"&gt;&lt;span class="pl-e"&gt;cref&lt;/span&gt;&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;TimeSpan&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;/&amp;gt; to a &amp;lt;&lt;span class="pl-ent"&gt;&lt;span class="pl-ent"&gt;see&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-e"&gt;&lt;span class="pl-e"&gt;cref&lt;/span&gt;&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;double&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;/&amp;gt; via&lt;/span&gt;
        &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;///&lt;/span&gt; the &amp;lt;&lt;span class="pl-ent"&gt;&lt;span class="pl-ent"&gt;see&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-e"&gt;&lt;span class="pl-e"&gt;cref&lt;/span&gt;&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;TimeSpan.TotalMilliseconds&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;/&amp;gt; property.&lt;/span&gt;
        &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;///&lt;/span&gt; &amp;lt;/&lt;span class="pl-ent"&gt;&lt;span class="pl-ent"&gt;remarks&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;///&lt;/span&gt; &amp;lt;&lt;span class="pl-ent"&gt;&lt;span class="pl-ent"&gt;param&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-e"&gt;&lt;span class="pl-e"&gt;name&lt;/span&gt;&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;metric&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;&amp;gt;The metric to record the value on.&amp;lt;/&lt;span class="pl-ent"&gt;&lt;span class="pl-ent"&gt;param&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;///&lt;/span&gt; &amp;lt;&lt;span class="pl-ent"&gt;&lt;span class="pl-ent"&gt;param&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-e"&gt;&lt;span class="pl-e"&gt;name&lt;/span&gt;&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;value&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;&amp;gt;The value to record for this metric.&amp;lt;/&lt;span class="pl-ent"&gt;&lt;span class="pl-ent"&gt;param&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="pl-k"&gt;public&lt;/span&gt; &lt;span class="pl-k"&gt;static&lt;/span&gt; &lt;span class="pl-k"&gt;void&lt;/span&gt; &lt;span class="pl-en"&gt;RecordValue&lt;/span&gt;(&lt;span class="pl-k"&gt;this&lt;/span&gt; &lt;span class="pl-en"&gt;IMetric&lt;/span&gt; &lt;span class="pl-smi"&gt;metric&lt;/span&gt;, &lt;span class="pl-en"&gt;TimeSpan&lt;/span&gt; &lt;span class="pl-smi"&gt;value&lt;/span&gt;) &lt;span class="pl-k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="pl-smi"&gt;metric&lt;/span&gt;.&lt;span class="pl-en"&gt;RecordValue&lt;/span&gt;(&lt;span class="pl-smi"&gt;value&lt;/span&gt;.&lt;span class="pl-smi"&gt;TotalMilliseconds&lt;/span&gt;);
    }
}&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;&lt;code&gt;Logger&lt;/code&gt; updates&lt;/h3&gt;
&lt;p&gt;The aggregate &lt;code&gt;Logger&lt;/code&gt; class we return from &lt;code&gt;LoggerFactory.CreateLogger&lt;/code&gt; would be updated to support &lt;code&gt;IMetricsLogger&lt;/code&gt;, even if none of the &lt;code&gt;ILogger&lt;/code&gt;s it aggregates support it. It would only send metrics to the loggers that are known to support the interface.&lt;/p&gt;
&lt;h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;&lt;code&gt;Define&lt;/code&gt;/&lt;code&gt;Record&lt;/code&gt; pattern&lt;/h2&gt;
&lt;p&gt;In order to keep the performance cost as low as possible for recording the actual metric value, the API uses a &lt;code&gt;Define&lt;/code&gt;/&lt;code&gt;Record&lt;/code&gt; pattern. Consumers should expect to call &lt;code&gt;DefineMetric("foo")&lt;/code&gt; &lt;strong&gt;once&lt;/strong&gt; for a particular value of "foo" and store the result as globally as possible (in singleton types, etc.). It is &lt;code&gt;DefineMetric&lt;/code&gt; that does the bulk of the work to set up the metric recording. After calling &lt;code&gt;DefineMetric&lt;/code&gt;, the &lt;code&gt;RecordValue&lt;/code&gt; call on the &lt;code&gt;IMetric&lt;/code&gt; interface can choose how to store the value based on the providers needs. For example, in a provider that plans to send pre-aggregated metrics, the &lt;code&gt;RecordValue&lt;/code&gt; could simply update rolling aggregate values and then drop the actual recording (thus having constant storage requirements for each metric). If a provider needs to report individual metrics, it can use dynamically-allocated buffers or ring buffers, depending upon the configuration and the needs of the provider. As an example of an &lt;code&gt;IMetric&lt;/code&gt; implementation based on pre-aggregating data, see &lt;a href="https://gist.github.com/anurse/03c6746204317bd3616c372b4df9dbba" rel="noopener noreferrer"&gt;https://gist.github.com/anurse/03c6746204317bd3616c372b4df9dbba&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;Filtering Metrics&lt;/h2&gt;
&lt;p&gt;&lt;del&gt;Metrics should be filterable, and they should participate in the existing Logger filtering pipeline. My current proposal is that Metrics are treated like &lt;code&gt;LogLevel.Critical&lt;/code&gt; messages, in that if the category is enabled at all, the metrics are written. We could consider capturing a &lt;code&gt;LogLevel&lt;/code&gt; in &lt;code&gt;.DefineMetric&lt;/code&gt; and using that to provide different "levels" of metrics. Since the existing filters only let you filter by Provider, Category, and Level, it is very difficult to filter out specific metrics by name (as that would require a new Filter structure). This may make &lt;code&gt;LogLevel&lt;/code&gt; support for metrics more important.&lt;/del&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;@pakrym and I talked and came up with a specific suggestion&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Metrics can be filtered at the provider and category name, but there is no concept of a &lt;code&gt;LogLevel&lt;/code&gt; for metrics. However, filters can disable &lt;strong&gt;all&lt;/strong&gt; metrics for a particular provider/category combination. To do this, we'll add an &lt;code&gt;AllowMetrics&lt;/code&gt; boolean to &lt;code&gt;LoggerFilterRule&lt;/code&gt; which defaults to &lt;code&gt;true&lt;/code&gt;. When writing a metric, we'll check the provider and category name against the filter options as well as checking this boolean.&lt;/p&gt;
&lt;h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;Scopes and Property Bags&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;FEEDBACK REQUESTED&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;My initial thought is that Metrics exist outside of scopes, as they are generally aggregated and Scopes imply per-event data. Providers could, in theory, give their &lt;code&gt;IMetric&lt;/code&gt; instances access to read active scope data, and attach them to metrics if they choose (for example, systems that report unaggregated metrics may want to). For similar reasons, property bags (i.e. Log Values/Structured Logging, etc.) don't really make sense for metrics in general as they are usually aggregated. Having said that, many providers do support arbitrary properties (InfluxDB, App Insights), so some level of support may be useful. We could easily add an optional parameter to &lt;code&gt;.RecordValue&lt;/code&gt; to allow adding arbitrary properties to each metric, and providers could choose to disregard it if it doesn't make sense for that provider.&lt;/p&gt;
&lt;h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;Impact on existing Providers&lt;/h2&gt;
&lt;p&gt;There is minimal impact on existing Providers. Because the interface provides an opt-in model for a provider to receive metrics, existing providers are unaffected. I'd imagine providers like Serilog would not participate in this system as they don't have an infrastructure for metrics (/cc @nblumhardt , I may be wrong!). Providers like App Insights may choose to either add metrics support to their existing providers or add new providers that only handle metrics (and ignore log messages) that are co-registered.&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/aspnet/Logging/issues/708" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


</description>
      <category>devops</category>
      <category>csharp</category>
      <category>monitoring</category>
      <category>logging</category>
    </item>
    <item>
      <title>One year of answering Stack Overflow questions. The Good, The Bad and The Ugly.</title>
      <dc:creator>Peter Bons</dc:creator>
      <pubDate>Sun, 30 Dec 2018 20:53:48 +0000</pubDate>
      <link>https://dev.to/expecho/one-year-of-answering-stack-overflow-questions-the-good-the-bad-and-the-ugly--2df6</link>
      <guid>https://dev.to/expecho/one-year-of-answering-stack-overflow-questions-the-good-the-bad-and-the-ugly--2df6</guid>
      <description>&lt;p&gt;I have been a member of Stack Overflow for a long time now, asking the occasional question now and then. But is has not been until the beginning of this year that I started being more involved in the community by answering questions. So far it has been an overall pleasant experience, and given I almost reached 10k rep. in one year tells me that most of my effort actually helped people out.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fses7ojnm75jbz9pli31u.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fses7ojnm75jbz9pli31u.jpg" alt="graph" width="500" height="229"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this post I like to share my experience of being a contributor to this well-known community. &lt;/p&gt;

&lt;h1&gt;
  
  
  The Good
&lt;/h1&gt;

&lt;p&gt;There are a couple of things I like about doing this. For one thing, I like sharing knowledge and helping people out by solving some of their problems. It does not take that much time (I do pick my battles though, I will came back to this later) and I love the times I learn something new due to other answers or the question itself. For example, more often than not there are different ways to tackle a problem and I've learned new or other ways of doing things on numerous occasions. &lt;/p&gt;

&lt;p&gt;Sometimes I just don't know the answer but if it is about one of those topics I am particularly interested in I might fire up something like &lt;a href="https://www.linqpad.net/" rel="noopener noreferrer"&gt;LinqPad&lt;/a&gt; or Visual Studio (Code) to try and solve it. I see it as a fun way of learning new stuff.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Bad
&lt;/h1&gt;

&lt;p&gt;If there is one thing that I have learned in this time is that asking a good question is an art. I think Jon Skeet summarizes the main points in &lt;a href="https://codeblog.jonskeet.uk/2010/08/29/writing-the-perfect-question/" rel="noopener noreferrer"&gt;this blogpost&lt;/a&gt;.  For example, I often see questions lacking the proper context that is necessary for me to be able to provide an answer. &lt;/p&gt;

&lt;p&gt;People get upset when their question is downvoted or closed but instead of editing their question based on the comments they almost all leave it as it is to never return to the site again. That is a pity, because I am sure most people genuinely want to help and do not close questions just for the sake of it. I wish every participant that has his or hers question closed or downvoted take the time to read &lt;a href="https://codeblog.jonskeet.uk/2012/11/24/stack-overflow-question-checklist/" rel="noopener noreferrer"&gt;this checklist&lt;/a&gt; and make another attempt.&lt;/p&gt;

&lt;p&gt;I also quickly learned that answers providing a direction of thoughts or hints on how to solve the problem aren't as much appreciated as answers that literally fixes the problem at hand. Is that a bad thing? Not per se, I do understand that when you have a problem you want an answer that can help you out immediately. But there are times I think it would be better to discover the answer yourself using some tips and guidance so it leads to a better understanding of how things work. Asynchronous and parallel computing is one of those topics this really applies to.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Ugly
&lt;/h1&gt;

&lt;p&gt;It is not until recently that I became aware of &lt;a href="https://stackoverflow.blog/2018/04/26/stack-overflow-isnt-very-welcoming-its-time-for-that-to-change/" rel="noopener noreferrer"&gt;the problems&lt;/a&gt; this community faces when it comes to being (un)welcoming to new contributors and the attitude of some contributors towards others. Sure, I have seen some ugly comments or unfriendly behavior but it never struck me as such a widespread issue. I know there are efforts made to change this, and it is not the goal of this post to address it but I sincerely hope that Stack Overflow gets back its reputation as the primary source for developers to get help on any programming related question no matter their skillset and knowledge.&lt;/p&gt;

&lt;p&gt;Communication is key here. Negative feedback is a widespread issue on the internet nowadays and Stack Overflow is no exception. Sadly, the world of developers isn't always one happy community (The world of Open Source is &lt;a href="https://www.zdnet.com/article/github-open-source-is-dominated-by-men-who-just-cant-communicate/" rel="noopener noreferrer"&gt;another example&lt;/a&gt;). I rather try to gain a better understanding of the problem by asking questions about the question than to leave some snarky comment about the low quality of the question. We all had to start somewhere when we entered the world of programming so I keep that in mind.&lt;/p&gt;

&lt;h1&gt;
  
  
  My approach
&lt;/h1&gt;

&lt;p&gt;I soon realized I did not want to spend too much time on checking the website for new and interesting questions. I decided that I wanted to put my effort in answering questions in topics I am interested in, or have detailed knowledge about. Therefore I wrote my own bot that posts questions having specific tags I am interested in to a Slack channel using an Azure Function. You are welcome to check it out:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Expecho" rel="noopener noreferrer"&gt;
        Expecho
      &lt;/a&gt; / &lt;a href="https://github.com/Expecho/StackOverflow-To-Slack-Tag-Tracker" rel="noopener noreferrer"&gt;
        StackOverflow-To-Slack-Tag-Tracker
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Azure Function that acts as a bot which creates notifications in a Slack channel about StackOverflow activity based on the question tags
    &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;StackOverflow -&amp;gt; Slack Tag Tracker&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Azure Function that acts as a bot which creates notifications in a &lt;a href="https://slack.com/" rel="nofollow noopener noreferrer"&gt;Slack&lt;/a&gt; channel about &lt;a href="https://stackoverflow.com/" rel="nofollow noopener noreferrer"&gt;StackOverflow&lt;/a&gt; activity based on the question tags.&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/Expecho/StackOverflow-To-Slack-Tag-Trackermedia/slack.PNG?raw=true"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FExpecho%2FStackOverflow-To-Slack-Tag-Trackermedia%2Fslack.PNG%3Fraw%3Dtrue" alt="Overview"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Getting up &amp;amp; running&lt;/h1&gt;
&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;Create a new timer based Azure Function (for javascript). For instructions see &lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-create-first-azure-function" rel="nofollow noopener noreferrer"&gt;the docs&lt;/a&gt;. I recommend a timer that will fire every 15 minutes, due to the api request limitations of Stack Overflow.&lt;/li&gt;
&lt;li&gt;Install the required node.js packages. Instructions can be found &lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-reference-node#node-version-and-package-management" rel="nofollow noopener noreferrer"&gt;here&lt;/a&gt;. The package.json file is in this repository.&lt;/li&gt;
&lt;li&gt;Replace the default javascript code with the code in this repository. Then change the configuration to your liking*&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;A Slack token can be generated &lt;a href="https://api.slack.com/apps" rel="nofollow noopener noreferrer"&gt;here&lt;/a&gt;. A StackOverflow token can be created &lt;a href="https://stackapps.com/apps/oauth/register" rel="nofollow noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Configuration&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;The configuration is defined using environment variables:&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;    slackbot_username: "StackOverflow Tag Tracker",
    slackbot_icon_emoji: ':incoming_envelope:',
    slackbot_token: '&amp;lt;token&amp;gt;',
    slackbot_channel: '&amp;lt;channel&amp;gt;',
    slackbot_workspace: '&amp;lt;workspace&amp;gt;',
    so_api_key: '&amp;lt;api key&amp;gt;',
    so_tracked_tags: 'azure;asp.net-web-api|powerbi',
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;slackbot_username&lt;/strong&gt;&lt;/em&gt;&lt;br&gt;
The bot account name&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;slackbot_icon_emoji&lt;/strong&gt;&lt;/em&gt;&lt;br&gt;
The Slack…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Expecho/StackOverflow-To-Slack-Tag-Tracker" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Anyway, don't let the bad &amp;amp; the ugly deter you from making Stack Overflow a better place. There are plenty of opportunities to help people out because one thing is for sure, in our ever changing world there will always be a new source of questions. &lt;/p&gt;

</description>
      <category>stackoverflow</category>
      <category>discuss</category>
      <category>learning</category>
    </item>
    <item>
      <title>Monitoring non-web apps using Azure Application Insights (Part 1: Getting Started)</title>
      <dc:creator>Peter Bons</dc:creator>
      <pubDate>Fri, 14 Dec 2018 21:25:35 +0000</pubDate>
      <link>https://dev.to/expecho/monitoring-non-website-applications-using-azure-application-insights-part-1--42oa</link>
      <guid>https://dev.to/expecho/monitoring-non-website-applications-using-azure-application-insights-part-1--42oa</guid>
      <description>&lt;p&gt;This is the first post of a serie in which we will take a look at how we can use &lt;a href="https://docs.microsoft.com/en-us/azure/application-insights/app-insights-overview" rel="noopener noreferrer"&gt;Application Insights&lt;/a&gt; to monitor other applications besides web applications. Most application landscapes are a mixture of cloudbased and on-premises applications. Some are webbased, some are desktop applications. Would it not be great if we can use one tool to monitor them all? Luckely there is Application Insights, a low cost monitoring solution running on Azure.&lt;/p&gt;

&lt;p&gt;This post will cover the introduction of Application Insights and the first steps of monitoring a desktop application.&lt;/p&gt;

&lt;h1&gt;
  
  
  What is Application Insights?
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;Application Insights is an &lt;strong&gt;extensible&lt;/strong&gt; Application Performance Management (APM) service for web developers on &lt;strong&gt;multiple platforms&lt;/strong&gt;. Use it to monitor your live web application. It will automatically detect performance anomalies. It includes &lt;strong&gt;powerful analytics&lt;/strong&gt; tools to help you diagnose issues and to understand what users actually do with your app. It's designed to help you continuously improve performance and usability. It works for apps on a wide variety of platforms including &lt;strong&gt;.NET, Node.js and J2EE&lt;/strong&gt;, hosted &lt;strong&gt;on-premises or in the cloud&lt;/strong&gt;. It integrates with your DevOps process, and has connection points to a variety of development tools.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;There are a couple of things to like about Application Insights:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It is tightly integrated in many Azure Services like Azure Web Apps, Azure Functions, Azure Kubernetes Services and many more.&lt;/li&gt;
&lt;li&gt;It is really easy to configure. (Very often it is either automatically done or it need at most one or two clicks)&lt;/li&gt;
&lt;li&gt;It has a powerful querying mechanism called &lt;a href="https://docs.microsoft.com/en-us/azure/application-insights/app-insights-analytics" rel="noopener noreferrer"&gt;Application Insights Analytics&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;It has many extension points. For example, you can &lt;a href="https://docs.microsoft.com/en-us/azure/application-insights/app-insights-api-filtering-sampling" rel="noopener noreferrer"&gt;enrich or filter&lt;/a&gt; telemetry and &lt;a href="https://docs.microsoft.com/en-us/azure/application-insights/app-insights-api-custom-events-metrics?toc=/azure/azure-monitor/toc.json" rel="noopener noreferrer"&gt;track your own&lt;/a&gt; telemetry.&lt;/li&gt;
&lt;li&gt;You can &lt;a href="https://docs.microsoft.com/en-us/azure/azure-monitor/visualizations?toc=/azure/azure-monitor/toc.json" rel="noopener noreferrer"&gt;create and pin&lt;/a&gt; your own visuals.&lt;/li&gt;
&lt;li&gt;It has powerful &lt;a href="https://docs.microsoft.com/en-us/azure/azure-monitor/platform/alerts-overview" rel="noopener noreferrer"&gt;alerting capabilities&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;It is not restricted to workloads running in the cloud.&lt;/li&gt;
&lt;li&gt;It is &lt;a href="https://github.com/Microsoft?utf8=%E2%9C%93&amp;amp;q=applicationinsights&amp;amp;type=&amp;amp;language=" rel="noopener noreferrer"&gt;Open Source&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Monitoring a simple desktop application
&lt;/h1&gt;

&lt;p&gt;Most documentation and blogposts regarding Application Insights deal with setting up monitoring web applications. This is really straight forward since all that needs to be done is adding some NuGet packages, provide an Instrumentation Key and add some config code. Then you get automatically request, exception and trace telemetry send to Application Insights since it can hook into several extension points provided by the Asp.Net (Core) framework. But unfortunately, when you are stuck developing desktop applications using WPF or WinForms for example, there is no such mechanism as a request pipeline to use. But, as we will explore in this serie, that does not mean we cannot use Application Insights at all.&lt;/p&gt;

&lt;p&gt;So, without further ado, this is what will be covered by this serie:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Provisioning an Application Insights resource in Azure and enable the &lt;a href="https://docs.microsoft.com/en-us/azure/application-insights/app-insights-live-stream" rel="noopener noreferrer"&gt;Live Metrics Stream&lt;/a&gt; of our little console application.&lt;/li&gt;
&lt;li&gt;Add basic instrumentation to our code and have it send to Application Insights.&lt;/li&gt;
&lt;li&gt;Enhancing our instrumentation by automatically tracking exceptions, requests and dependencies.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Provisioning an Application Insights resource
&lt;/h2&gt;

&lt;p&gt;The first thing we need to do is obviously creating an Application Insights resource for us to use. Then we need to extract the Instrumentation Key that we need in our application to configure the Application Insights integration.&lt;/p&gt;

&lt;p&gt;Go to the &lt;a href="https://portal.azure.com/" rel="noopener noreferrer"&gt;Azure Portal&lt;/a&gt; and create an Application Insights resource:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fexpecho.blob.core.windows.net%2Fblogposts%2Fcreate-appinsights.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fexpecho.blob.core.windows.net%2Fblogposts%2Fcreate-appinsights.png" alt="Create Resource" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once the resource is created, browse to it and note the instrumentation key. We will use this key in our application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fexpecho.blob.core.windows.net%2Fblogposts%2Fappinsights-getinstkey.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fexpecho.blob.core.windows.net%2Fblogposts%2Fappinsights-getinstkey.png" alt="Get InstrumentationKety" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That is it for now. It is time to create our application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enabling Application Insights in our application
&lt;/h2&gt;

&lt;p&gt;I created a .Net 4.7.2 console application using Visual Studio 2017. To use Application Insights we will have to add a reference to the Microsoft.ApplicationInsights.WindowsServer &lt;a href="https://www.nuget.org/packages/Microsoft.ApplicationInsights.WindowsServer/" rel="noopener noreferrer"&gt;NuGet Package&lt;/a&gt;. (This will automatically reference the Microsoft.ApplicationInsights package)&lt;/p&gt;

&lt;p&gt;When the NuGet Packages are installed a new file is added to the project, called &lt;code&gt;ApplicationInsights.config&lt;/code&gt;. Open that file and add the InstrumentationKey add the top like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;ApplicationInsights&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.microsoft.com/ApplicationInsights/2013/Settings"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;InstrumentationKey&amp;gt;&lt;/span&gt;YOUR_KEY_HERE&lt;span class="nt"&gt;&amp;lt;/InstrumentationKey&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;TelemetryInitializers&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Add&lt;/span&gt; &lt;span class="na"&gt;Type=&lt;/span&gt;&lt;span class="s"&gt;"Microsoft.ApplicationInsights.DependencyCollector.HttpDependenciesParsingTelemetryInitializer, Microsoft.AI.DependencyCollector"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Add&lt;/span&gt; &lt;span class="na"&gt;Type=&lt;/span&gt;&lt;span class="s"&gt;"Microsoft.ApplicationInsights.WindowsServer.AzureRoleEnvironmentTelemetryInitializer, Microsoft.AI.WindowsServer"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Add&lt;/span&gt; &lt;span class="na"&gt;Type=&lt;/span&gt;&lt;span class="s"&gt;"Microsoft.ApplicationInsights.WindowsServer.AzureWebAppRoleEnvironmentTelemetryInitializer, Microsoft.AI.WindowsServer"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Add&lt;/span&gt; &lt;span class="na"&gt;Type=&lt;/span&gt;&lt;span class="s"&gt;"Microsoft.ApplicationInsights.WindowsServer.BuildInfoConfigComponentVersionTelemetryInitializer, Microsoft.AI.WindowsServer"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/TelemetryInitializers&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;TelemetryModules&amp;gt;&lt;/span&gt;
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we could have chosen to just send some "Hello World" message from our application to Application Insights but let us just make it a bit more juicier than that. Would it not be nice if we have some real-time insights of the cpu and memory usage of our machine running the application? Let us try by modifying our console application to make this happen:&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;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.ApplicationInsights.Extensibility&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;NonWebIntegrationDemo&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="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="n"&gt;_&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TelemetryConfiguration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Active&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;"Press any key to exit."&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;ReadKey&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The line &lt;code&gt;_ = TelemetryConfiguration.Active;&lt;/code&gt; triggers the SDK to start sending telemetry to Application Insights.&lt;/p&gt;

&lt;p&gt;Now, build and execute the application and leave it running. Browse to the Azure Portal and navigate to your Application Insights resource. From there, open the Live Metrics Stream tab and observe the live feed of the application:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fexpecho.blob.core.windows.net%2Fblogposts%2Fappinsights-livestream.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fexpecho.blob.core.windows.net%2Fblogposts%2Fappinsights-livestream.png" alt="Live Metric Stream-Nav" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fexpecho.blob.core.windows.net%2Fblogposts%2FLiveMetricsStream-Basic.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fexpecho.blob.core.windows.net%2Fblogposts%2FLiveMetricsStream-Basic.PNG" alt="Live Metric Stream" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It might take a few moments before the live stream shows data, so be patient.&lt;/p&gt;

&lt;p&gt;That is it for now! We have created an Application Insights resource and configured it successfully in our console application. This will be our starting point for the next post, stay tuned.&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>azure</category>
      <category>devops</category>
      <category>monitoring</category>
    </item>
  </channel>
</rss>
