<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Ivan Kahl's Blog]]></title><description><![CDATA[Ivan Kahl's Blog]]></description><link>https://ivankahl.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Wed, 04 Nov 2026 20:04:57 GMT</lastBuildDate><atom:link href="https://ivankahl.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Mastering the C# Dispose Pattern]]></title><description><![CDATA[The .NET runtime comes with efficient resource management, helping you build robust applications. It can allocate, manage, and reclaim memory efficiently…]]></description><link>https://ivankahl.hashnode.dev/csharp-dispose-pattern</link><guid isPermaLink="true">https://ivankahl.hashnode.dev/csharp-dispose-pattern</guid><category><![CDATA[dotnet]]></category><category><![CDATA[dotnetcore]]></category><category><![CDATA[Programming Tips]]></category><category><![CDATA[C#]]></category><dc:creator><![CDATA[Ivan Kahl]]></dc:creator><pubDate>Mon, 13 Oct 2025 11:44:14 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1760353326321/b99ef2e2-fdc5-4bdc-a7a9-441a0c635765.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The .NET runtime comes with efficient resource management, helping you build robust applications. It can allocate, manage, and reclaim memory efficiently for objects, helping prevent memory leaks and memory exhaustion. Most cleanup is done automatically. However, there are scenarios where you, as the developer, need to manually clean up unmanaged resources that the runtime cannot see.</p>
<p>This guide will briefly explain how .NET's resource management works and its limitations when it comes to dealing with unmanaged resources. You'll then see how the <code>IDisposable</code> interface can be implemented in different scenarios to ensure resources are cleaned up properly.</p>
<h2 id="heading-resource-management-in-net">Resource Management in .NET</h2>
<p>The .NET runtime manages a memory heap for your application's reference types. While the runtime handles the allocation, the Garbage Collector (GC) is responsible for automatically reclaiming memory from objects that are no longer in use. It is also responsible for optimizing memory by compacting the heap. This entire process frees you from manually deallocating memory.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text"><strong>What are Reference Types? </strong><a target="_self" href="https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/reference-types">Reference types</a> are any .NET types whose values get stored on the heap instead of the stack. When you assign such a type to a variable, the variable stores a <em>reference</em> to the object on the heap. This is unlike <a target="_self" href="https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/value-types">value types</a>, which store the actual value in the variable.</div>
</div>

<p>Since the runtime manages the memory for reference types, it's called <em>managed memory</em>. However, applications can often use <em>unmanaged resources.</em> The memory for these resources sits outside the runtime's control and visibility. Such resources can include file handles, database connections, and network sockets. Because it has no visibility of these resources, the GC has no way of compacting or reclaiming this memory automatically. Instead, the class itself needs to release these unmanaged resources to prevent memory leaks.</p>
<p>To solve this problem, .NET provides the <code>IDisposable</code> interface to <a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-idisposable">deterministically cleanup resources</a>. The following section demonstrates a simple <code>IDisposable</code> implementation that is most commonly used.</p>
<h2 id="heading-the-basic-dispose-pattern-a-simple-implementation">The Basic Dispose Pattern: A Simple Implementation</h2>
<p>In most cases, your classes will work with unmanaged resources that are already wrapped in their own <code>IDisposable</code> classes.</p>
<p>For instance, your class might use the <code>NpgsqlConnection</code> class to establish a connection to a PostgreSQL database. Even though the database connection is an unmanaged resource, the <code>NpgsqlConnection</code> class already implements a <code>Dispose()</code> method to manage those resources. Your class's <code>Dispose()</code> method simply needs to call the database's <code>Dispose()</code> method.</p>
<p>This is demonstrated in the code snippet below:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">CustomerRepository</span> : <span class="hljs-title">IDisposable</span>
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">bool</span> _disposed = <span class="hljs-literal">false</span>;

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> NpgsqlConnection _connection;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">CustomerRepository</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> connectionString</span>)</span>
    {
        _connection = <span class="hljs-keyword">new</span> NpgsqlConnection(connectionString);
        _connection.Open();
    }

    <span class="hljs-comment">// Methods that use the database connection...</span>

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Dispose</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-keyword">if</span> (_disposed)
            <span class="hljs-keyword">return</span>;

        _disposed = <span class="hljs-literal">true</span>;

        <span class="hljs-comment">// Call the database Dispose() method to handle cleanup</span>
        _connection.Dispose();
    }
}
</code></pre>
<p>Notice how the <code>CustomerRepository.Dispose()</code> method makes a call to the underlying database connection to dispose it. Now the unmanaged resource is taken care of. Nothing too complicated!</p>
<p>The <code>_disposed</code> field also keeps track of whether the dispose method has been called already. This is important, since your <code>Dispose()</code> method <a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose#implement-the-dispose-pattern-for-a-derived-class"><em>should</em> <em>always be idempotent</em></a><em>,</em> otherwise exceptions might be thrown.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text"><strong>Cascading </strong><code>Dispose()</code><strong> Calls:</strong> Whenever your class <em>owns</em> a class that implements <code>IDisposable</code>, it <em>must</em> <a target="_self" href="https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose#cascade-dispose-calls">cascade dispose calls</a> down to those owned objects to ensure proper cleanup. However, this is <em>not necessary</em> if your class <em>doesn't own</em> the resource (e.g., it was passed in as a dependency in the constructor).</div>
</div>

<h3 id="heading-consuming-the-idisposable-class">Consuming the <code>IDisposable</code> Class</h3>
<p>When consuming the class above, you should use the <code>using</code> block as it automatically calls <code>Dispose()</code> for you when you're finished with the object:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> (<span class="hljs-keyword">var</span> repository = <span class="hljs-keyword">new</span> CustomerRepository(_connectionString))
{
    <span class="hljs-comment">// Use repository here...</span>
} <span class="hljs-comment">// Calls repository.Dispose() automatically</span>
</code></pre>
<p>Notice how the <code>Dispose()</code> method is called as soon as you reach the end of the <code>using</code> block.</p>
<p>You can also remove the block, in which case the <code>Dispose()</code> method will be called when the surrounding code block ends:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">private</span> Customer? FindCustomer(<span class="hljs-keyword">int</span> id)
{
    <span class="hljs-comment">// Create repository with `using var`</span>
    <span class="hljs-keyword">using</span> <span class="hljs-keyword">var</span> repository = <span class="hljs-keyword">new</span> CustomerRepository(_connectionString);

    <span class="hljs-keyword">return</span> repository.Get(id);
} <span class="hljs-comment">// Calls repository.Dispose() automatically</span>
</code></pre>
<p>In the snippet above, the <code>Dispose()</code> method will be called automatically after the function returns.</p>
<h2 id="heading-the-full-dispose-pattern-handling-unmanaged-resources">The Full Dispose Pattern: Handling Unmanaged Resources</h2>
<p>The implementation above will suffice for most of your <code>IDisposable</code> implementations. However, there might be times when you're dealing with unmanaged resources directly (i.e., they aren't wrapped in their own <code>IDisposable</code>). In those cases, there are a couple more things to consider in your implementation.</p>
<p>Take a look at the implementation below:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> Microsoft.Win32.SafeHandles;
<span class="hljs-keyword">using</span> System.ComponentModel;
<span class="hljs-keyword">using</span> System.Runtime.InteropServices;

<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">UnmanagedFileHandler</span> : <span class="hljs-title">IDisposable</span>
{
    <span class="hljs-comment">// Raw, unmanaged resource pointer</span>
    <span class="hljs-keyword">private</span> IntPtr _handle;

    <span class="hljs-comment">// Managed resource</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> MemoryStream _buffer;

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">bool</span> _disposed = <span class="hljs-literal">false</span>;

    <span class="hljs-comment">// Using a constant for the invalid handle value for clarity.</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">readonly</span> IntPtr INVALID_HANDLE_VALUE = <span class="hljs-keyword">new</span>(<span class="hljs-number">-1</span>);

    <span class="hljs-comment">// Import the CreateFile function from the Windows API.</span>
    [<span class="hljs-meta">DllImport(<span class="hljs-meta-string">"kernel32.dll"</span>, SetLastError = true, CharSet = CharSet.Unicode)</span>]
    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">extern</span> IntPtr <span class="hljs-title">CreateFile</span>(<span class="hljs-params">
        <span class="hljs-keyword">string</span> lpFileName,
        <span class="hljs-keyword">uint</span> dwDesiredAccess,
        <span class="hljs-keyword">uint</span> dwShareMode,
        IntPtr lpSecurityAttributes,
        <span class="hljs-keyword">uint</span> dwCreationDisposition,
        <span class="hljs-keyword">uint</span> dwFlagsAndAttributes,
        IntPtr hTemplateFile</span>)</span>;

    <span class="hljs-comment">// Import the CloseHandle function.</span>
    [<span class="hljs-meta">DllImport(<span class="hljs-meta-string">"kernel32.dll"</span>, SetLastError = true)</span>]
    [<span class="hljs-meta">return: MarshalAs(UnmanagedType.Bool)</span>]
    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">extern</span> <span class="hljs-keyword">bool</span> <span class="hljs-title">CloseHandle</span>(<span class="hljs-params">IntPtr hObject</span>)</span>;

    <span class="hljs-comment">// Constants for file access from the Windows API.</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">const</span> <span class="hljs-keyword">uint</span> GENERIC_WRITE = <span class="hljs-number">0x40000000</span>;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">const</span> <span class="hljs-keyword">uint</span> CREATE_ALWAYS = <span class="hljs-number">2</span>;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">const</span> <span class="hljs-keyword">uint</span> NO_SHARING = <span class="hljs-number">0</span>;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">const</span> <span class="hljs-keyword">uint</span> DEFAULT_ATTRIBUTES = <span class="hljs-number">0</span>;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">UnmanagedFileHandler</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> filePath</span>)</span>
    {
        <span class="hljs-comment">// Call the unmanaged Windows API to get a file handle.</span>
        _handle = CreateFile(
            filePath,
            GENERIC_WRITE,
            NO_SHARING,
            IntPtr.Zero,
            CREATE_ALWAYS,
            DEFAULT_ATTRIBUTES,
            IntPtr.Zero);

        _buffer = <span class="hljs-keyword">new</span> MemoryStream();

        <span class="hljs-comment">// Check if the handle is valid. If not, throw an exception.</span>
        <span class="hljs-keyword">if</span> (_handle == INVALID_HANDLE_VALUE)
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Win32Exception(Marshal.GetLastWin32Error(), <span class="hljs-string">"Failed to create the file handle."</span>);
    }

    <span class="hljs-comment">// File methods here...</span>

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Dispose</span>(<span class="hljs-params"></span>)</span>
    {
        Dispose(<span class="hljs-literal">true</span>);
        GC.SuppressFinalize(<span class="hljs-keyword">this</span>);
    }

    ~UnmanagedFileHandler()
    {
        Dispose(<span class="hljs-literal">false</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">virtual</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Dispose</span>(<span class="hljs-params"><span class="hljs-keyword">bool</span> disposing</span>)</span>
    {
        <span class="hljs-keyword">if</span> (_disposed)
            <span class="hljs-keyword">return</span>;

        <span class="hljs-keyword">if</span> (disposing)
        {
            <span class="hljs-comment">// Dispose managed resources if called from Dispose()</span>
            _buffer.Dispose();
        }

        <span class="hljs-comment">// Always dispose unmanaged resources</span>
        <span class="hljs-keyword">if</span> (_handle != IntPtr.Zero &amp;&amp; _handle != INVALID_HANDLE_VALUE)
        {
            CloseHandle(_handle);
            _handle = IntPtr.Zero;
        }

        _disposed = <span class="hljs-literal">true</span>;
    }
}
</code></pre>
<p>That's a bit more code!</p>
<p>First, notice how the class has an <code>IntPtr</code> pointing to a file, which is created using Window's low-level <code>CreateFile</code> method. This pointer is an unmanaged resource that has to be cleaned up manually.</p>
<p>A <code>MemoryStream</code> is also created to act as a buffer. This is another unmanaged resource. However, because the <code>MemoryStream</code> class implements <code>IDisposable</code>, you only need to call the <code>Dispose()</code> method on that field.</p>
<p>There's also a new <code>Dispose(bool disposing)</code> method. It cleans up managed and unmanaged resources. This method can be called from two places in the class: the <code>IDisposable.Dispose()</code> method, or the class finalizer.</p>
<p>The GC calls the finalizer before reclaiming the object's memory.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text"><strong>What are Finalizers?</strong> Finalizers are another name for destructors in C#. These methods have a simple signature: <code>public ~ClassName() {}</code></div>
</div>

<p>When calling the new <code>Dispose(bool disposing)</code> method, the <code>disposing</code> parameter is determined by the origin of the method call:</p>
<ul>
<li><p>When called from <code>IDisposable.Dispose()</code>, then <code>disposing</code> is <code>true</code>, meaning both managed and unmanaged resources should be cleaned up.</p>
</li>
<li><p>When called from the finalizer (i.e., <code>~UnmanagedFileHandler()</code>), then <code>disposing</code> is <code>false</code>, so only unmanaged resources are cleaned up. This is because the GC will finalize the owned managed resources, so no need to <code>Dispose()</code> them ourselves.</p>
</li>
</ul>
<p><code>GC.SuppressFinalize()</code> is also called on the current object in the <code>Dispose()</code> method. This tells the GC that it does <em>not</em> need to call the finalizer method on this class.</p>
<p>This is necessary for performance reasons, since finalizers are not exactly efficient. When the GC encounters a class with a finalizer that needs to be reclaimed, it first places that finalizer on a queue to execute later. This is to prevent the current GC run from being potentially delayed by calling the finalizer immediately. Once the current GC run is finished, the finalizer is executed. Only after the finalizer is executed does the class become eligible to be reclaimed.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1760353603446/cb942822-fece-46ef-9fb3-48799b9f5b1c.webp" alt="Diagram illustrating how the finalizer is executed after the current GC run, delaying memory being reclaimed." class="image--center mx-auto" /></p>
<p>So by suppressing the finalizer on the class, the memory for that class can be immediately reclaimed without waiting for the finalizer to execute first.</p>
<p>Finally, you'll see the <code>Dispose(bool disposing)</code> method is <code>virtual</code>. In the next section, you'll find out why this is necessary when it comes to class inheritance with <code>IDisposable</code>.</p>
<h2 id="heading-disposing-of-inherited-classes">Disposing of Inherited Classes</h2>
<p>What happens if a class inherits from your <code>IDisposable</code> class and uses its own unmanaged resources? The child class's resources also need to be cleaned up, along with the parent class's resources.</p>
<p>Fortunately, since the <code>Dispose(bool disposing)</code> method is <code>virtual</code>, a child class can execute its own cleanup logic when the class is disposed.</p>
<p>The code snippet below is for a <code>LogFileHandler</code> class, which inherits from the <code>UnmanagedFileHandler</code> class referenced above.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">LogFileHandler</span> : <span class="hljs-title">UnmanagedFileHandler</span>
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">bool</span> _disposed = <span class="hljs-literal">false</span>;

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> MemoryStream _logBuffer;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">LogFileHandler</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> filePath</span>) : <span class="hljs-title">base</span>(<span class="hljs-params">filePath</span>)</span>
    {
        _logBuffer = <span class="hljs-keyword">new</span> MemoryStream();
    }

    <span class="hljs-comment">// Log methods here...</span>

    <span class="hljs-comment">// Override the parent class Dispose method to clean up the additional resource.</span>
    <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Dispose</span>(<span class="hljs-params"><span class="hljs-keyword">bool</span> disposing</span>)</span>
    {
        <span class="hljs-keyword">if</span> (_disposed)
            <span class="hljs-keyword">return</span>;

        _disposed = <span class="hljs-literal">true</span>;

        <span class="hljs-keyword">if</span> (disposing)
        {
            <span class="hljs-comment">// Dispose the additional managed resource</span>
            _logBuffer.Dispose();
        }

        <span class="hljs-comment">// No unmanaged resources to clean up in this child class</span>

        <span class="hljs-comment">// Call the base class Dispose method</span>
        <span class="hljs-keyword">base</span>.Dispose(disposing);
    }
}
</code></pre>
<p>The <code>LogFileHandler</code> class has its own <code>MemoryStream</code> field, which is used to buffer log messages. This resource implements the <code>IDisposable</code> interface, so the <code>LogFileHandler</code> must override the <code>Dispose(bool disposing)</code> method from the parent class to dispose of the buffer. When overriding the method, <em>the base class</em> <code>Dispose(bool disposing)</code> method must still be called.</p>
<p>Since the <code>Dispose(bool disposing)</code> method is already called from the <code>IDisposable.Dispose()</code> and finalizer in the base class, there's no need to implement them in the <code>LogFileHandler</code> class.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text"><strong>What If I Never Plan On Inheriting?</strong> If your <code>IDisposable</code> class will never be inherited from, <a target="_self" href="https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/sealed">mark the class as <code>sealed</code></a> and remove the <code>virtual</code> flag from the <code>Dispose(bool disposing)</code> method.</div>
</div>

<h2 id="heading-best-practices">Best Practices</h2>
<p>When implementing any of the patterns above, keep these things in mind to ensure your disposal logic is robust.</p>
<h3 id="heading-ensure-idempotency">Ensure Idempotency</h3>
<p>Calls to <code>Dispose()</code> should always be idempotent to avoid exceptions from being thrown. This can happen if part of disposing of a property sets it to an invalid value (like <code>null</code>):</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Dispose</span>(<span class="hljs-params"></span>)</span>
{
    _connection.Dispose();
    _connection = <span class="hljs-literal">null</span>;
}
</code></pre>
<p>If, for any reason, the <code>Dispose()</code> method above is called again, a <code>NullReferenceException</code> will be thrown because <code>_connection</code> was set to <code>null</code> previously.</p>
<p>So it's best to always use a <code>_disposed</code> private field to track if the dispose has already been run:</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Dispose</span>(<span class="hljs-params"></span>)</span>
{
    <span class="hljs-keyword">if</span> (_disposed)
        <span class="hljs-keyword">return</span>;

    _disposed = <span class="hljs-literal">true</span>;

    _connection.Dispose();
    _connection = <span class="hljs-literal">null</span>;
}
</code></pre>
<p>Now the method will return early if it's ever called multiple times.</p>
<h3 id="heading-dont-throw-exceptions-in-finalizers">Don't Throw Exceptions in Finalizers</h3>
<p>When implementing a finalizers that dispose resources, it's crucial to avoid throwing any exceptions as they can have unintended side effects, <a target="_blank" href="https://stackoverflow.com/questions/20358401/throwing-exception-in-finalizer-to-enforce-dispose-calls">like causing the entire application to crash</a>.</p>
<p>Always write your finalizers as defensively as possible to prevent unhandled exceptions from surfacing.</p>
<h3 id="heading-cascade-dispose-calls-to-owned-resources">Cascade Dispose Calls to Owned Resources</h3>
<p>Any class that owns resources that implement <code>IDisposable</code> must implement the <code>IDisposable</code> interface and call the <code>Dispose()</code> method on those resources in its own <code>Dispose()</code> method. If not done, owned resources won't be released, which could cause memory leaks.</p>
<h3 id="heading-always-call-base-class-dispose">Always Call Base Class Dispose</h3>
<p>If a class inherits from another class implementing <code>IDisposable</code>, make sure you override the <code>Dispose(bool disposing)</code> method to release any unmanaged resources in the inherited class.</p>
<p>Also, always <em>call the base class's</em> <code>Dispose(bool disposing)</code> method from the overridden method.</p>
<h3 id="heading-use-safehandle-to-managed-those-unmanaged-resources">Use <code>SafeHandle</code> to Managed Those Unmanaged Resources</h3>
<p>The full Dispose pattern is necessary if your class deals with unmanaged resources directly (i.e., the resources don't have an existing <code>IDisposable</code> wrapper, such as <code>IntPtr</code>). However, the .NET runtime comes with <code>SafeHandle</code> classes that can wrap any raw unmanaged <code>IntPtr</code> in an <code>IDisposable</code>. These wrapper classes manage the pointer for you, meaning your class only needs to implement the Basic Dispose pattern.</p>
<p>The <a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose#safe-handles">official documentation goes into great detail on <code>SafeHandles</code> and how they simplify disposing of a class</a>.</p>
<h3 id="heading-disposing-asynchronously-with-iasyncdisposable">Disposing Asynchronously with <code>IAsyncDisposable</code></h3>
<p>When your class holds resources that involve asynchronous operations during cleanup (like closing a database connection or releasing a lock), you should implement the <code>IAsyncDisposable</code> instead of (or in addition to) <code>IDisposable</code>. This allows for non-blocking cleanup, keeping your application responsive.</p>
<p>The <code>IAsyncDisposable</code> interface <a target="_blank" href="https://source.dot.net/#System.Private.CoreLib/src/libraries/System.Private.CoreLib/src/System/IAsyncDisposable.cs">expects a <code>ValueTask DisposeAsync()</code> method to be implemented</a>.</p>
<p>Below is an example of implementing the <code>IAsyncDisposable</code> interface:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">CustomerRepository</span> : <span class="hljs-title">IAsyncDisposable</span>
{
    <span class="hljs-comment">// ... </span>

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> ValueTask <span class="hljs-title">DisposeAsync</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-comment">// Implement asychronous cleanup logic</span>
        <span class="hljs-keyword">await</span> _connection.DisposeAsync();

        <span class="hljs-comment">// Also implement any synchronous cleanup here as well</span>
        _buffer.Dispose();
    }
}
</code></pre>
<p>Consuming an <code>IAsyncDisposable</code> class is similar to the <code>IDisposable</code> class. You just need to add <code>await</code> to your using statement:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">await</span> <span class="hljs-keyword">using</span> (<span class="hljs-keyword">var</span> repository = <span class="hljs-keyword">new</span> CustomerRepository(_connectionString))
{
    <span class="hljs-comment">// Use repository here</span>
} <span class="hljs-comment">// Calls repository.DisposeAsync() automatically</span>
</code></pre>
<h2 id="heading-conclusion">Conclusion</h2>
<p>While the .NET GC does a great job of managing memory, it cannot clean unmanaged resources, like low-level file handles or database connections. The <code>IDisposable</code> interface helps ensure all managed and unmanaged resources are cleaned up deterministically.</p>
<p>Hopefully, this guide has shed some light on the Dispose pattern in C#. In most cases, you'll stick to the first, simple implementation. However, if you ever have to clean up unmanaged resources manually, a bit more code is needed to make it work.</p>
<p>By implementing the <code>IDisposable</code> interface properly, you'll reduce the number of potential memory leaks, resulting in a robust and stable end product.</p>
]]></content:encoded></item><item><title><![CDATA[Case-sensitive and Case-insensitive String Comparisons in PowerShell]]></title><description><![CDATA[I wrote a PowerShell script the other day and, while doing so, discovered an interesting fact about string comparison in PowerShell that is quite contrary…]]></description><link>https://ivankahl.hashnode.dev/case-sensitive-and-case-insensitive-string-comparisons-in-powershell</link><guid isPermaLink="true">https://ivankahl.hashnode.dev/case-sensitive-and-case-insensitive-string-comparisons-in-powershell</guid><category><![CDATA[Powershell]]></category><dc:creator><![CDATA[Ivan Kahl]]></dc:creator><pubDate>Sat, 18 Dec 2021 07:36:17 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1639812934577/nyV0GR0-w.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I wrote a PowerShell script the other day and, while doing so, discovered an interesting fact about string comparison in PowerShell that is quite contrary to .NET (and thus unfamiliar for me): string comparisons are case-insensitive by default.</p>
<p>This caught me off-guard since my particular use case required a case-sensitive comparison. I managed to get case-sensitive comparisons to work and thought I'd share it.</p>
<h2 id="heading-using-the-equals-operator-eq-ceq">Using the Equals operator (-eq/-ceq)</h2>
<p>When you would like to see if two strings are exactly the same, you can make use of the equals operator.</p>
<h3 id="heading-case-insensitive-equals-eq">Case-Insensitive Equals (-eq)</h3>
<p>You can use <code>-eq</code> to perform a case-insensitive string comparison.</p>
<pre><code class="lang-powershell">❯ "Ivan Kahl's Blog" -eq "ivan kahl's BLOG"
True
</code></pre>
<h3 id="heading-case-sensitive-equals-ceq">Case-Sensitive Equals (-ceq)</h3>
<p>If you would like to do a case-sensitive string comparison, you can use <code>-ceq</code>:</p>
<pre><code class="lang-powershell">❯ "Ivan Kahl's Blog" -ceq "ivan kahl's BLOG"
False
</code></pre>
<h2 id="heading-using-the-like-operator-like-clike">Using the Like operator (-like/-clike)</h2>
<p>You can also use patterns for string comparisons using the Like operator in Powershell.</p>
<h3 id="heading-case-insensitive-like-like">Case-Insensitive Like (-like)</h3>
<p>If you want to use a pattern for string comparison and not worry about the case, use <code>-like</code>:</p>
<pre><code class="lang-powershell">❯ "Ivan Kahl's Blog" -like "ivan kahl's*"
True
</code></pre>
<h3 id="heading-case-sensitive-like-clike">Case-Sensitive Like (-clike)</h3>
<p>If you do want to check case while using string patterns, you can make use of <code>-clike</code>:</p>
<pre><code class="lang-powershell">❯ "Ivan Kahl's Blog" -clike "ivan kahl's*"
False
</code></pre>
<h2 id="heading-closing">Closing</h2>
<p>I hope you found this quick tip useful. If you have any questions or thoughts, please leave a comment below.</p>
]]></content:encoded></item><item><title><![CDATA[Logging .NET to AWS CloudWatch: Understanding the basics using AWS SDK]]></title><description><![CDATA[AWS CloudWatch is a management tool in AWS that allows us to monitor resources in AWS and hosted elsewhere. One form of monitoring that AWS CloudWatch…]]></description><link>https://ivankahl.hashnode.dev/logging-net-to-aws-cloudwatch-understanding-the-basics-using-aws-sdk</link><guid isPermaLink="true">https://ivankahl.hashnode.dev/logging-net-to-aws-cloudwatch-understanding-the-basics-using-aws-sdk</guid><category><![CDATA[dotnet]]></category><category><![CDATA[AWS]]></category><category><![CDATA[.NET]]></category><category><![CDATA[C#]]></category><dc:creator><![CDATA[Ivan Kahl]]></dc:creator><pubDate>Fri, 10 Dec 2021 06:13:28 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1639808074873/vlCOoF__N.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>AWS CloudWatch is a management tool in AWS that allows us to monitor resources in AWS and hosted elsewhere. One form of monitoring that AWS CloudWatch offers is ingesting logs from different services so that they can be browsed and queried from a single interface.</p>
<p>Many services in the AWS ecosystem feed their logs directly into CloudWatch by default without any configuration needed. This is convenient when debugging AWS services, but you might find yourself figuring out how to send your own application's logs to AWS (when AWS doesn't automatically forward them to AWS CloudWatch like it does with some services). This could happen if you are running your application on an EC2 instance or in a container.</p>
<p>In this article, we are going to look at how we can log messages to AWS CloudWatch in .NET. We will be using the AWS SDK to get a low-level, first principles understanding of how it's done before having a look at logging to AWS CloudWatch using popular logging libraries such as Serilog and NLog in future posts.</p>
<h2 id="heading-video">Video</h2>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=IbP_NoWyuI4">https://www.youtube.com/watch?v=IbP_NoWyuI4</a></div>
<h2 id="heading-prerequisites">Prerequisites</h2>
<h3 id="heading-aws-account">AWS Account</h3>
<p>You will need an active AWS account that we can use to push logs from our .NET application to AWS CloudWatch. Our volumes will be minimal so we shouldn't exceed the <a target="_blank" href="https://aws.amazon.com/cloudwatch/pricing/">free tier for AWS CloudWatch</a>. </p>
<p>If you don't have an AWS account yet, you can sign up for one <a target="_blank" href="https://portal.aws.amazon.com/billing/signup#/start">here</a>.</p>
<h3 id="heading-aws-profile">AWS Profile</h3>
<p>Since this article is just focusing on AWS CloudWatch, we won't be configuring any AWS credentials in our .NET application. Rather, we will let the AWS SDK automatically use our AWS profile that is set up when running the AWS CLI. This simplifies the demonstrations as we don't have to fumble around with permissions and credentials.</p>
<p><strong>However, please note that you should always make sure to give applications their own IAM roles/users in production with minimal permissions according to AWS best practices.</strong></p>
<h2 id="heading-lets-go">Let's Go!</h2>
<p>With that out the way, let's get started!</p>
<h3 id="heading-1-create-a-new-console-application">1. Create a new Console application</h3>
<p>We will be using a .NET 6 Console application in this demonstration. You can create this project using either Visual Studio 2022 or the .NET 6 CLI.</p>
<h3 id="heading-2-add-the-aws-sdk-nuget-package">2. Add the AWS SDK Nuget package</h3>
<p>Before we can do anything with AWS CloudWatch from .NET, we need to install the <em>AWSSDK.CloudWatchLogs</em> Nuget package. This will allow us to make calls to the AWS CloudWatch service from .NET programmatically using an SDK developed by AWS.</p>
<h3 id="heading-3-create-a-logging-class">3. Create a Logging class</h3>
<p>We will be encapsulating our logging logic in a single Logging class (called <code>CloudWatchLogger</code>). This will neaten up our logging logic and keep it out of our application code.</p>
<p><strong>While we are creating our own CloudWatchLogger, it will be a heavily simplified logger that aims to simply demonstrate how most logging libraries log to AWS CloudWatch. In production, it is advisable to use an existing logging library to log to AWS CloudWatch rather than try roll your own.</strong></p>
<h3 id="heading-4-asynchronously-construct-our-cloudwatchlogger-class">4. Asynchronously construct our CloudWatchLogger class</h3>
<p>When interacting with AWS services using the AWS SDK, all of our operations occur asynchronously. This is important to remember because we are going to do some initialization in AWS CloudWatch when creating our logger. In order to do this initialization, we need to be able to construct our <code>CloudWatchLogger</code> asynchronously.</p>
<p>You can see how we are able to do this using a <code>private</code> constructor and asynchronous <code>static</code> method:</p>
<p><strong>CloudWatchLogger.cs</strong></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">namespace</span> <span class="hljs-title">AWSCloudWatchLoggingWithAWSSDK</span>;

<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">CloudWatchLogger</span>
{
    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-title">CloudWatchLogger</span>(<span class="hljs-params"></span>)</span>
    {
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">async</span> Task&lt;CloudWatchLogger&gt; <span class="hljs-title">GetLoggerAsync</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-keyword">var</span> logger = <span class="hljs-keyword">new</span> CloudWatchLogger();

        <span class="hljs-comment">// Do more initialization work here</span>

        <span class="hljs-keyword">return</span> logger;
    }
}
</code></pre>
<p>The pattern you're seeing is similar to the factory method of constructing objects where we have a method create instances of an object.</p>
<h3 id="heading-5-create-the-amazoncloudwatchlogsclient">5. Create the AmazonCloudWatchLogsClient</h3>
<p>We first need to create an instance of AmazonCloudWatchLogsClient that we will then use to call AWS CloudWatch methods. We will create a new instance in the constructor and assign it to a private field for later use:</p>
<p><strong>CloudWatchLogger.cs</strong></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> Amazon.CloudWatchLogs;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">AWSCloudWatchLoggingWithAWSSDK</span>;

<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">CloudWatchLogger</span>
{
    <span class="hljs-keyword">private</span> IAmazonCloudWatchLogs _client;

    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-title">CloudWatchLogger</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-comment">// If don't have an AWS Profile on your machine and application is hosted outside</span>
        <span class="hljs-comment">// of AWS infrastructure (where IAM roles cannot be assigned to infrastructure),</span>
        <span class="hljs-comment">// rather use:</span>
        <span class="hljs-comment">// _client = new AmazonCloudWatchLogsClient(awsAccessKeyId, awsSecretAccessKey, RegionEndpoint.AFSouth1);</span>
        _client = <span class="hljs-keyword">new</span> AmazonCloudWatchLogsClient();
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">async</span> Task&lt;CloudWatchLogger&gt; <span class="hljs-title">GetLoggerAsync</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-keyword">var</span> logger = <span class="hljs-keyword">new</span> CloudWatchLogger();

        <span class="hljs-keyword">return</span> logger;
    }
}
</code></pre>
<h3 id="heading-6-create-a-log-group">6. Create a Log Group</h3>
<p>In AWS CloudWatch, logs are grouped at a top-level into Log Groups. Each Log Group can belong to a different application or service in AWS. For example, a Log Group for an AWS Lambda function called first_python_function might look like this:</p>
<pre><code><span class="hljs-operator">/</span>aws<span class="hljs-operator">/</span>lambda<span class="hljs-operator">/</span>first_python_function
</code></pre><p>When we construct our new logger, we will need to create a new Log Group that we can log to:</p>
<p><strong>CloudWatchLogger.cs</strong></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> Amazon.CloudWatchLogs;
<span class="hljs-keyword">using</span> Amazon.CloudWatchLogs.Model;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">AWSCloudWatchLoggingWithAWSSDK</span>;

<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">CloudWatchLogger</span>
{
    <span class="hljs-keyword">private</span> IAmazonCloudWatchLogs _client;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">string</span> _logGroup;

    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-title">CloudWatchLogger</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> logGroup</span>)</span>
    {
        <span class="hljs-comment">// If don't have an AWS Profile on your machine and application is hosted outside</span>
        <span class="hljs-comment">// of AWS infrastructure (where IAM roles cannot be assigned to infrastructure),</span>
        <span class="hljs-comment">// rather use:</span>
        <span class="hljs-comment">// _client = new AmazonCloudWatchLogsClient(awsAccessKeyId, awsSecretAccessKey, RegionEndpoint.AFSouth1);</span>
        _client = <span class="hljs-keyword">new</span> AmazonCloudWatchLogsClient();
        _logGroup = logGroup;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">async</span> Task&lt;CloudWatchLogger&gt; <span class="hljs-title">GetLoggerAsync</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> logGroup</span>)</span>
    {
        <span class="hljs-keyword">var</span> logger = <span class="hljs-keyword">new</span> CloudWatchLogger(logGroup);

        <span class="hljs-comment">// Create a log group for our logger</span>
        <span class="hljs-keyword">await</span> logger.CreateLogGroupAsync();

        <span class="hljs-keyword">return</span> logger;
    }

    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">CreateLogGroupAsync</span>(<span class="hljs-params"></span>)</span>
    {
        _ = <span class="hljs-keyword">await</span> _client.CreateLogGroupAsync(<span class="hljs-keyword">new</span> CreateLogGroupRequest()
        {
            LogGroupName = _logGroup
        });
    }
}
</code></pre>
<p>While this might look like it should work, after calling our constructor a second time, you will get the following exception:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1639808414346/AVG26GBk2V.png" alt="A ResourceAlreadyExistsException is thrown when we try to create a log group that already exists" /></p>
<p>As you've probably already guessed, this exception is being thrown because we're trying to create a Log Group that already exists! We need some way of making sure we don't crash the application because the log group already exists. There are a few techniques for doing this. We will take a rather simple and naive approach and update our <code>CreateLogGroupAsync</code> method as follows:</p>
<p><strong>CloudWatchLogger.cs</strong></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> Amazon.CloudWatchLogs;
<span class="hljs-keyword">using</span> Amazon.CloudWatchLogs.Model;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">AWSCloudWatchLoggingWithAWSSDK</span>;

<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">CloudWatchLogger</span>
{
    <span class="hljs-comment">// ...</span>

    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">CreateLogGroupAsync</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-keyword">var</span> existingLogGroups = <span class="hljs-keyword">await</span> _client.DescribeLogGroupsAsync();
        <span class="hljs-keyword">if</span> (existingLogGroups.LogGroups.Any(x =&gt; x.LogGroupName == _logGroup))
            <span class="hljs-keyword">return</span>;

        _ = <span class="hljs-keyword">await</span> _client.CreateLogGroupAsync(<span class="hljs-keyword">new</span> CreateLogGroupRequest()
        {
            LogGroupName = _logGroup
        });
    }
}
</code></pre>
<p>This will now fetch a list of all the Log Groups in AWS and check if our Log Group already exists. If it does, we return before creating a new Log Group.</p>
<p>Let's do a quick test to see what happens when we create a new instance of our logger:</p>
<p><strong>Program.cs</strong></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> AWSCloudWatchLoggingWithAWSSDK;

<span class="hljs-keyword">var</span> logger = <span class="hljs-keyword">await</span> CloudWatchLogger.GetLoggerAsync(<span class="hljs-string">"/dotnet/logging-demo/awssdk"</span>);
</code></pre>
<p><strong>AWS CloudWatch Console</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1639808451122/lzOAQg8fC.png" alt="We should see our new Log Group in the AWS CloudWatch Console" /></p>
<p>You can see that we have a new Log Group created in the AWS CloudWatch Console now!</p>
<h3 id="heading-7-create-a-log-stream">7. Create a Log Stream</h3>
<p>Previously we created a Log Group to contain logs for our application. In AWS CloudWatch, our logs are group again into Log Streams. Ideally, these Log Streams group log events from a single invocation or request in an application. For example, if you had a web application, you would group a single request sent to your web application in a Log Stream.</p>
<p>In our example, we are going to create a Log Stream in the constructor and reuse that Log Stream throughout the lifetime of that instance of the <code>CloudWatchLogger</code> class:</p>
<p><strong>CloudWatchLogger.cs</strong></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> Amazon.CloudWatchLogs;
<span class="hljs-keyword">using</span> Amazon.CloudWatchLogs.Model;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">AWSCloudWatchLoggingWithAWSSDK</span>;

<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">CloudWatchLogger</span>
{
    <span class="hljs-comment">// ...</span>

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">string</span> _logStream;

    <span class="hljs-comment">// ...</span>

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">async</span> Task&lt;CloudWatchLogger&gt; <span class="hljs-title">GetLoggerAsync</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> logGroup</span>)</span>
    {
        <span class="hljs-keyword">var</span> logger = <span class="hljs-keyword">new</span> CloudWatchLogger(logGroup);

        <span class="hljs-comment">// Create a log group for our logger</span>
        <span class="hljs-keyword">await</span> logger.CreateLogGroupAsync();

        <span class="hljs-comment">// Create a log stream</span>
        <span class="hljs-keyword">await</span> logger.CreateLogStreamAsync();

        <span class="hljs-keyword">return</span> logger;
    }

    <span class="hljs-comment">// ...</span>

    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">CreateLogStreamAsync</span>(<span class="hljs-params"></span>)</span>
    {
        _logStream = DateTime.UtcNow.ToString(<span class="hljs-string">"yyyyMMddHHmmssfff"</span>);

        _ = <span class="hljs-keyword">await</span> _client.CreateLogStreamAsync(<span class="hljs-keyword">new</span> CreateLogStreamRequest()
        {
            LogGroupName = _logGroup,
            LogStreamName = _logStream
        });
    }
}
</code></pre>
<p>If we now run our program again and look in AWS CloudWatch, we should see a newly created Log Stream in our Log Group:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1639808481635/QwyXUiovz.png" alt="We should now see our new Log Stream in the AWS CloudWatch Console" /></p>
<p>Awesome!</p>
<h3 id="heading-8-put-log-messages-into-aws-cloudwatch">8. "Put" log messages into AWS CloudWatch</h3>
<p>Now that we've set up a Log Group and Log Stream, we're finally ready to start sending log messages to AWS CloudWatch! The AWS SDK provides a method called <code>PutLogEventsAsync</code> which allows us to upload a batch of log events to AWS CloudWatch. </p>
<p><strong>For simplicity's sake we are going to call this method every time we log a message, however, we can exceed our maximum requests per second very quickly this way. Hence, it is best practice to batch these log events when sending them through to AWS CloudWatch.</strong></p>
<p>Let's create a <code>LogMessageAsync</code> method which will write our log message to AWS CloudWatch when called:</p>
<p><strong>CloudWatchLogger.cs</strong></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> Amazon.CloudWatchLogs;
<span class="hljs-keyword">using</span> Amazon.CloudWatchLogs.Model;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">AWSCloudWatchLoggingWithAWSSDK</span>;

<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">CloudWatchLogger</span>
{
    <span class="hljs-comment">// ...</span>

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">LogMessageAsync</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> message</span>)</span>
    {
        _ = <span class="hljs-keyword">await</span> _client.PutLogEventsAsync(<span class="hljs-keyword">new</span> PutLogEventsRequest()
        {
            LogGroupName = _logGroup,
            LogStreamName = _logStream,
            LogEvents = <span class="hljs-keyword">new</span> List&lt;InputLogEvent&gt;()
            {
                <span class="hljs-keyword">new</span> InputLogEvent()
                {
                    Message = message,
                    Timestamp = DateTime.UtcNow
                }
            }
        });
    }

    <span class="hljs-comment">// ...</span>
}
</code></pre>
<p>Let's run the following program and see what happens:</p>
<p><strong>Program.cs</strong></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> AWSCloudWatchLoggingWithAWSSDK;

<span class="hljs-keyword">var</span> logger = <span class="hljs-keyword">await</span> CloudWatchLogger.GetLoggerAsync(<span class="hljs-string">"/dotnet/logging-demo/awssdk"</span>);

<span class="hljs-keyword">await</span> logger.LogMessageAsync(<span class="hljs-string">"This is my first message!"</span>);
<span class="hljs-keyword">await</span> logger.LogMessageAsync(<span class="hljs-string">"this is another message much like the first!"</span>);
</code></pre>
<p>You will see that we get the following exception when trying to call <code>LogMessageAsync</code> a second time:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1639808510570/iP06enKq7.png" alt="An InvalidSequenceTokenException is thrown the second time we try log a message" /></p>
<p>This is caused by not providing a Sequence Token when putting log events into the Log Stream. The first time we call <code>PutLogEventsAsync</code> on an empty Log Stream, the Sequence Token is not required because the Log Stream is empty. But, once we've written messages to the Log Stream, subsequent calls need to provide a Sequence Token so that they can be written in the correct order.</p>
<p>Fortunately, this isn't too hard to fix in our simple demonstration:</p>
<p><strong>CloudWatchLogger.cs</strong></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> Amazon.CloudWatchLogs;
<span class="hljs-keyword">using</span> Amazon.CloudWatchLogs.Model;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">AWSCloudWatchLoggingWithAWSSDK</span>;

<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">CloudWatchLogger</span>
{
    <span class="hljs-comment">//...</span>

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">string</span> _nextSequenceToken = <span class="hljs-literal">null</span>;

    <span class="hljs-comment">// ...</span>

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">LogMessageAsync</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> message</span>)</span>
    {
        <span class="hljs-keyword">var</span> response = <span class="hljs-keyword">await</span> _client.PutLogEventsAsync(<span class="hljs-keyword">new</span> PutLogEventsRequest()
        {
            LogGroupName = _logGroup,
            LogStreamName = _logStream,
            SequenceToken = _nextSequenceToken,
            LogEvents = <span class="hljs-keyword">new</span> List&lt;InputLogEvent&gt;()
            {
                <span class="hljs-keyword">new</span> InputLogEvent()
                {
                    Message = message,
                    Timestamp = DateTime.UtcNow
                }
            }
        });

        _nextSequenceToken = response.NextSequenceToken;
    }

    <span class="hljs-comment">// ...</span>
}
</code></pre>
<p>We've now created a private field to store the next Sequence Token that should be used the next time we insert log events into the Log Stream. Initially, the private field is set to <code>null</code>, but that's not a problem for our implementation because we know that our first request to log a message to the Log Stream will always be to an empty Log Stream. Thereafter, we get the <code>NextSequenceToken</code> value from the response object and store it in the private field for next time. </p>
<p>And that solves the issue! You should now see our two, beautiful logged messages in AWS CloudWatch:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1639808537356/Vh97wJ4tL.png" alt="Our two, beautiful logged messages in AWS CloudWatch" /></p>
<h2 id="heading-closing">Closing</h2>
<p>That's all for this first post in the <em>Logging .NET to AWS CloudWatch</em> series. The goal of this post was to give you a first principles, hands-on demonstration of how we use the AWS SDK to log to AWS CloudWatch.</p>
<p>It is a very simplified demonstration, but it paves the way for understanding how existing logging libraries implement this functionality such as Serilog or NLog. We will focus on implementing logging to AWS CloudWatch using these libraries in the next few posts in this series.</p>
]]></content:encoded></item></channel></rss>