<?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[Kris on code]]></title><description><![CDATA[This is a blog where I share my journey as a developer—diving deep into the world of .NET, C#, ASP.NET Core, Blazor, and modern software practices.]]></description><link>https://krisoncode.com</link><generator>RSS for Node</generator><lastBuildDate>Fri, 17 Apr 2026 12:51:28 GMT</lastBuildDate><atom:link href="https://krisoncode.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Update Your Configuration and Secret Without Restarting Your App (ASP.NET Core)]]></title><description><![CDATA[In modern cloud-native applications, the ability to update configuration or secret at runtime — without redeploying or restarting — is a huge productivity and operational win. ASP.NET Core has excellent built-in support for this in three common scena...]]></description><link>https://krisoncode.com/update-your-configuration-and-secret-without-restarting-your-app-aspnet-core</link><guid isPermaLink="true">https://krisoncode.com/update-your-configuration-and-secret-without-restarting-your-app-aspnet-core</guid><category><![CDATA[AppConfig]]></category><category><![CDATA[Azure]]></category><category><![CDATA[Azure Key Vault]]></category><category><![CDATA[Aspnetcore]]></category><category><![CDATA[.NET]]></category><dc:creator><![CDATA[Kristiadhy]]></dc:creator><pubDate>Wed, 19 Nov 2025 10:24:09 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1763547733731/a24a7e27-880a-449f-896d-a459407a0cfc.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In modern cloud-native applications, the ability to update configuration or secret at runtime — without redeploying or restarting — is a huge productivity and operational win. ASP.NET Core has excellent built-in support for this in three common scenarios:</p>
<ol>
<li><p><strong>JSON-based configuration files</strong> (e.g., appsettings.json)</p>
</li>
<li><p><strong>Secrets stored in Azure Key Vault</strong></p>
</li>
<li><p><strong>Centralized configuration &amp; feature flags in Azure App Configuration</strong></p>
</li>
</ol>
<p>Let’s look at exactly what works, what doesn’t, and the gotchas you need to know.</p>
<h2 id="heading-1-hot-reloading-json-configuration-files-no-app-restart-needed">1. Hot-Reloading JSON Configuration Files (No App Restart Needed)</h2>
<p>By default, most ASP.NET Core templates already enable hot reload for appsettings.json — you just have to use the right options pattern.</p>
<h3 id="heading-how-it-works-out-of-the-box">✅ How It Works Out of the Box</h3>
<p>When you create a project with:</p>
<p>C#</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> builder = WebApplication.CreateBuilder(args);
</code></pre>
<p>The default host builder automatically registers your JSON files with <strong>reloadOnChange: true</strong>:</p>
<p>C#</p>
<pre><code class="lang-csharp">builder.Configuration
    .AddJsonFile(<span class="hljs-string">"appsettings.json"</span>, optional: <span class="hljs-literal">false</span>, reloadOnChange: <span class="hljs-literal">true</span>)
    .AddJsonFile(<span class="hljs-string">$"appsettings.<span class="hljs-subst">{builder.Environment.EnvironmentName}</span>.json"</span>, optional: <span class="hljs-literal">true</span>, reloadOnChange: <span class="hljs-literal">true</span>);
</code></pre>
<p>This sets up a file system watcher. As soon as the file changes on disk, the IConfigurationRoot is refreshed.</p>
<h3 id="heading-how-to-read-the-latest-values">✅ How to Read the Latest Values</h3>
<p>You have two good options:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Interface</td><td>When It Updates</td><td>Best For</td></tr>
</thead>
<tbody>
<tr>
<td>IOptionsSnapshot&lt;T&gt;</td><td>On the next HTTP request (scoped)</td><td>Web-facing code (controllers, minimal APIs, Razor pages)</td></tr>
<tr>
<td>IOptionsMonitor&lt;T&gt;</td><td>Immediately (singleton + change notifications)</td><td>Background services, hosted services, or any code that needs real-time updates</td></tr>
</tbody>
</table>
</div><p>Example:</p>
<p>C#</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">MyService</span>
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> MySettings _settings;

    <span class="hljs-comment">// Updates immediately when file changes</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">MyService</span>(<span class="hljs-params">IOptionsMonitor&lt;MySettings&gt; settings</span>)</span>
    {
        _settings = settings.CurrentValue;

        <span class="hljs-comment">// Optional: react to future changes</span>
        settings.OnChange(updatedSettings =&gt; {
            _settings = updatedSettings;
            <span class="hljs-comment">// Trigger whatever logic you need</span>
        });
    }
}
</code></pre>
<h3 id="heading-what-does-not-work">❌ What Does NOT Work</h3>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Approach</td><td>Why It Fails</td></tr>
</thead>
<tbody>
<tr>
<td>IOptions&lt;T&gt;</td><td>Values are read once at startup and cached</td></tr>
<tr>
<td>Manually reading IConfiguration once and storing in a singleton</td><td>You’re holding a stale snapshot</td></tr>
<tr>
<td>Hard-coded values or static fields</td><td>Obviously never change</td></tr>
</tbody>
</table>
</div><h3 id="heading-limitations-of-json-hot-reload">Limitations of JSON Hot Reload</h3>
<p>Only JSON files added via AddJsonFile(..., reloadOnChange: true) support this. The following sources are <strong>static</strong> (loaded once at startup):</p>
<ul>
<li><p>Environment variables</p>
</li>
<li><p>Command-line arguments</p>
</li>
<li><p>User secrets (in development)</p>
</li>
<li><p>Most other providers (Azure App Configuration has its own mechanism, etc.)</p>
</li>
</ul>
<h2 id="heading-2-hot-reloading-secrets-from-azure-key-vault-dynamic-refresh">2. Hot-Reloading Secrets from Azure Key Vault (Dynamic Refresh)</h2>
<p>Storing secrets directly in appsettings.json or user secrets is convenient for development, but in production you usually want them in Azure Key Vault. The good news: you can make those secrets refresh automatically too.</p>
<h3 id="heading-how-to-enable-periodic-refresh">✅ How to Enable Periodic Refresh</h3>
<p>C#</p>
<pre><code class="lang-csharp">builder.Configuration.AddAzureKeyVault(
    <span class="hljs-keyword">new</span> Uri(<span class="hljs-string">$"https://<span class="hljs-subst">{builder.Configuration[<span class="hljs-string">"KeyVaultName"</span>]}</span>.vault.azure.net/"</span>),
    <span class="hljs-keyword">new</span> DefaultAzureCredential(),
    <span class="hljs-keyword">new</span> AzureKeyVaultConfigurationOptions
    {
        ReloadInterval = TimeSpan.FromMinutes(<span class="hljs-number">10</span>),   <span class="hljs-comment">// ← critical line</span>
        Manager = <span class="hljs-keyword">new</span> KeyVaultSecretManager()       <span class="hljs-comment">// optional: prefix filtering, etc.</span>
    });
</code></pre>
<p>The ReloadInterval property is what turns one-time loading into periodic polling.</p>
<h3 id="heading-how-the-polling-works">How the Polling Works</h3>
<ul>
<li><p>Every ReloadInterval, the provider queries Key Vault for the current version of each secret it previously loaded.</p>
</li>
<li><p>Azure only transfers the secret value if the version has actually changed.</p>
</li>
<li><p>When a new version is detected → the entire configuration root is refreshed → IOptionsMonitor&lt;T&gt; and IOptionsSnapshot&lt;T&gt; pick up the new values exactly like JSON file changes.</p>
</li>
</ul>
<h3 id="heading-recommended-options-pattern">✅ Recommended Options Pattern.</h3>
<p>Again, use IOptionsMonitor&lt;T&gt; for instant updates (great for background services that read secrets) or IOptionsSnapshot&lt;T&gt; for per-request freshness.</p>
<h3 id="heading-important-operational-considerations">⚠️ Important Operational Considerations</h3>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Consideration</td><td>Recommendation</td></tr>
</thead>
<tbody>
<tr>
<td>API call volume</td><td>Every reload hits Key Vault for metadata of all secrets you loaded</td></tr>
<tr>
<td>Quota impact</td><td>In production, use a longer interval (20–60 minutes)</td></tr>
<tr>
<td>Cost</td><td>Negligible unless you have thousands of secrets and very short intervals</td></tr>
<tr>
<td>Immediate propagation</td><td>Still limited by your chosen ReloadInterval</td></tr>
</tbody>
</table>
</div><h3 id="heading-what-does-not-refresh-automatically">❌ What Does NOT Refresh Automatically</h3>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Approach</td><td>Result</td></tr>
</thead>
<tbody>
<tr>
<td>AddAzureKeyVault without ReloadInterval</td><td>Secrets loaded once at startup only</td></tr>
<tr>
<td>Using IOptions&lt;T&gt;</td><td>Values frozen even if config root reloads</td></tr>
<tr>
<td>Manually calling KeyVaultClient.GetSecretAsync and caching</td><td>You have to implement your own polling/caching</td></tr>
</tbody>
</table>
</div><h2 id="heading-3-hot-reloading-azure-app-configuration-the-most-powerful-option">3. Hot-Reloading Azure App Configuration (The Most Powerful Option)</h2>
<p>Azure App Configuration is the go-to service for centralized config, feature flags, and Key Vault references. It supports <strong>true dynamic refresh</strong> without restarting your app — and it’s smarter than simple polling.</p>
<h3 id="heading-how-to-enable-it">✅ How to Enable It</h3>
<p>C#</p>
<pre><code class="lang-csharp">builder.Configuration.AddAzureAppConfiguration(options =&gt;
{
    options.Connect(connectionString)
           <span class="hljs-comment">// Register keys you want to watch (or use a sentinel pattern)</span>
           .ConfigureRefresh(refresh =&gt;
           {
               <span class="hljs-comment">// Option 1: Watch a single "sentinel" key (recommended)</span>
               refresh.Register(<span class="hljs-string">"Sentinel"</span>, refreshAll: <span class="hljs-literal">true</span>)
                      .SetCacheExpiration(TimeSpan.FromMinutes(<span class="hljs-number">5</span>));

               <span class="hljs-comment">// Option 2: Watch individual keys (less efficient)</span>
               <span class="hljs-comment">// refresh.Register("MyApp:Settings:BackgroundColor", refreshAll: false);</span>
           });

    <span class="hljs-comment">// Optional: trigger refresh on every request (web apps)</span>
    <span class="hljs-comment">// options.UseFeatureFlags();</span>
});
</code></pre>
<p>For <strong>web apps</strong>, add the refresh middleware (triggers on each request):</p>
<p>C#</p>
<pre><code class="lang-csharp">app.UseAzureAppConfiguration();
</code></pre>
<h3 id="heading-how-the-sentinel-pattern-works-best-practice">How the Sentinel Pattern Works (Best Practice)</h3>
<ol>
<li><p>Create a dummy key in App Configuration called Sentinel (value can be a version number or timestamp).</p>
</li>
<li><p>Your app checks this key periodically (based on cache expiration).</p>
</li>
<li><p>When you need to push a new config:</p>
<ul>
<li><p>Update all your real keys first.</p>
</li>
<li><p>Finally update Sentinel → your app detects the change → reloads <strong>everything</strong> exactly once.</p>
</li>
</ul>
</li>
<li><p>New values instantly appear via IOptionsMonitor&lt;T&gt; / IOptionsSnapshot&lt;T&gt;.</p>
</li>
</ol>
<p>This avoids polling every single key and gives you atomic, consistent updates.</p>
<h3 id="heading-same-options-pattern-applies">✅ Same Options Pattern Applies</h3>
<p>Use IOptionsMonitor&lt;T&gt; (immediate) or IOptionsSnapshot&lt;T&gt; (per-request) — exactly like JSON and Key Vault.</p>
<h3 id="heading-important-notes">⚠️ Important Notes</h3>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Consideration</td><td>Recommendation</td></tr>
</thead>
<tbody>
<tr>
<td>Refresh trigger</td><td>Prefer sentinel key + longer cache (5–30 min)</td></tr>
<tr>
<td>Cost &amp; throttling</td><td>Only polls the watched keys (usually just the sentinel)</td></tr>
<tr>
<td>Feature flags</td><td>Automatically refreshed too (with UseFeatureFlags())</td></tr>
<tr>
<td>Key Vault references</td><td>Refresh App Config → automatically pulls latest secret version</td></tr>
</tbody>
</table>
</div><h3 id="heading-what-does-not-refresh">❌ What Does NOT Refresh</h3>
<ul>
<li><p>Not registering any keys for refresh</p>
</li>
<li><p>Forgetting app.UseAzureAppConfiguration() in web apps</p>
</li>
<li><p>Using plain IConfiguration.GetValue&lt;T&gt;() without the options pattern</p>
</li>
</ul>
<h2 id="heading-quick-checklist-can-i-change-this-without-a-restart">Quick Checklist: “Can I Change This Without a Restart?”</h2>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Source</td><td>Hot Reload Possible?</td><td>How?</td></tr>
</thead>
<tbody>
<tr>
<td>appsettings*.json</td><td>Yes (default)</td><td>reloadOnChange: true + IOptionsMonitor/Snapshot</td></tr>
<tr>
<td>Environment variables</td><td>No</td><td>Requires process restart</td></tr>
<tr>
<td>Command-line args</td><td>No</td><td>Requires process restart</td></tr>
<tr>
<td>Azure Key Vault (direct)</td><td>Yes</td><td>ReloadInterval + IOptionsMonitor/Snapshot</td></tr>
<tr>
<td>Azure App Configuration</td><td>Yes (best option)</td><td>Sentinel key + ConfigureRefresh + middleware</td></tr>
<tr>
<td>Database-driven config</td><td>Yes (manual)</td><td>Implement your own polling + IOptionsMonitor</td></tr>
</tbody>
</table>
</div><div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">You can find out more about setting up Azure App Configuration and Azure Key Vault properly by reading this article: <a target="_self" href="https://krisoncode.com/how-to-integrate-azure-app-configuration-in-aspnet-core-for-centralized-settings">Azure App Configuration in </a><a target="_self" href="http://ASP.NET">ASP.NET</a><a target="_self" href="https://krisoncode.com/how-to-integrate-azure-app-configuration-in-aspnet-core-for-centralized-settings"> Core Guide</a></div>
</div>

<h2 id="heading-final-thoughts">Final Thoughts</h2>
<p>Hot-reloading configuration is one of those small features that has an outsized impact on operations and developer happiness.</p>
<ul>
<li><p>Most apps get JSON hot reload for free.</p>
</li>
<li><p>Add one line for Key Vault polling when you need simple secret rotation.</p>
</li>
<li><p>Switch to <strong>Azure App Configuration</strong> with the sentinel pattern when you want centralized config, feature flags, and atomic zero-downtime updates.</p>
</li>
</ul>
<p>Pick the approach that fits your app — and never restart again just to change a setting or rotate a secret! 🚀</p>
]]></content:encoded></item><item><title><![CDATA[4 Ways to Send Data in an API Request]]></title><description><![CDATA[APIs are fundamentally about exchanging data between systems. The four main options are the request body, query parameters, headers, and path parameters (often just called route parameters). Deciding where to place that data in a request is important...]]></description><link>https://krisoncode.com/4-ways-to-send-data-in-an-api-request</link><guid isPermaLink="true">https://krisoncode.com/4-ways-to-send-data-in-an-api-request</guid><category><![CDATA[API basics ]]></category><category><![CDATA[api]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[REST API]]></category><dc:creator><![CDATA[Kristiadhy]]></dc:creator><pubDate>Mon, 20 Oct 2025 01:00:57 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1760876001614/14f45ad5-b968-43d0-9202-cd6e6aac7772.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>APIs are fundamentally about exchanging data between systems. The four main options are the <strong><em>request body, query parameters, headers, and path parameters</em></strong> (often just called route parameters). Deciding where to place that data in a request is important for keeping things straightforward and functional. Each has its own role, and choosing appropriately makes your API easier to understand and maintain. Misplace them, and it might cause issues for anyone working with it later.</p>
<h2 id="heading-1-request-body">1. Request Body</h2>
<p>The request body is where you typically put the bulk of the data you're sending to the server. It's common in methods like POST, PUT, and PATCH, which are used for creating or updating resources.</p>
<p><strong>Example:</strong></p>
<p>text</p>
<pre><code class="lang-csharp">POST /api/users
Content-Type: application/json

{
  <span class="hljs-string">"name"</span>: <span class="hljs-string">"Kris"</span>,
  <span class="hljs-string">"email"</span>: <span class="hljs-string">"kris@example.com"</span>
}
</code></pre>
<p><strong>Common use:</strong></p>
<ul>
<li>Sending structured or complex data, such as JSON objects, arrays, or files in create or update operations.</li>
</ul>
<p><strong>When to use:</strong></p>
<ul>
<li><p>When you need to transmit detailed payloads that don't fit well in the URL.</p>
</li>
<li><p>It keeps sensitive information out of the URL, which isn't visible in logs or browser history.</p>
</li>
<li><p>Servers don't cache or log bodies by default, adding a layer of security.</p>
</li>
</ul>
<p><strong>When to avoid it:</strong></p>
<ul>
<li>Don't use it with GET requests, as those are for retrieving data, not sending it. Some servers might even reject bodies in GETs.</li>
</ul>
<h2 id="heading-2-query-parameters">2. Query Parameters</h2>
<p>Query parameters go in the URL after a question mark (?). They're straightforward for adding extra details like filters or pagination.</p>
<p><strong>Example:</strong></p>
<p>text</p>
<pre><code class="lang-csharp">GET /api/users?role=admin&amp;page=<span class="hljs-number">2</span>
</code></pre>
<p><strong>Common use:</strong></p>
<ul>
<li>Applying filters, handling pagination, or passing optional flags in read operations.</li>
</ul>
<p><strong>When to use:</strong></p>
<ul>
<li><p>They're easy to implement, test, and modify—just tweak the URL.</p>
</li>
<li><p>Great for optional values or small bits of information that refine a request.</p>
</li>
</ul>
<p><strong>When to avoid it:</strong></p>
<ul>
<li><p>Skip them for sensitive data like passwords or API keys, since URLs can be logged or shared.</p>
</li>
<li><p>Avoid them for large or nested data; URLs have length limits (around 2,000 characters in practice), and they can quickly become unreadable.</p>
</li>
</ul>
<h2 id="heading-3-http-headers">3. HTTP Headers</h2>
<p>Headers provide metadata about the request itself, rather than the core data. They're commonly used for authentication, specifying formats, or other instructions.</p>
<p><strong>Example:</strong></p>
<p>text</p>
<pre><code class="lang-csharp">GET /api/profile
Authorization: Bearer eyJhbGciOiJI...
Accept-Language: en-US
</code></pre>
<p><strong>Common use:</strong></p>
<ul>
<li>Handling authentication, content negotiation, or localization settings.</li>
</ul>
<p><strong>When to use:</strong></p>
<ul>
<li><p>They separate control information from the main payload, keeping things organized.</p>
</li>
<li><p>Essential for things like auth tokens, content types, or client preferences.</p>
</li>
</ul>
<p><strong>When to avoid it:</strong></p>
<ul>
<li><p>Don't stuff application-specific data into headers; that's not their purpose and can complicate things.</p>
</li>
<li><p>Stick to standard headers when possible—custom ones should only be added if they solve a specific problem.</p>
</li>
</ul>
<h2 id="heading-4-path-parameters">4. Path Parameters</h2>
<p>Path parameters are embedded right in the URL path, helping identify specific resources in a clean way. They align well with RESTful API designs.</p>
<p><strong>Example:</strong></p>
<p>text</p>
<pre><code class="lang-csharp">GET /api/users/<span class="hljs-number">42</span>
</code></pre>
<p><strong>Common use:</strong></p>
<ul>
<li>Specifying unique identifiers for resources in RESTful endpoints.</li>
</ul>
<p><strong>When to use:</strong></p>
<ul>
<li><p>It makes the endpoint clear and human-readable, showing exactly what resource is being targeted.</p>
</li>
<li><p>Perfect for required identifiers, like user IDs or product codes.</p>
</li>
</ul>
<p><strong>When to avoid it:</strong></p>
<ul>
<li><p>Not for optional filters or search criteria—use query parameters for those.</p>
</li>
<li><p>Keep them simple; too many can make routes hard to manage.</p>
</li>
</ul>
<h2 id="heading-choosing-the-right-approach">Choosing the Right Approach</h2>
<p>Here's a quick reference table to help decide:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Location</td><td>Common Use</td><td>Example</td></tr>
</thead>
<tbody>
<tr>
<td>Body</td><td>Main payload for creates/updates</td><td>POST /api/users with JSON data</td></tr>
<tr>
<td>Query Params</td><td>Filters, pagination, options</td><td>/api/users?active=true</td></tr>
<tr>
<td>Headers</td><td>Auth, metadata, preferences</td><td>Authorization: Bearer ...</td></tr>
<tr>
<td>Path Params</td><td>Resource identifiers</td><td>/api/users/123</td></tr>
</tbody>
</table>
</div><p>If you're unsure, consider the data's purpose:</p>
<ul>
<li><p>Does it specify the exact resource? → Path parameter.</p>
</li>
<li><p>Is it an optional refinement? → Query parameter.</p>
</li>
<li><p>Is it the actual content being sent? → Body.</p>
</li>
<li><p>Does it provide instructions or context? → Header.</p>
</li>
</ul>
<h2 id="heading-final-notes">Final Notes</h2>
<p>Well-designed APIs are straightforward and consistent, so developers (including future you) don't have to second-guess where things go. Sticking to these conventions not only makes your code cleaner but also simplifies documentation and integration with clients. If you're building or using an API, start with these basics and adjust based on your specific needs.</p>
]]></content:encoded></item><item><title><![CDATA[Plan Before You Code: Build Better with This Habit]]></title><description><![CDATA[Introduction
In my early days as a software engineer, I viewed coding as a superpower—a tool to transform ideas into reality with speed and precision. My enthusiasm often led me to dive headfirst into writing code, believing that more lines equaled b...]]></description><link>https://krisoncode.com/plan-before-you-code-build-better-with-this-habit</link><guid isPermaLink="true">https://krisoncode.com/plan-before-you-code-build-better-with-this-habit</guid><category><![CDATA[software development]]></category><category><![CDATA[Software Engineering]]></category><category><![CDATA[planning]]></category><dc:creator><![CDATA[Kristiadhy]]></dc:creator><pubDate>Thu, 09 Oct 2025 00:09:21 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1759968081728/6309a533-74af-4920-9a4b-235f46247ee1.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>In my early days as a software engineer, I viewed coding as a superpower—a tool to transform ideas into reality with speed and precision. My enthusiasm often led me to dive headfirst into writing code, believing that more lines equaled better solutions. However, I quickly learned that this approach was flawed. Hours of coding sometimes resulted in minimal impact, leaving me frustrated and inefficient. This experience taught me a valuable lesson: understanding the problem and planning thoroughly before coding is the key to delivering impactful solutions.</p>
<h2 id="heading-the-analogy-of-building-a-house">The Analogy of Building a House</h2>
<p>Software development is much like constructing a house. You wouldn’t start laying bricks without a blueprint, as it risks wasting time, money, and energy on a structure that may not meet your needs. A blueprint provides a clear vision of the final product, allowing adjustments before construction begins. Similarly, in software engineering, a well-defined plan ensures that the solution aligns with the problem, saving resources and maximizing efficiency.</p>
<h2 id="heading-the-role-of-a-software-engineer">The Role of a Software Engineer</h2>
<p>Our role as software engineers extends beyond writing code. We are problem-solvers, leveraging technology to address challenges effectively. Coding is merely the final step in a process that begins with understanding the problem and designing a solution. Learning about system analysis transformed my approach, helping me become a more effective developer. By prioritizing planning, I could deliver solutions that were both efficient and impactful.</p>
<h2 id="heading-a-structured-approach-to-software-development">A Structured Approach to Software Development</h2>
<p>To optimize my workflow, I follow these steps before writing a single line of code:</p>
<ol>
<li><p><strong>Map the Workflow</strong>: Create a detailed flowchart for each feature to visualize the process and ensure clarity.</p>
</li>
<li><p><strong>Validate with Stakeholders</strong>: Confirm the approach with clients or product managers to align on the problem and proposed solution.</p>
</li>
<li><p><strong>Assess and Mitigate Risks</strong>: Identify potential risks in the approach, choosing the path with minimal risk or ensuring risks are manageable.</p>
</li>
<li><p><strong>Document Everything</strong>: Maintain comprehensive, up-to-date documentation of the process to track decisions and progress.</p>
</li>
</ol>
<p>This methodical approach has streamlined my coding process, reduced wasted effort, and consistently delivered solutions that meet client needs.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Effective software development begins with understanding, not coding. By treating planning as a blueprint for success, we can save time, reduce costs, and build solutions that truly address the problem at hand. Adopting a structured approach—mapping workflows, validating with stakeholders, mitigating risks, and documenting thoroughly—empowers developers to code with purpose and efficiency. Before you build, take the time to plan. Your future self, your team, and your clients will thank you.</p>
]]></content:encoded></item><item><title><![CDATA[Implementing the Open-Closed Principle with Strategy and Factory Patterns]]></title><description><![CDATA[When building software, you want your code to be flexible and easy to extend without disrupting the existing logic. The Open-Closed Principle (OCP)—part of the SOLID principles—helps with exactly that. It says your code should be “open for extension ...]]></description><link>https://krisoncode.com/implementing-the-open-closed-principle-with-strategy-and-factory-patterns</link><guid isPermaLink="true">https://krisoncode.com/implementing-the-open-closed-principle-with-strategy-and-factory-patterns</guid><category><![CDATA[SOLID principles]]></category><category><![CDATA[Open Closed Principle]]></category><category><![CDATA[StrategyPattern]]></category><category><![CDATA[Factory Design Pattern]]></category><dc:creator><![CDATA[Kristiadhy]]></dc:creator><pubDate>Tue, 23 Sep 2025 14:06:36 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1758635170709/255783af-3717-4a0c-b23c-f2f7b4cc24fc.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When building software, you want your code to be flexible and easy to extend without disrupting the existing logic. The <strong>Open-Closed Principle (OCP)</strong>—part of the SOLID principles—helps with exactly that. It says your code should be “<em>open for extension</em> but <em>closed for modification”</em>. Sounds great, but how do you actually do it? One clean way is to combine the <strong>Strategy Pattern</strong> and the <strong>Factory Pattern</strong>. Let’s walk through an example in C# to show how these patterns team up to make your code OCP-compliant, using a discount calculation system as our playground.</p>
<h2 id="heading-the-problem-rigid-discount-logic">The Problem: Rigid Discount Logic</h2>
<p>Imagine you’re building an e-commerce system where customers get discounts based on their membership tier (Silver, Gold, Platinum). Initially, you might be tempted to write a big <code>if-else</code> block to handle different discount calculations:</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">decimal</span> <span class="hljs-title">CalculateDiscount</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> membershipType, <span class="hljs-keyword">decimal</span> amount</span>)</span>
{
    <span class="hljs-keyword">if</span> (membershipType == <span class="hljs-string">"Silver"</span>)
        <span class="hljs-keyword">return</span> amount * <span class="hljs-number">0.05</span>m;
    <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (membershipType == <span class="hljs-string">"Gold"</span>)
        <span class="hljs-keyword">return</span> amount * <span class="hljs-number">0.10</span>m;
    <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (membershipType == <span class="hljs-string">"Platinum"</span>)
        <span class="hljs-keyword">return</span> amount * <span class="hljs-number">0.15</span>m;
    <span class="hljs-keyword">else</span>
        <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
}
</code></pre>
<p>This works for a small system, but it’s a maintenance nightmare. Adding a new membership tier means cracking open the code and adding another <code>else if</code>. That’s exactly what OCP tells us to avoid—modifying existing code for new functionality. Plus, it’s hard to test and scale. Enter the Strategy and Factory patterns.</p>
<h2 id="heading-step-1-define-the-strategy-with-an-interface">Step 1: Define the Strategy with an Interface</h2>
<p>The Strategy Pattern lets us define a family of algorithms (in this case, discount calculations), encapsulate each one, and make them interchangeable. We start by creating an interface that all discount policies will follow:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">internal</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">IDiscountPolicy</span>
{
    <span class="hljs-function"><span class="hljs-keyword">decimal</span> <span class="hljs-title">CalculateDiscount</span>(<span class="hljs-params"><span class="hljs-keyword">decimal</span> amount</span>)</span>;
}
</code></pre>
<p>This interface is the contract. Any discount policy we create must implement <code>CalculateDiscount</code> and return a decimal. This keeps things clean and ensures all policies are interchangeable.</p>
<h2 id="heading-step-2-implement-concrete-strategies">Step 2: Implement Concrete Strategies</h2>
<p>Now, let’s create the actual discount policies for each membership tier. Each policy implements the <code>IDiscountPolicy</code> interface and defines its own discount logic:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">internal</span> <span class="hljs-keyword">class</span> <span class="hljs-title">DiscountSilverPolicy</span> : <span class="hljs-title">IDiscountPolicy</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">decimal</span> <span class="hljs-title">CalculateDiscount</span>(<span class="hljs-params"><span class="hljs-keyword">decimal</span> amount</span>)</span>
    {
        <span class="hljs-keyword">return</span> amount * <span class="hljs-number">0.05</span>m;
    }
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">internal</span> <span class="hljs-keyword">class</span> <span class="hljs-title">DiscountGoldPolicy</span> : <span class="hljs-title">IDiscountPolicy</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">decimal</span> <span class="hljs-title">CalculateDiscount</span>(<span class="hljs-params"><span class="hljs-keyword">decimal</span> amount</span>)</span>
    {
        <span class="hljs-keyword">return</span> amount * <span class="hljs-number">0.10</span>m;
    }
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">internal</span> <span class="hljs-keyword">class</span> <span class="hljs-title">DiscountPlatinumPolicy</span> : <span class="hljs-title">IDiscountPolicy</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">decimal</span> <span class="hljs-title">CalculateDiscount</span>(<span class="hljs-params"><span class="hljs-keyword">decimal</span> amount</span>)</span>
    {
        <span class="hljs-keyword">return</span> amount * <span class="hljs-number">0.15</span>m;
    }
}
</code></pre>
<p>Each class is simple and focused, handling one specific discount calculation. If we need a new tier, like “Diamond,” we just create a new class implementing <code>IDiscountPolicy</code>—no need to touch the existing ones. This is the “open for extension” part of OCP in action.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">To keep things simple, I used a straightforward example. In the code, I hardcoded the discount value. You can optimize this in your real-world scenario.</div>
</div>

<h2 id="heading-step-3-use-a-factory-to-create-strategies">Step 3: Use a Factory to Create Strategies</h2>
<p>So, how do we decide which policy to use at runtime? This is where the Factory Pattern comes in. Instead of scattering logic to pick the right policy across your codebase, a factory centralizes that decision. Here’s how we can implement it:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">internal</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> <span class="hljs-title">DiscountPolicyFactory</span>
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">readonly</span> Dictionary&lt;DiscountType, IDiscountPolicy&gt; _discountPolicies = <span class="hljs-keyword">new</span>()
    {
        { DiscountType.Silver, <span class="hljs-keyword">new</span> DiscountSilverPolicy() },
        { DiscountType.Gold, <span class="hljs-keyword">new</span> DiscountGoldPolicy() },
        { DiscountType.Platinum, <span class="hljs-keyword">new</span> DiscountPlatinumPolicy() }
    };

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> IDiscountPolicy <span class="hljs-title">GetDiscountPolicy</span>(<span class="hljs-params">DiscountType discountType</span>)</span> =&gt;
        _discountPolicies.TryGetValue(discountType, <span class="hljs-keyword">out</span> <span class="hljs-keyword">var</span> policy)
            ? policy
            : <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentException(<span class="hljs-string">"Invalid discount type"</span>);
}
</code></pre>
<p>We’re using an enum <code>DiscountType</code> to represent the membership tiers (Silver, Gold, Platinum). The factory maintains a dictionary mapping each <code>DiscountType</code> to its corresponding policy. When you call <code>GetDiscountPolicy</code>, it returns the right <code>IDiscountPolicy</code> implementation or throws an exception if the type is invalid.</p>
<h2 id="heading-step-4-putting-it-all-together">Step 4: Putting It All Together</h2>
<p>Here’s how you’d use this setup in your application:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> discountType = DiscountType.Gold;
<span class="hljs-keyword">decimal</span> validAmount = <span class="hljs-number">1000</span>m;

<span class="hljs-comment">// Get the right discount strategy from the factory</span>
<span class="hljs-keyword">var</span> discountPolicy = DiscountPolicyFactory.GetDiscountPolicy(discountType);

<span class="hljs-comment">// Apply discount directly</span>
<span class="hljs-keyword">decimal</span> discount = discountPolicy.CalculateDiscount(validAmount);
<span class="hljs-keyword">decimal</span> finalAmount = validAmount - discount;

Console.WriteLine(<span class="hljs-string">$"Final amount after <span class="hljs-subst">{discountType}</span> discount: <span class="hljs-subst">{finalAmount}</span>"</span>);
</code></pre>
<p>Or, you can also create the <code>DiscountCalculator</code> class to encapsulate this logic:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">internal</span> <span class="hljs-keyword">class</span> <span class="hljs-title">DiscountCalculator</span>
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IDiscountPolicy _discountPolicy;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">DiscountCalculator</span>(<span class="hljs-params">IDiscountPolicy discountPolicy</span>)</span>
    {
        _discountPolicy = discountPolicy;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">decimal</span> <span class="hljs-title">CalculateFinalAmount</span>(<span class="hljs-params"><span class="hljs-keyword">decimal</span> amount</span>)</span>
    {
        <span class="hljs-keyword">return</span> amount - _discountPolicy.CalculateDiscount(amount);
    }
}
</code></pre>
<p>And the implementation will be like this:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> discountType = DiscountType.Gold;
<span class="hljs-keyword">decimal</span> validAmount = <span class="hljs-number">1000</span>m;

<span class="hljs-comment">// Get the right discount strategy from the factory</span>
IDiscountPolicy discountPolicy = DiscountPolicyFactory.GetDiscountPolicy(discountType);

<span class="hljs-comment">// Pass it into the calculator</span>
<span class="hljs-keyword">var</span> discountCalculator = <span class="hljs-keyword">new</span> DiscountCalculator(discountPolicy);

<span class="hljs-comment">// Now, the calculator takes care of the final amount logic</span>
Console.WriteLine(<span class="hljs-string">$"Final amount after <span class="hljs-subst">{discountType}</span> discount:
<span class="hljs-subst">{discountCalculator.CalculateFinalAmount(validAmount)}</span>"</span>);
</code></pre>
<p>The beauty here is that the client code doesn’t need to know how discounts are calculated, or which policy is being used. It just asks the factory for a policy and calls <code>CalculateDiscount</code>. If you add a new discount tier, you only need to:</p>
<ol>
<li><p>Create a new policy class implementing <code>IDiscountPolicy</code>.</p>
</li>
<li><p>Update the factory’s dictionary with the new policy.</p>
</li>
</ol>
<p>No existing code needs to change, satisfying OCP’s “closed for modification” rule.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">You can check the full implementation in this repository: <a target="_self" href="https://github.com/kristiadhy/SolidPractical">kristiadhy/SolidPractical</a></div>
</div>

<h2 id="heading-why-this-works">Why This Works</h2>
<ul>
<li><p><strong>Strategy Pattern</strong>: Encapsulates discount logic into separate classes, making them easy to swap or extend.</p>
</li>
<li><p><strong>Factory Pattern</strong>: Centralizes the creation of strategies, keeping the client code clean and decoupled.</p>
</li>
<li><p><strong>OCP Compliance</strong>: Adding a new discount tier doesn’t require modifying existing classes—just extend with a new policy and update the factory.</p>
</li>
</ul>
<p>By combining Strategy and Factory patterns, you’ve got a clean, extensible system that’s easy to maintain and scales like a charm. Give it a try in your next project, and you’ll see how much easier it is to add new features without breaking a sweat.</p>
]]></content:encoded></item><item><title><![CDATA[Understanding Deferred Execution in LINQ with Entity Framework Core]]></title><description><![CDATA[When working with LINQ in C#, especially with Entity Framework Core (EF Core), deferred execution is a key concept that can make your database queries more flexible and efficient. However, misunderstanding it can lead to performance issues or unexpec...]]></description><link>https://krisoncode.com/understanding-deferred-execution-in-linq-with-entity-framework-core</link><guid isPermaLink="true">https://krisoncode.com/understanding-deferred-execution-in-linq-with-entity-framework-core</guid><category><![CDATA[linq]]></category><category><![CDATA[efcore]]></category><category><![CDATA[.NET]]></category><dc:creator><![CDATA[Kristiadhy]]></dc:creator><pubDate>Fri, 12 Sep 2025 06:18:54 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1757657188893/2d90d3c3-e989-40d5-9e6a-3890bef32ce4.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When working with LINQ in C#, especially with Entity Framework Core (EF Core), <em>deferred execution</em> is a key concept that can make your database queries more flexible and efficient. However, misunderstanding it can lead to performance issues or unexpected behavior. In this post, we’ll explore what deferred execution is, how it works with EF Core, when queries are materialized, and how to optimize common scenarios. We’ll use practical examples to illustrate the benefits and pitfalls, ensuring you can leverage deferred execution effectively.</p>
<h2 id="heading-what-is-deferred-execution">What Is Deferred Execution?</h2>
<p>Deferred execution means a LINQ query doesn’t execute when you define it—it’s only executed when you request the results. With EF Core, queries are built using <code>IQueryable&lt;T&gt;</code>, which creates an expression tree that EF Core translates into SQL when the query is materialized. This allows you to build complex queries incrementally without hitting the database until necessary.</p>
<p>Key benefits:</p>
<ul>
<li><p><strong>Fewer database hits</strong>: Chain multiple LINQ operations (e.g., <code>Where</code>, <code>OrderBy</code>, <code>Take</code>) into a single SQL query.</p>
</li>
<li><p><strong>Flexibility</strong>: Modify the query before execution without redundant database calls.</p>
</li>
<li><p><strong>Performance</strong>: Push filtering, sorting, and projections to the database, avoiding unnecessary data transfer.</p>
</li>
</ul>
<p>However, you need to know <em>when</em> a query materializes to avoid pitfalls like pulling too much data into memory.</p>
<h2 id="heading-deferred-execution-in-action">Deferred Execution in Action</h2>
<p>Let’s explore deferred execution with a practical example, querying a <code>Users</code> table in EF Core. We’ll filter users over 18, find the first matching user, and count the total matches.</p>
<h3 id="heading-deferred-execution-example">Deferred Execution Example</h3>
<p>Here’s how deferred execution works with <code>IQueryable&lt;T&gt;</code>:</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Define the query (not executed yet)</span>
<span class="hljs-keyword">var</span> query = dbContext.Users.Where(u =&gt; u.Age &gt; <span class="hljs-number">18</span>);

<span class="hljs-comment">// Deferred execution: each operation triggers a separate SQL query</span>
<span class="hljs-keyword">var</span> firstUser = query.First(); <span class="hljs-comment">// SQL: SELECT TOP(1) * FROM Users WHERE Age &gt; 18</span>
<span class="hljs-keyword">var</span> count = query.Count();     <span class="hljs-comment">// SQL: SELECT COUNT(*) FROM Users WHERE Age &gt; 18</span>
</code></pre>
<p><strong>What’s happening?</strong></p>
<ul>
<li><p>The <code>query</code> variable is an <code>IQueryable&lt;T&gt;</code> representing the LINQ expression <code>Where(u =&gt; u.Age &gt; 18)</code>. It doesn’t hit the database when defined.</p>
</li>
<li><p>When <code>First()</code> is called, EF Core translates the query into <code>SELECT TOP(1) * FROM Users WHERE Age &gt; 18</code> and executes it.</p>
</li>
<li><p>When <code>Count()</code> is called, EF Core generates a separate query: <code>SELECT COUNT(*) FROM Users WHERE Age &gt; 18</code>.</p>
</li>
<li><p><strong>Key point</strong>: Each materialization (<code>First()</code>, <code>Count()</code>) triggers a distinct database call, fetching only the specific data needed.</p>
</li>
</ul>
<h3 id="heading-what-triggers-materialization">What Triggers Materialization?</h3>
<p>A query remains deferred until you <em>materialize</em> it, meaning you request the actual data from the database. Here are common scenarios that trigger materialization with <code>IQueryable&lt;T&gt;</code> in EF Core:</p>
<ul>
<li><p><strong>Iteration</strong>: Looping over the query (e.g., <code>foreach (var user in query)</code>).</p>
</li>
<li><p><strong>Aggregation methods</strong>: Calling <code>Count()</code>, <code>Sum()</code>, <code>Average()</code>, <code>Min()</code>, <code>Max()</code>, etc.</p>
</li>
<li><p><strong>Single result methods</strong>: Calling <code>First()</code>, <code>FirstOrDefault()</code>, <code>Single()</code>, <code>SingleOrDefault()</code>, <code>Last()</code>, or <code>LastOrDefault()</code>.</p>
</li>
<li><p><strong>Materialization methods</strong>: Calling <code>ToList()</code>, <code>ToArray()</code>, <code>ToDictionary()</code>, or <code>ToHashSet()</code>.</p>
</li>
<li><p><strong>Conversion to IEnumerable</strong>: Calling <code>AsEnumerable()</code>, which forces subsequent operations to execute in memory.</p>
</li>
</ul>
<p><strong>Example</strong>:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> query = dbContext.Users.Where(u =&gt; u.Age &gt; <span class="hljs-number">18</span>);
<span class="hljs-comment">// Still deferred: no database hit</span>
query = query.OrderBy(u =&gt; u.LastName);
<span class="hljs-comment">// Still deferred: no database hit</span>
<span class="hljs-keyword">var</span> results = query.ToList(); <span class="hljs-comment">// Materializes: executes SQL and loads data into memory</span>
<span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> user <span class="hljs-keyword">in</span> query) { ... } <span class="hljs-comment">// Materializes: executes SQL and iterates results</span>
<span class="hljs-keyword">var</span> count = query.Count(); <span class="hljs-comment">// Materializes: executes SQL to compute count</span>
</code></pre>
<p><strong>Note</strong>: Each materialization triggers a new database query, so avoid multiple materializations of the same query to prevent redundant database hits.</p>
<h3 id="heading-immediate-execution-contrast">Immediate Execution Contrast</h3>
<p>Forcing immediate execution materializes the query early, loading data into memory:</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Load all matching users into memory immediately</span>
<span class="hljs-keyword">var</span> users = dbContext.Users
    .Where(u =&gt; u.Age &gt; <span class="hljs-number">18</span>)
    .ToList();

<span class="hljs-comment">// Operations happen in memory</span>
<span class="hljs-keyword">var</span> firstUser = users.FirstOrDefault(); <span class="hljs-comment">// CLR processes the list</span>
<span class="hljs-keyword">var</span> count = users.Count;                <span class="hljs-comment">// CLR counts the list</span>
</code></pre>
<p><strong>What’s happening?</strong></p>
<ul>
<li><p><code>ToList()</code> triggers immediate execution, running <code>SELECT * FROM Users WHERE Age &gt; 18</code> and loading <em>all matching rows</em> into memory.</p>
</li>
<li><p><code>FirstOrDefault()</code> and <code>Count</code> operate on the in-memory <code>List&lt;User&gt;</code>, not the database.</p>
</li>
<li><p><strong>Downside</strong>: If the <code>Users</code> table has 1 million rows over 18, all are pulled into memory, even though you only need one user and a count. This is inefficient for large datasets.</p>
</li>
</ul>
<h3 id="heading-optimizing-multiple-operations">Optimizing Multiple Operations</h3>
<p>In the deferred execution example, calling <code>First()</code> and <code>Count()</code> separately results in two database queries. To optimize, you can combine these into a single query using grouping:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> result = <span class="hljs-keyword">await</span> dbContext.Users
    .Where(u =&gt; u.Age &gt; <span class="hljs-number">18</span>)
    .GroupBy(u =&gt; <span class="hljs-number">1</span>) <span class="hljs-comment">// Dummy key to group all rows</span>
    .Select(g =&gt; <span class="hljs-keyword">new</span>
    {
        FirstUser = g.OrderBy(u =&gt; u.Id).FirstOrDefault(),
        Count = g.Count()
    })
    .FirstOrDefaultAsync();
</code></pre>
<p><strong>What’s happening?</strong></p>
<ul>
<li><p>The <code>GroupBy(u =&gt; 1)</code> groups all rows into a single group, allowing <code>FirstOrDefault</code> and <code>Count</code> to be computed together.</p>
</li>
<li><p>EF Core translates this into a single SQL query (simplified):</p>
</li>
</ul>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> TOP(<span class="hljs-number">1</span>) (
    <span class="hljs-keyword">SELECT</span> TOP(<span class="hljs-number">1</span>) * <span class="hljs-keyword">FROM</span> <span class="hljs-keyword">Users</span> <span class="hljs-keyword">WHERE</span> Age &gt; <span class="hljs-number">18</span> <span class="hljs-keyword">ORDER</span> <span class="hljs-keyword">BY</span> <span class="hljs-keyword">Id</span>
) <span class="hljs-keyword">AS</span> FirstUser,
<span class="hljs-keyword">COUNT</span>(*) <span class="hljs-keyword">AS</span> <span class="hljs-keyword">Count</span>
<span class="hljs-keyword">FROM</span> <span class="hljs-keyword">Users</span> <span class="hljs-keyword">WHERE</span> Age &gt; <span class="hljs-number">18</span>;
</code></pre>
<ul>
<li><p><strong>Benefit</strong>: One database round-trip instead of two, reducing latency and server load.</p>
</li>
<li><p><strong>Note</strong>: Using <code>FirstOrDefaultAsync()</code> ensures async execution, a best practice for database operations in EF Core.</p>
</li>
</ul>
<h2 id="heading-real-world-analogy">Real-World Analogy</h2>
<p>Think of deferred execution like planning a grocery shopping trip:</p>
<ul>
<li><p><strong>Deferred execution</strong>: You write a shopping list (<code>IQueryable&lt;T&gt;</code> query), adding items as you think of them (e.g., “milk,” “eggs,” “only organic”). You don’t go to the store until you’re ready, and you get exactly what’s on the final list in one trip.</p>
</li>
<li><p><strong>Immediate execution</strong>: You go to the store, buy everything in the dairy aisle (<code>ToList()</code>), bring it home, and then decide you only needed one carton of milk. Wasteful!</p>
</li>
</ul>
<p>Deferred execution lets you refine your “shopping list” before hitting the database, ensuring you only fetch what you need.</p>
<h2 id="heading-common-pitfalls-to-avoid">Common Pitfalls to Avoid</h2>
<ol>
<li><p><strong>Premature Materialization</strong>:</p>
<ul>
<li><p>Calling <code>ToList()</code> or <code>AsEnumerable()</code> too early forces all data into memory, losing the benefits of deferred execution.</p>
</li>
<li><p>Example: <code>dbContext.Users.ToList().Where(u =&gt; u.Age &gt; 18)</code> pulls all users into memory before filtering, which is inefficient.</p>
</li>
</ul>
</li>
<li><p><strong>Multiple Queries by Accident</strong>:</p>
<ul>
<li><p>Materializing an <code>IQueryable&lt;T&gt;</code> multiple times (e.g., in a loop) triggers multiple database hits.</p>
</li>
<li><p>Example:</p>
</li>
</ul>
</li>
</ol>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> query = dbContext.Users.Where(u =&gt; u.Age &gt; <span class="hljs-number">18</span>);
<span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> user <span class="hljs-keyword">in</span> query) { ... } <span class="hljs-comment">// SQL executed</span>
<span class="hljs-keyword">var</span> count = query.Count();         <span class="hljs-comment">// SQL executed again</span>
</code></pre>
<ul>
<li><strong>Fix</strong>: Materialize once (<code>var users = query.ToList();</code>) or use the optimized grouping approach above.</li>
</ul>
<ol start="3">
<li><p><strong>Forgetting Async</strong>:</p>
<ul>
<li>Use async methods like <code>ToListAsync()</code>, <code>FirstOrDefaultAsync()</code>, or <code>CountAsync()</code> to avoid blocking threads in web apps or APIs.</li>
</ul>
</li>
</ol>
<h2 id="heading-when-to-leverage-deferred-execution">When to Leverage Deferred Execution</h2>
<ul>
<li><p><strong>Building complex queries</strong>: Chain multiple <code>Where</code>, <code>OrderBy</code>, or <code>Select</code> operations to create a single, optimized SQL query.</p>
</li>
<li><p><strong>Dynamic queries</strong>: Adjust filters based on conditions (e.g., user input) before executing.</p>
</li>
<li><p><strong>Aggregates and single records</strong>: Combine operations like <code>First()</code> and <code>Count()</code> into one query for efficiency.</p>
</li>
</ul>
<p><strong>Example</strong> (dynamic query):</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> query = dbContext.Users.AsQueryable();
<span class="hljs-keyword">if</span> (onlyActive)
    query = query.Where(u =&gt; u.IsActive);
<span class="hljs-keyword">if</span> (minAge.HasValue)
    query = query.Where(u =&gt; u.Age &gt;= minAge.Value);
<span class="hljs-keyword">var</span> results = <span class="hljs-keyword">await</span> query.ToListAsync();
</code></pre>
<p>Here, deferred execution lets you build the query dynamically without hitting the database until <code>ToListAsync()</code>.</p>
<h2 id="heading-conclusions">Conclusions</h2>
<ul>
<li><p><strong>Deferred execution</strong> delays query execution until materialization (e.g., <code>ToList()</code>, <code>First()</code>, <code>Count()</code>, or iteration), allowing flexible query composition.</p>
</li>
<li><p><strong>Materialization triggers</strong>: Iteration, aggregation (<code>Count</code>, <code>Sum</code>), single result methods (<code>First</code>, <code>Single</code>), or conversion to in-memory collections (<code>ToList</code>, <code>AsEnumerable</code>).</p>
</li>
<li><p><strong>IQueryable with EF Core</strong> translates LINQ queries into optimized SQL, executed by the database.</p>
</li>
<li><p><strong>Avoid immediate execution</strong> (e.g., early <code>ToList()</code>) for large datasets to prevent loading unnecessary data into memory.</p>
</li>
<li><p><strong>Optimize multiple operations</strong> by combining them into a single query, like using <code>GroupBy</code> for <code>FirstOrDefault</code> and <code>Count</code>.</p>
</li>
<li><p><strong>Pro Tip</strong>: Use async methods (<code>ToListAsync()</code>, <code>FirstOrDefaultAsync()</code>) for database queries to keep your app responsive.</p>
</li>
</ul>
<p>Deferred execution is a superpower in LINQ with EF Core. By understanding when queries materialize and how to optimize them, you can write cleaner, faster, and more scalable code. Next time you’re querying a database, use deferred execution to minimize database hits and maximize performance.</p>
]]></content:encoded></item><item><title><![CDATA[IEnumerable<T> vs IQueryable<T>:
When to use each]]></title><description><![CDATA[If you’ve worked with LINQ in C#, you’ve likely encountered IEnumerable<T> and IQueryable<T>. They both support LINQ queries, but their behavior differs significantly, especially when querying databases. Choosing the wrong one can lead to performance...]]></description><link>https://krisoncode.com/ienumerablet-vs-iqueryablet-when-to-use-each</link><guid isPermaLink="true">https://krisoncode.com/ienumerablet-vs-iqueryablet-when-to-use-each</guid><category><![CDATA[#IEnumerable]]></category><category><![CDATA[IQueryable]]></category><category><![CDATA[.NET]]></category><category><![CDATA[efcore]]></category><dc:creator><![CDATA[Kristiadhy]]></dc:creator><pubDate>Fri, 12 Sep 2025 06:17:54 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1757657161561/f78511f2-a934-4117-8d60-981c6742941f.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you’ve worked with LINQ in C#, you’ve likely encountered <code>IEnumerable&lt;T&gt;</code> and <code>IQueryable&lt;T&gt;</code>. They both support LINQ queries, but their behavior differs significantly, especially when querying databases. Choosing the wrong one can lead to performance bottlenecks or bloated code. In this post, we’ll explore their differences, provide clear examples, and guide you on when to use each.</p>
<h2 id="heading-what-are-they">What Are They?</h2>
<h3 id="heading-ienumerable">IEnumerable</h3>
<ul>
<li><p><strong>Definition</strong>: Represents an in-memory sequence of objects you can iterate over.</p>
</li>
<li><p><strong>Execution</strong>: Uses delegates (<code>Func&lt;T, bool&gt;</code>) to filter or transform data, executed by the CLR (Common Language Runtime).</p>
</li>
<li><p><strong>Typical Use</strong>: LINQ-to-Objects for in-memory collections like <code>List&lt;T&gt;</code> or arrays.</p>
</li>
</ul>
<h3 id="heading-iqueryable">IQueryable</h3>
<ul>
<li><p><strong>Definition</strong>: Represents a query that can be executed against a query provider (e.g., Entity Framework Core for databases).</p>
</li>
<li><p><strong>Execution</strong>: Uses expression trees (<code>Expression&lt;Func&lt;T, bool&gt;&gt;</code>) that a provider translates into something like SQL.</p>
</li>
<li><p><strong>Typical Use</strong>: LINQ-to-Entities for database queries or remote data sources.</p>
</li>
</ul>
<p>The core difference is <em>where</em> the query runs: <code>IEnumerable&lt;T&gt;</code> processes data in memory, while <code>IQueryable&lt;T&gt;</code> pushes processing to the data source (e.g., a database).</p>
<h2 id="heading-working-with-in-memory-collections">Working with In-Memory Collections</h2>
<p>When querying in-memory data (like a <code>List&lt;T&gt;</code>), both <code>IEnumerable&lt;T&gt;</code> and <code>IQueryable&lt;T&gt;</code> execute in the CLR, so their differences are subtle.</p>
<h3 id="heading-ienumerable-example">IEnumerable Example</h3>
<p>Filtering a list of users in memory:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> users = <span class="hljs-keyword">new</span> List&lt;User&gt;
{
    <span class="hljs-keyword">new</span> User { Name = <span class="hljs-string">"Alice"</span>, Age = <span class="hljs-number">25</span> },
    <span class="hljs-keyword">new</span> User { Name = <span class="hljs-string">"Bob"</span>, Age = <span class="hljs-number">40</span> },
    <span class="hljs-keyword">new</span> User { Name = <span class="hljs-string">"Charlie"</span>, Age = <span class="hljs-number">35</span> }
};

<span class="hljs-comment">// Filter users over 30 using IEnumerable&lt;T&gt;</span>
IEnumerable&lt;User&gt; result = users.Where(u =&gt; u.Age &gt; <span class="hljs-number">30</span>);
</code></pre>
<p><strong>What’s happening?</strong></p>
<ul>
<li><p>The <code>Where</code> clause uses a delegate (<code>Func&lt;User, bool&gt;</code>).</p>
</li>
<li><p>The CLR iterates each element, applying the filter:</p>
</li>
</ul>
<pre><code class="lang-csharp">Func&lt;User, <span class="hljs-keyword">bool</span>&gt; predicate = user =&gt; user.Age &gt; <span class="hljs-number">30</span>;
<span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> user <span class="hljs-keyword">in</span> users)
{
    <span class="hljs-keyword">if</span> (predicate(user))
    {
        <span class="hljs-keyword">yield</span> <span class="hljs-keyword">return</span> user; <span class="hljs-comment">// Include if true</span>
    }
}
</code></pre>
<p><strong>Result</strong>: Returns <code>Bob</code> and <code>Charlie</code>, processed in memory.</p>
<h3 id="heading-iqueryable-example">IQueryable Example</h3>
<p>Same filter, but with <code>IQueryable&lt;T&gt;</code>:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> users = <span class="hljs-keyword">new</span> List&lt;User&gt;
{
    <span class="hljs-keyword">new</span> User { Name = <span class="hljs-string">"Alice"</span>, Age = <span class="hljs-number">25</span> },
    <span class="hljs-keyword">new</span> User { Name = <span class="hljs-string">"Bob"</span>, Age = <span class="hljs-number">40</span> },
    <span class="hljs-keyword">new</span> User { Name = <span class="hljs-string">"Charlie"</span>, Age = <span class="hljs-number">35</span> }
};

<span class="hljs-comment">// Convert to IQueryable&lt;T&gt; and filter</span>
IQueryable&lt;User&gt; result = users.AsQueryable().Where(u =&gt; u.Age &gt; <span class="hljs-number">30</span>);
</code></pre>
<p><strong>What’s happening?</strong></p>
<ul>
<li><p>The <code>Where</code> clause builds an expression tree (<code>Expression&lt;Func&lt;User, bool&gt;&gt;</code>).</p>
</li>
<li><p>Since no database provider is involved, LINQ-to-Objects evaluates the expression tree in memory, looping through the collection like <code>IEnumerable&lt;T&gt;</code>.</p>
</li>
</ul>
<p><strong>Outcome</strong>: For in-memory data, both interfaces perform similarly. Use <code>IEnumerable&lt;T&gt;</code> for simplicity unless you’re testing query provider behavior.</p>
<h2 id="heading-working-with-databases-entity-framework-core">Working with Databases (Entity Framework Core)</h2>
<p>When querying a database with Entity Framework Core, the choice between <code>IEnumerable&lt;T&gt;</code> and <code>IQueryable&lt;T&gt;</code> drastically affects performance. <code>IEnumerable&lt;T&gt;</code> processes data in memory, while <code>IQueryable&lt;T&gt;</code> lets the database handle the heavy lifting.</p>
<h3 id="heading-ienumerable-example-pulls-all-data-to-memory">IEnumerable Example (Pulls All Data to Memory)</h3>
<p>Suppose you’re querying a <code>Users</code> table:</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Load all users into memory</span>
IEnumerable&lt;User&gt; users = dbContext.Users.AsEnumerable();

<span class="hljs-comment">// Filter and sort in memory</span>
<span class="hljs-keyword">var</span> result = users
    .Where(u =&gt; u.IsActive &amp;&amp; u.Age &gt; <span class="hljs-number">30</span>)
    .OrderBy(u =&gt; u.LastName)
    .Take(<span class="hljs-number">2</span>);
</code></pre>
<p><strong>What’s happening?</strong></p>
<ul>
<li><p><code>AsEnumerable()</code> (or <code>ToList()</code>) forces the query to execute immediately, retrieving <em>all rows</em> from the <code>Users</code> table (e.g., <code>SELECT * FROM Users</code>).</p>
</li>
<li><p>The CLR then applies <code>Where</code>, <code>OrderBy</code>, and <code>Take</code> to the in-memory collection.</p>
</li>
<li><p><strong>Problem</strong>: If the table has 1 million rows, all 1 million are loaded into memory before filtering or sorting. This is slow and resource-intensive.</p>
</li>
</ul>
<p><strong>Example SQL executed</strong>:</p>
<p>This line of code:</p>
<pre><code class="lang-csharp">IEnumerable&lt;User&gt; users = dbContext.Users.AsEnumerable();
</code></pre>
<p>Will generate this SQL query:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> <span class="hljs-keyword">Users</span>;
</code></pre>
<ul>
<li><strong>Downside</strong>: Network traffic spikes, memory usage balloons, and performance suffers.</li>
</ul>
<h3 id="heading-important-note-deferred-execution">⚠️ Important Note: Deferred Execution</h3>
<p>If you don’t call <code>.AsEnumerable()</code> or <code>.ToList()</code>, the query is <strong>not executed immediately</strong>:</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// IQueryable&lt;User&gt; (DbSet) upcasted to IEnumerable&lt;User&gt;</span>
IEnumerable&lt;User&gt; users = dbContext.Users;

<span class="hljs-comment">// Still part of the query pipeline</span>
<span class="hljs-keyword">var</span> result = users
    .Where(u =&gt; u.IsActive &amp;&amp; u.Age &gt; <span class="hljs-number">30</span>)
    .OrderBy(u =&gt; u.LastName)
    .Take(<span class="hljs-number">2</span>);
</code></pre>
<h4 id="heading-whats-really-happening">What’s really happening:</h4>
<ul>
<li><p><code>dbContext.Users</code> is a <code>DbSet&lt;User&gt;</code>, which implements <strong>both</strong> <code>IQueryable&lt;User&gt;</code> and <code>IEnumerable&lt;User&gt;</code>.</p>
</li>
<li><p>Simply assigning it to an <code>IEnumerable&lt;User&gt;</code> <strong>does not materialize</strong> the data.</p>
</li>
<li><p>EF Core still sees the underlying <code>IQueryable</code>.</p>
</li>
<li><p>When you chain <code>.Where()</code>, <code>.OrderBy()</code>, <code>.Take()</code>, the <strong>expression tree is preserved</strong>.</p>
</li>
<li><p>EF Core translates the final query into SQL when you enumerate (e.g. <code>foreach</code>, <code>.ToList()</code>).</p>
</li>
</ul>
<h4 id="heading-sql-generated">SQL Generated:</h4>
<pre><code class="lang-csharp"><span class="hljs-function">SELECT <span class="hljs-title">TOP</span>(<span class="hljs-params"><span class="hljs-number">2</span></span>) *
FROM Users
WHERE IsActive</span> = <span class="hljs-number">1</span> AND Age &gt; <span class="hljs-number">30</span>
ORDER BY LastName;
</code></pre>
<p>Filtering, sorting, and limiting still happen <strong>in the database</strong>, not in memory.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Prefer declaring <strong>IQueryable </strong>instead of <strong>IEnumerable </strong>if you want deferred execution and database-side filtering. <code>IQueryable users = dbContext.Users;</code> This makes it explicit to readers (and to yourself later) that the query will be composed and executed in the database, not in memory.</div>
</div>

<p>Please read more about deferred execution here: <a target="_blank" href="https://krisoncode.com/understanding-deferred-execution-in-linq-with-entity-framework-core">Understanding Deferred Execution in LINQ with Entity Framework Core</a></p>
<h3 id="heading-iqueryable-example-database-optimized">IQueryable Example (Database-Optimized)</h3>
<p>Same query, but using <code>IQueryable&lt;T&gt;</code>:</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Build query to execute in the database</span>
IQueryable&lt;User&gt; usersQuery = dbContext.Users
    .Where(u =&gt; u.IsActive &amp;&amp; u.Age &gt; <span class="hljs-number">30</span>)
    .OrderBy(u =&gt; u.LastName)
    .Take(<span class="hljs-number">2</span>);

<span class="hljs-comment">// Execute when needed</span>
<span class="hljs-keyword">var</span> result = usersQuery.ToList();
</code></pre>
<p><strong>What’s happening?</strong></p>
<ul>
<li>The query builds an expression tree that EF Core translates into a single, optimized SQL query:</li>
</ul>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> TOP(<span class="hljs-number">2</span>) *
<span class="hljs-keyword">FROM</span> <span class="hljs-keyword">Users</span>
<span class="hljs-keyword">WHERE</span> IsActive = <span class="hljs-number">1</span> <span class="hljs-keyword">AND</span> Age &gt; <span class="hljs-number">30</span>
<span class="hljs-keyword">ORDER</span> <span class="hljs-keyword">BY</span> LastName;
</code></pre>
<ul>
<li><p>The database performs the filtering, sorting, and limiting, returning only the two matching rows.</p>
</li>
<li><p><strong>Benefit</strong>: Minimal data is transferred, and the database’s query engine optimizes the operation.</p>
</li>
</ul>
<p><strong>Outcome</strong>: <code>IQueryable&lt;T&gt;</code> is far more efficient for databases, as it minimizes data transfer and leverages the database’s capabilities.</p>
<h2 id="heading-key-differences-in-database-queries">Key Differences in Database Queries</h2>
<ul>
<li><p><strong>IEnumerable</strong>:</p>
<ul>
<li><p>Pulls <em>all</em> data into memory before processing.</p>
</li>
<li><p>Filtering/sorting happens in the CLR, which is slow for large datasets.</p>
</li>
<li><p>Risk: Overloading memory and network with unnecessary data.</p>
</li>
</ul>
</li>
<li><p><strong>IQueryable</strong>:</p>
<ul>
<li><p>Translates LINQ operations into SQL, executed by the database.</p>
</li>
<li><p>Only retrieves the data you need.</p>
</li>
<li><p>Benefit: Faster, less memory usage, and scalable for large datasets.</p>
</li>
</ul>
</li>
</ul>
<h2 id="heading-a-real-world-analogy">A Real-World Analogy</h2>
<ul>
<li><p><strong>IEnumerable</strong>: You order every item from an online store, have it shipped to your house, then pick the ones you want. Wasteful!</p>
</li>
<li><p><strong>IQueryable</strong>: You filter your order online (e.g., “only blue shirts under $20”), and only those items are shipped. Efficient!</p>
</li>
</ul>
<h2 id="heading-when-to-use-each">When to Use Each</h2>
<h3 id="heading-use-ienumerable">Use IEnumerable</h3>
<ul>
<li><p><strong>In-memory collections</strong>: For <code>List&lt;T&gt;</code>, arrays, or cached data.</p>
</li>
<li><p><strong>Small datasets</strong>: When the data is already in memory and performance isn’t a concern.</p>
</li>
<li><p><strong>Example</strong>: Filtering a small list of cached items.</p>
</li>
</ul>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> cachedProducts = GetProductsFromCache(); <span class="hljs-comment">// Returns List&lt;Product&gt;</span>
<span class="hljs-keyword">var</span> discounted = cachedProducts.Where(p =&gt; p.Price &lt; <span class="hljs-number">10</span>);
</code></pre>
<h3 id="heading-use-iqueryable">Use IQueryable</h3>
<ul>
<li><p><strong>Database queries</strong>: For EF Core or other query providers (e.g., APIs).</p>
</li>
<li><p><strong>Large datasets</strong>: When you want the database to handle filtering, sorting, or paging.</p>
</li>
<li><p><strong>Example</strong>: Fetching paginated data from a database.</p>
</li>
</ul>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> activeUsers = dbContext.Users
    .Where(u =&gt; u.IsActive)
    .OrderBy(u =&gt; u.LastName)
    .Skip(<span class="hljs-number">10</span>)
    .Take(<span class="hljs-number">5</span>)
    .ToList();
</code></pre>
<h2 id="heading-quick-comparison-table">Quick Comparison Table</h2>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Aspect</strong></td><td><strong>IEnumerable</strong></td><td><strong>IQueryable</strong></td></tr>
</thead>
<tbody>
<tr>
<td><strong>Definition</strong></td><td>In-memory sequence</td><td>Query against a provider (e.g., EF Core)</td></tr>
<tr>
<td><strong>Execution</strong></td><td>Delegates (<code>Func&lt;T, bool&gt;</code>) in CLR</td><td>Expression trees (<code>Expression&lt;Func&lt;T, bool&gt;&gt;</code>)</td></tr>
<tr>
<td><strong>In-Memory</strong></td><td>Runs in memory</td><td>Runs in memory (LINQ-to-Objects)</td></tr>
<tr>
<td><strong>Databases</strong></td><td>Loads all rows, filters in memory</td><td>Filters in database, returns minimal data</td></tr>
<tr>
<td><strong>Efficiency</strong></td><td>Inefficient for large remote datasets</td><td>Efficient for large remote datasets</td></tr>
<tr>
<td><strong>Use Case</strong></td><td>LINQ-to-Objects</td><td>LINQ-to-Entities, remote queries</td></tr>
</tbody>
</table>
</div><h2 id="heading-conclusions">Conclusions</h2>
<ul>
<li><p><strong>IEnumerable</strong>: Great for in-memory data like lists or arrays. Avoid for database queries unless the dataset is small.</p>
</li>
<li><p><strong>IQueryable</strong>: Ideal for databases or remote sources, pushing filtering and sorting to the data source for efficiency.</p>
</li>
<li><p><strong>Pro Tip</strong>: Be cautious with <code>AsEnumerable()</code> or <code>ToList()</code> in database queries—they force data into memory, negating <code>IQueryable&lt;T&gt;</code>’s benefits.</p>
</li>
</ul>
<p>Choosing between <code>IEnumerable&lt;T&gt;</code> and <code>IQueryable&lt;T&gt;</code> depends on where your data lives. For in-memory work, <code>IEnumerable&lt;T&gt;</code> is simpler. For databases, <code>IQueryable&lt;T&gt;</code> is your go-to for performance and scalability. Next time you write a LINQ query, think about where the work should happen—client or server—and pick the right tool for the job.</p>
]]></content:encoded></item><item><title><![CDATA[How to Integrate Azure App Configuration in ASP.NET Core for Centralized Settings]]></title><description><![CDATA[In an ASP .NET Core application, configuration values are often stored in appsettings.json.For different environments, we typically create separate files such as appsettings.Development.json, appsettings.Staging.json, and appsettings.Production.json....]]></description><link>https://krisoncode.com/how-to-integrate-azure-app-configuration-in-aspnet-core-for-centralized-settings</link><guid isPermaLink="true">https://krisoncode.com/how-to-integrate-azure-app-configuration-in-aspnet-core-for-centralized-settings</guid><category><![CDATA[Azure]]></category><category><![CDATA[dotnet]]></category><category><![CDATA[AppConfig]]></category><category><![CDATA[APPSETTINGS.JSON]]></category><dc:creator><![CDATA[Kristiadhy]]></dc:creator><pubDate>Mon, 11 Aug 2025 02:57:52 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1754879760026/957d10ce-cee5-4788-aef4-f7b5005d5be5.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In an <strong>ASP .NET Core</strong> application, configuration values are often stored in <code>appsettings.json</code>.<br />For different environments, we typically create separate files such as <code>appsettings.Development.json</code>, <code>appsettings.Staging.json</code>, and <code>appsettings.Production.json</code>.</p>
<p>While this approach works, it comes with several drawbacks—especially in production:</p>
<ul>
<li><p><strong>Deployment Complexity.</strong></p>
<p>  Even small configuration changes may require a <strong>full CI/CD pipeline run</strong> or manual updates in each environment on your cloud server. This slows down delivery and increases operational overhead.</p>
</li>
<li><p><strong>Difficult to Maintain.</strong></p>
<p>  If you have multiple environments (e.g., <strong>Development</strong>, <strong>Staging</strong>, and <strong>Production</strong>), keeping all configuration files synchronized can be error-prone. Missing or outdated values in one environment can lead to bugs or inconsistencies.</p>
</li>
<li><p><strong>Limited Access Control.</strong></p>
<p>  <code>appsettings.json</code> is accessible to anyone with file system access. Fine-grained access control—such as granting read-only permissions to specific keys—is not straightforward.</p>
</li>
</ul>
<h3 id="heading-this-is-why-you-need-central-configuration">This is why you need central configuration.</h3>
<p>A <strong>centralized configuration system</strong> solves these problems by providing:</p>
<ul>
<li><p><strong>One source of truth</strong> for configuration values.</p>
</li>
<li><p><strong>Instant updates</strong> without requiring application redeployments.</p>
</li>
<li><p><strong>Better security and access control</strong> for sensitive values.</p>
</li>
</ul>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">In the previous article, I explained how to connect your ASP .NET Core application to Azure Key Vault to store secrets. You can read it here: <a target="_self" href="https://kristiadhy.hashnode.dev/how-to-secure-your-net-application-secrets-with-azure-key-vault-free-code-repository-included">Azure Key Vault: Secure .NET App Secrets</a></div>
</div>

<h2 id="heading-azure-app-configuration">Azure App Configuration</h2>
<p>Azure App Configuration is a fully managed service that lets you <strong>store, manage, and distribute application settings</strong> from a single location.<br />Rather than storing configuration values in local files and including them in your codebase, you should keep them in a centralized store and retrieve them at runtime.</p>
<p>Key benefits:</p>
<ul>
<li><p><strong>Instant configuration updates</strong> without redeploying your app</p>
</li>
<li><p><strong>Consistency</strong> across multiple environments and applications</p>
</li>
<li><p><strong>Dynamic settings</strong> support, including <strong>feature flags</strong></p>
</li>
</ul>
<p>Let’s get started.</p>
<h3 id="heading-setting-up-azure-app-configuration">Setting Up Azure App Configuration.</h3>
<ol>
<li><p><strong>Create the service.</strong><br /> In the Azure Portal, search for <strong>App Configuration</strong> in the top search bar.<br /> Click <strong>Create</strong> and provide the required details (subscription, resource group, region, and name). Once done, click <strong>Review + Create</strong>, then <strong>Create</strong>.</p>
</li>
<li><p><strong>Add configuration values.</strong><br /> After the resource is created, open it and navigate to <strong>Configuration Explorer</strong> from the left-hand menu.<br /> Click <strong>+ Create</strong> to add a new key-value pair.</p>
</li>
<li><p><strong>Define your settings.</strong><br /> You can add keys in the same way you would structure them in <code>appsettings.json</code>. For example:</p>
<ul>
<li><code>AppSettings:AppName</code> → <code>"My Web App"</code></li>
</ul>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1754867332649/e5450937-bb9b-4408-8e78-66f2e6e466b1.png" alt /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Azure App Configuration supports <strong>hierarchical keys</strong> (use<code>:</code> as a separator), allowing you to mirror your application’s configuration structure.</div>
</div>

<p>The example below shows what it looks like in the Azure configuration.</p>
<p><strong>Note: You can categorize your key using a label.</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1754867276460/46f8803e-66c7-4e1f-b802-a367657f725a.png" alt /></p>
<p>It’s similar to this structure in your <code>appsettings.json</code>:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"AppSettings"</span>: {
    <span class="hljs-attr">"AppName"</span>: <span class="hljs-string">"MyApp"</span>,
    <span class="hljs-attr">"Developer"</span>: <span class="hljs-string">"Kristiadhy"</span>
  }
}
</code></pre>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Never store secrets in <strong>Azure App Configuration</strong>. Store them in <strong>Azure Key Vault </strong>instead. You can still connect it to Azure App Configuration using a Key Vault reference. I'll explain this further in another article.</div>
</div>

<p>Now, let's look at how you can read it from your app.</p>
<h3 id="heading-connecting-your-asp-net-core-app-to-azure-app-configuration">Connecting your ASP NET Core app to Azure App Configuration.</h3>
<p>Here’s how you can connect your app to Azure App Configuration.</p>
<p><strong>Install the required NuGet packages</strong></p>
<p>From your project directory, run:</p>
<pre><code class="lang-csharp">dotnet <span class="hljs-keyword">add</span> package Microsoft.Azure.AppConfiguration.AspNetCore
</code></pre>
<p><strong>Retrieve the connection string from Azure</strong></p>
<p>In the Azure Portal, navigate to your <strong>App Configuration</strong> resource and:</p>
<ul>
<li><p>Go to <strong>Access Settings</strong> in the left-hand menu.</p>
</li>
<li><p>Copy the <strong>Primary Connection String</strong>.</p>
</li>
</ul>
<p>Note: You'll have <strong>Read-Write</strong> keys or <strong>Read-Only</strong> keys. Please select accordingly.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1754874032442/45685d2f-ff54-4625-9003-04dd1b8f8ae6.jpeg" alt /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Store this connection string in a secure location, such as <strong>user secrets</strong> for local development and environment variables in production.</div>
</div>

<p>Note: To use a user secret in Visual Studio, right-click your project and select Manage User Secret. Then, enter the value as shown in the example below.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1754880841083/dc6510a9-6207-4985-b953-647ef23330ca.png" alt class="image--center mx-auto" /></p>
<p><strong>Update</strong> <code>Program.cs</code> <strong>to use Azure App Configuration</strong></p>
<p>Modify your <code>Program.cs</code> to load configuration from Azure:</p>
<pre><code class="lang-json">using Azure.Identity;

var builder = WebApplication.CreateBuilder(args);

<span class="hljs-comment">// Connect to Azure App Configuration</span>
builder.Configuration.AddAzureAppConfiguration(options =&gt;
{
    options.Connect(builder.Configuration[<span class="hljs-attr">"AzureAppConfiguration:ConnectionString"</span>]);
});

builder.Services.AddAzureAppConfiguration();

var app = builder.Build();

app.UseAzureAppConfiguration();

app.MapControllers();
app.Run();
</code></pre>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">The above example is not recommended for connecting to your Azure App Configuration because the value will not automatically refresh if there is an update to the value. 🚫 I’ll provide a more robust approach with <strong>multiple settings</strong> and <strong>an explanation </strong>in the <strong>free repository</strong> at the end of the article. ✅</div>
</div>

<p><strong>Using the configuration in your code.</strong></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">AppConfigController</span> : <span class="hljs-title">ControllerBase</span>
{
  <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IConfiguration _configuration;

  <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">AppConfigController</span>(<span class="hljs-params">IConfiguration configuration</span>)</span>
  {
    _configuration = configuration;
  }

  [<span class="hljs-meta">HttpGet(<span class="hljs-meta-string">"Configuration"</span>)</span>]
  <span class="hljs-function"><span class="hljs-keyword">public</span> IActionResult <span class="hljs-title">GetAppConfigValueFromConfiguration</span>(<span class="hljs-params"></span>)</span>
  {
    <span class="hljs-keyword">var</span> appSettings = <span class="hljs-keyword">new</span> AppSettings
    {
      AppName = _configuration[<span class="hljs-string">"AppSettings:AppName"</span>]!,
      Developer = _configuration[<span class="hljs-string">"AppSettings:Developer"</span>]!
    };
    <span class="hljs-keyword">return</span> Ok(appSettings);
  }
}
</code></pre>
<p>The example above is also not recommended 🚫; it’s better to use the Option Pattern instead of injecting the configuration directly into your controller. In the free repository below, I have provided a more robust approach ✅:</p>
<ul>
<li><p>Using an extension method that makes your <code>program.cs</code> cleaner.</p>
</li>
<li><p>Different refresh settings with explanations to help you understand the refresh with multiple approaches.</p>
</li>
<li><p>Using the Option Pattern for a more effective approach.</p>
</li>
</ul>
<p>Grab this for repository free: <a target="_blank" href="https://github.com/kristiadhy/AzureAppConfigAndKeyVaultIntegration">https://github.com/kristiadhy/AzureAppConfigAndKeyVaultIntegration</a></p>
<p><strong>Note: If you find this helpful, please like the repo.</strong></p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>By using <strong>Azure App Configuration</strong>, you centralize configuration management, enabling instant updates across environments without redeployments.</p>
<p>This combination delivers:</p>
<ul>
<li><p><strong>Centralized management</strong> for all application settings.</p>
</li>
<li><p><strong>Consistent configuration</strong> across multiple apps and environments.</p>
</li>
<li><p><strong>Faster, safer updates</strong> without downtime.</p>
</li>
</ul>
<p>In the next article, I'll explain how to integrate the Azure App Configuration and Key Vault.</p>
]]></content:encoded></item><item><title><![CDATA[How to Deploy Your Dockerized Web App to a Linux VPS]]></title><description><![CDATA[Deploying a web application, especially a containerized one, can seem daunting. This guide will walk you through the process of taking your Dockerized web application from your development environment and deploying it onto a Linux Virtual Private Ser...]]></description><link>https://krisoncode.com/how-to-deploy-your-dockerized-web-app-to-a-linux-vps</link><guid isPermaLink="true">https://krisoncode.com/how-to-deploy-your-dockerized-web-app-to-a-linux-vps</guid><category><![CDATA[deployment]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Docker]]></category><category><![CDATA[Docker compose]]></category><category><![CDATA[vps]]></category><dc:creator><![CDATA[Kristiadhy]]></dc:creator><pubDate>Wed, 09 Jul 2025 23:55:07 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1752055557900/59d156a6-9118-4066-9d0d-5381387700ba.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Deploying a web application, especially a containerized one, can seem daunting. This guide will walk you through the process of taking your Dockerized web application from your development environment and deploying it onto a Linux Virtual Private Server (VPS). If you haven't set up your VPS yet, follow these guidelines <a target="_blank" href="https://kristiadhy.hashnode.dev/initial-vps-configuration-guide-building-a-solid-foundation-for-your-web-application">VPS Setup Essentials for Your Web App</a></p>
<p>This article covers everything from preparing your server environment and installing Docker to setting up Nginx as a reverse proxy and securing your application with SSL using Let's Encrypt. By the end of this article, you'll have a clear understanding of each step and why it's crucial for a secure, scalable, and maintainable deployment.</p>
<p>This guide assumes you have:</p>
<ul>
<li><p>A Dockerized web application ready for deployment (e.g., an ASP.NET Core application with a <code>Dockerfile</code> and <code>docker-compose.yml</code>).</p>
</li>
<li><p>A Linux VPS (Ubuntu is used in examples).</p>
</li>
<li><p>Basic familiarity with Linux command-line interface.</p>
</li>
<li><p>A registered domain name pointing to your VPS's IP address.</p>
</li>
</ul>
<p>Let's get started!</p>
<h3 id="heading-1-prepare-the-user-and-directory-for-your-application">1. Prepare the User and Directory for Your Application</h3>
<p>Security and organization are paramount in a production environment. We will create a dedicated system user and a specific directory structure for your application. This isolation helps prevent unauthorized access to other parts of your system and keeps your deployments organized.</p>
<h4 id="heading-11-create-a-dedicated-user-for-your-website">1.1 Create a Dedicated User for Your Website</h4>
<p>It's a security best practice to run your web applications under a dedicated, unprivileged user account rather than the <code>root</code> user. This limits the potential damage if your application is compromised.</p>
<p>Let's create a user called <code>mywebsiteuser</code>:</p>
<pre><code class="lang-csharp">sudo adduser mywebsiteuser
</code></pre>
<p><strong>Explanation:</strong></p>
<ul>
<li><p><code>sudo</code>: Executes the command with superuser privileges.</p>
</li>
<li><p><code>adduser</code>: A high-level utility in Debian-based systems (like Ubuntu) to add a new user. It handles creating the user's home directory, setting up initial permissions, and prompting for a password and other user details.</p>
</li>
</ul>
<p>You'll be prompted to set a password for <code>mywebsiteuser</code> and provide some optional information. Choose a strong password.</p>
<h4 id="heading-12-create-a-web-root-directory-for-each-app">1.2 Create a Web Root Directory for Each App</h4>
<p>For consistent management and separation of concerns, it's recommended to place application code under a standardized web root directory, commonly <code>/var/www</code>. This makes it easier to locate and manage your deployments.</p>
<pre><code class="lang-csharp">sudo mkdir -p /<span class="hljs-keyword">var</span>/www/mywebsite
</code></pre>
<p><strong>Explanation:</strong></p>
<ul>
<li><p><code>mkdir</code>: Creates a new directory.</p>
</li>
<li><p><code>-p</code>: The <code>parents</code> option ensures that if any parent directories in the path (<code>/var/www</code> in this case) do not exist, they will be created automatically.</p>
</li>
<li><p><code>/var/www/mywebsite</code>: This is the full path where your <code>mywebsite</code> application's files will reside.</p>
</li>
</ul>
<h4 id="heading-13-set-ownership-of-these-directories">1.3 Set Ownership of These Directories</h4>
<p>After creating the directory, it's crucial to assign its ownership to the dedicated user you just created. This ensures that only <code>mywebsiteuser</code> (and <code>root</code>) can modify the contents of this directory.</p>
<pre><code class="lang-csharp">sudo chown -R mywebsiteuser:mywebsiteuser /<span class="hljs-keyword">var</span>/www/mywebsite
</code></pre>
<p><strong>Explanation:</strong></p>
<ul>
<li><p><code>chown</code>: Changes the owner and group of files or directories.</p>
</li>
<li><p><code>-R</code>: The <code>recursive</code> option applies the ownership change to all files and subdirectories within <code>/var/www/mywebsite</code>.</p>
</li>
<li><p><code>mywebsiteuser:mywebsiteuser</code>: Sets both the owner and the primary group of the directory to <code>mywebsiteuser</code>.</p>
</li>
</ul>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text"><strong>Why is this important?</strong> This step ensures that only the app-specific user (<code>mywebsiteuser</code>) can modify their code. This is a fundamental security principle: the principle of least privilege. If your application process is ever compromised, the attacker will be limited to the permissions of <code>mywebsiteuser</code>, preventing them from easily affecting other parts of your server or other applications.</div>
</div>

<h4 id="heading-14-set-permissions-for-the-directory">1.4 Set Permissions for the Directory</h4>
<p>While <code>chown</code> sets ownership, <code>chmod</code> sets file and directory permissions. These permissions dictate who can read, write, or execute files.</p>
<pre><code class="lang-csharp">sudo chmod -R <span class="hljs-number">755</span> /<span class="hljs-keyword">var</span>/www/mywebsite
</code></pre>
<p><strong>Explanation:</strong></p>
<ul>
<li><p><code>chmod</code>: Changes file mode bits (permissions).</p>
</li>
<li><p><code>755</code>: This is an octal representation of permissions:</p>
<ul>
<li><p><strong>7 (Owner):</strong> Read (4) + Write (2) + Execute (1) = 7. The owner (<code>mywebsiteuser</code>) has full control over files and directories.</p>
</li>
<li><p><strong>5 (Group):</strong> Read (4) + Execute (1) = 5. Members of the <code>mywebsiteuser</code> group can read and traverse (execute) directories.</p>
</li>
<li><p><strong>5 (Others):</strong> Read (4) + Execute (1) = 5. Everyone else can read and traverse directories.</p>
</li>
</ul>
</li>
<li><p><strong>Why these permissions?</strong> This configuration is standard for web content. The owner needs full control to deploy and manage the application. Others (like the web server process) only need read and execute (traverse) permissions to serve static content or execute scripts. Write access for others is generally not needed and poses a security risk.</p>
</li>
</ul>
<h4 id="heading-15-switch-to-the-application-user-when-deploying">1.5 Switch to the Application User When Deploying</h4>
<p>When performing operations related to your specific application, such as cloning your Git repository or deploying new code, you should always do so as the <code>mywebsiteuser</code>. This maintains the security boundaries established.</p>
<p>To switch to the <code>mywebsiteuser</code> shell:</p>
<pre><code class="lang-csharp">sudo -i -u mywebsiteuser
</code></pre>
<p><strong>Explanation:</strong></p>
<ul>
<li><p><code>sudo -i</code>: Simulates an initial login, giving you a shell as the target user with their environment variables.</p>
</li>
<li><p><code>-u mywebsiteuser</code>: Specifies <code>mywebsiteuser</code> as the user to switch to.</p>
</li>
</ul>
<p>Once you've switched users, navigate to your application's root directory:</p>
<pre><code class="lang-csharp">cd /<span class="hljs-keyword">var</span>/www/mywebsite
</code></pre>
<p>All subsequent operations (like <code>git clone</code>, <code>docker-compose up</code>) that directly interact with your application's files should be performed from this user and directory.</p>
<h3 id="heading-2-install-docker-and-docker-compose">2. Install Docker and Docker Compose</h3>
<p>Docker is the cornerstone of this deployment strategy, allowing you to package your application and its dependencies into isolated containers. Docker Compose simplifies the management of multi-container Docker applications.</p>
<h4 id="heading-21-option-1-install-docker-from-the-ubuntu-repository-simple-but-potentially-older-version">2.1 Option 1: Install Docker from the Ubuntu Repository (Simple, but potentially older version)</h4>
<p>This method uses the Docker package available in Ubuntu's default repositories. It's generally simpler but might provide an older version of Docker.</p>
<pre><code class="lang-csharp">sudo apt update
sudo apt install -y docker.io
sudo systemctl enable --now docker
sudo usermod -aG docker $USER
</code></pre>
<p><strong>Explanation:</strong></p>
<ul>
<li><p><code>sudo apt update</code>: Refreshes the list of available packages from the repositories.</p>
</li>
<li><p><code>sudo apt install -y docker.io</code>: Installs the <code>docker.io</code> package. The <code>-y</code> flag automatically answers yes to prompts.</p>
</li>
<li><p><code>sudo systemctl enable --now docker</code>:</p>
<ul>
<li><p><code>systemctl enable docker</code>: Configures Docker to start automatically on system boot.</p>
</li>
<li><p><code>--now</code>: Starts the Docker service immediately without requiring a reboot.</p>
</li>
</ul>
</li>
<li><p><code>sudo usermod -aG docker $USER</code>: Adds your <em>current logged-in user</em> (the user you are using to SSH into the VPS) to the <code>docker</code> group. This is crucial because it allows your current user to run Docker commands without needing <code>sudo</code> every time.</p>
</li>
</ul>
<h4 id="heading-22-option-2-install-docker-ce-community-edition-from-official-docker-repository-recommended">2.2 Option 2: Install Docker CE (Community Edition) from Official Docker Repository (Recommended)</h4>
<p>This is the recommended approach for production environments as it provides the latest stable version of Docker CE, along with <code>containerd</code> (a core container runtime) and <code>Docker Compose CLI plugin</code>.</p>
<p>First, update your package index and install necessary utilities:</p>
<pre><code class="lang-csharp">sudo apt update
sudo apt install ca-certificates curl gnupg -y
</code></pre>
<p><strong>Explanation:</strong></p>
<ul>
<li><p><code>ca-certificates</code>: Allows web browsers and other programs to check the authenticity of SSL/TLS certificates.</p>
</li>
<li><p><code>curl</code>: A command-line tool for transferring data with URLs. Used here to download Docker's GPG key.</p>
</li>
<li><p><code>gnupg</code>: GNU Privacy Guard, used for managing cryptographic keys. Needed to verify the authenticity of Docker packages.</p>
</li>
</ul>
<p>Next, add Docker's official GPG key. This key is used to verify the authenticity of packages downloaded from Docker's repository, ensuring they haven't been tampered with.</p>
<pre><code class="lang-csharp">sudo install -m <span class="hljs-number">0755</span> -d /etc/apt/keyrings
curl -fsSL https:<span class="hljs-comment">//download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg</span>
sudo chmod a+r /etc/apt/keyrings/docker.gpg
</code></pre>
<p><strong>Explanation:</strong></p>
<ul>
<li><p><code>sudo install -m 0755 -d /etc/apt/keyrings</code>: Creates the <code>/etc/apt/keyrings</code> directory with appropriate permissions if it doesn't exist. This is where APT stores cryptographic keys.</p>
</li>
<li><p><code>curl -fsSL https://download.docker.com/linux/ubuntu/gpg</code>: Downloads the Docker GPG key.</p>
<ul>
<li><p><code>-f</code>: Fail silently on HTTP errors.</p>
</li>
<li><p><code>-s</code>: Silent mode (don't show progress meter or error messages).</p>
</li>
<li><p><code>-S</code>: Show error messages even with <code>-s</code>.</p>
</li>
<li><p><code>-L</code>: Follow redirects.</p>
</li>
</ul>
</li>
<li><p><code>| sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg</code>: Pipes the downloaded key to <code>gpg --dearmor</code>, which converts it to a format readable by APT, and saves it to the specified file.</p>
</li>
<li><p><code>sudo chmod a+r /etc/apt/keyrings/docker.gpg</code>: Sets read permissions for all users on the GPG key file.</p>
</li>
</ul>
<p>Now, add the Docker repository to your APT sources:</p>
<pre><code class="lang-csharp">echo \
  <span class="hljs-string">"deb [arch="</span>$(dpkg --print-architecture)<span class="hljs-string">" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  "</span>$(. /etc/os-release &amp;&amp; echo <span class="hljs-string">"$VERSION_CODENAME"</span>)<span class="hljs-string">" stable"</span> | \
  sudo tee /etc/apt/sources.list.d/docker.list &gt; /dev/<span class="hljs-literal">null</span>
sudo apt update
</code></pre>
<p><strong>Explanation:</strong></p>
<ul>
<li><p><code>echo "deb ... stable"</code>: This command constructs the repository entry string.</p>
<ul>
<li><p><code>$(dpkg --print-architecture)</code>: Dynamically gets your system's architecture (e.g., <code>amd64</code>).</p>
</li>
<li><p><code>signed-by=/etc/apt/keyrings/docker.gpg</code>: Specifies the GPG key used to sign packages from this repository.</p>
</li>
<li><p><code>$(. /etc/os-release &amp;&amp; echo "$VERSION_CODENAME")</code>: Dynamically gets your Ubuntu version's codename (e.g., <code>jammy</code> for Ubuntu 22.04).</p>
</li>
<li><p><code>stable</code>: Specifies that you want the stable release channel.</p>
</li>
</ul>
</li>
<li><p><code>| sudo tee /etc/apt/sources.list.d/docker.list &gt; /dev/null</code>: Pipes the output of <code>echo</code> to <code>tee</code>. <code>tee</code> writes to both standard output and the specified file (<code>/etc/apt/sources.list.d/docker.list</code>). Using <code>sudo tee</code> allows writing to a system file, and <code>&gt; /dev/null</code> suppresses output to the console.</p>
</li>
<li><p><code>sudo apt update</code>: Updates your package index again to include packages from the newly added Docker repository.</p>
</li>
</ul>
<p>Finally, install Docker Engine, containerd, and Docker Compose (CLI plugin):</p>
<pre><code class="lang-csharp">sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y
</code></pre>
<p><strong>Explanation:</strong></p>
<ul>
<li><p><code>docker-ce</code>: The Docker Engine Community Edition.</p>
</li>
<li><p><code>docker-ce-cli</code>: The Docker command-line interface.</p>
</li>
<li><p><code>containerd.io</code>: A high-level container runtime that Docker Engine uses internally.</p>
</li>
<li><p><code>docker-buildx-plugin</code>: A Docker CLI plugin for extended build capabilities (e.g., building multi-platform images).</p>
</li>
<li><p><code>docker-compose-plugin</code>: The new, integrated Docker Compose CLI plugin (accessible via <code>docker compose</code> without a hyphen).</p>
</li>
</ul>
<p>Add your user to the <code>docker</code> group (again, in case you purged it or if this is a fresh setup):</p>
<pre><code class="lang-csharp">sudo usermod -aG docker ${USER}
</code></pre>
<p><strong>Important Note:</strong> The <code>$USER</code> (or <code>${USER}</code>) variable expands to the username of the user currently logged in. This command adds <em>your current SSH user</em> to the <code>docker</code> group.</p>
<p><strong>To apply group membership changes, you MUST log out and log back in to your VPS.</strong> This reloads your user's group memberships. Simply running new commands will not reflect the change until a new session is started.</p>
<h4 id="heading-23-test-docker-installation">2.3 Test Docker Installation</h4>
<p>After logging back in, verify that Docker is correctly installed and that your user can run Docker commands without <code>sudo</code>:</p>
<pre><code class="lang-csharp">docker run hello-world
</code></pre>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text"><strong>Explanation:</strong> This command pulls a minimal "hello-world" image from Docker Hub and runs it in a new container. If successful, it confirms Docker is working and your user has the necessary permissions.</div>
</div>

<h3 id="heading-3-install-docker-compose-legacy-standalone-binary-if-not-using-docker-ce-plugin">3. Install Docker Compose (Legacy Standalone Binary - If not using Docker CE plugin)</h3>
<p><em>(Note: If you followed Option 2 and installed</em> <code>docker-compose-plugin</code>, you can skip this section as <code>docker compose</code> is already available as a Docker CLI subcommand. This section is for situations where you might have installed Docker via Option 1 or prefer the standalone <code>docker-compose</code> binary.)</p>
<p>While the <code>docker-compose-plugin</code> is the modern approach, some users might still prefer or require the standalone <code>docker-compose</code> binary.</p>
<p>First, define where the Docker Compose binary will be stored:</p>
<pre><code class="lang-csharp">DOCKER_CONFIG=${DOCKER_CONFIG:-$HOME/.docker}
mkdir -p $DOCKER_CONFIG/cli-plugins
</code></pre>
<p><strong>Explanation:</strong></p>
<ul>
<li><p><code>DOCKER_CONFIG=${DOCKER_CONFIG:-$HOME/.docker}</code>: This sets the <code>DOCKER_CONFIG</code> environment variable. If <code>DOCKER_CONFIG</code> is already set, it uses its value; otherwise, it defaults to <code>$HOME/.docker</code>. This is a common location for Docker CLI plugins.</p>
</li>
<li><p><code>mkdir -p $DOCKER_CONFIG/cli-plugins</code>: Creates the <code>cli-plugins</code> directory within your <code>DOCKER_CONFIG</code> path.</p>
</li>
</ul>
<p>Download the Docker Compose binary:</p>
<pre><code class="lang-csharp">curl -SL https:<span class="hljs-comment">//github.com/docker/compose/releases/latest/download/docker-compose-linux-x86_64 -o $DOCKER_CONFIG/cli-plugins/docker-compose</span>
</code></pre>
<p><strong>Explanation:</strong></p>
<ul>
<li><p><code>curl -SL ...</code>: Downloads the latest stable Docker Compose binary for Linux (x86_64 architecture).</p>
<ul>
<li><p><code>-S</code>: Show error messages.</p>
</li>
<li><p><code>-L</code>: Follow redirects.</p>
</li>
</ul>
</li>
<li><p><code>-o $DOCKER_CONFIG/cli-plugins/docker-compose</code>: Specifies the output file path and name for the downloaded binary.</p>
</li>
</ul>
<h4 id="heading-31-apply-executable-permissions">3.1 Apply Executable Permissions</h4>
<p>The downloaded binary needs to be marked as executable to be run as a command.</p>
<pre><code class="lang-csharp">chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose
</code></pre>
<p><strong>Explanation:</strong></p>
<ul>
<li><code>chmod +x</code>: Adds execute permission to the specified file.</li>
</ul>
<h4 id="heading-32-verify-the-installation">3.2 Verify the Installation</h4>
<p>Confirm that Docker Compose is correctly installed and accessible:</p>
<pre><code class="lang-csharp">docker compose version <span class="hljs-meta"># If using the plugin (Option 2)</span>
<span class="hljs-meta"># OR</span>
docker-compose version <span class="hljs-meta"># If using the standalone binary (Option 3)</span>
</code></pre>
<p>You should see the version number of Docker Compose printed to your console.</p>
<h3 id="heading-4-create-an-ssh-key-for-your-github-repository">4. Create an SSH Key for Your GitHub Repository</h3>
<p>When deploying your application, you'll typically pull your code from a Git repository (like GitHub, GitLab, or Bitbucket). Using SSH keys for authentication is more secure and convenient than using HTTPS with a personal access token, especially for automated deployments.</p>
<h4 id="heading-41-change-to-your-specific-website-user">4.1 Change to Your Specific Website User</h4>
<p><strong>Crucially, generate the SSH key as the</strong> <code>mywebsiteuser</code> (or whatever dedicated user you created), NOT as the <code>root</code> user or your primary SSH user. This ensures that the key is associated with the correct user and adheres to the principle of least privilege.</p>
<pre><code class="lang-csharp">sudo -i -u mywebsiteuser
</code></pre>
<p>You are now operating as <code>mywebsiteuser</code>. Any files created will be owned by this user.</p>
<h4 id="heading-42-create-an-ssh-key">4.2 Create an SSH Key</h4>
<pre><code class="lang-csharp">ssh-keygen -t ed25519 -C <span class="hljs-string">"mywebsiteuser_github_key"</span>
</code></pre>
<p><strong>Explanation:</strong></p>
<ul>
<li><p><code>ssh-keygen</code>: The command to generate SSH key pairs.</p>
</li>
<li><p><code>-t ed25519</code>: Specifies the type of key to create. <code>ed25519</code> is a modern, highly secure, and efficient elliptic curve algorithm, generally preferred over RSA for new keys.</p>
</li>
<li><p><code>-C "mywebsiteuser_github_key"</code>: Adds a comment to the public key. This is helpful for identifying the key's purpose when you add it to GitHub or other services.</p>
</li>
</ul>
<p>You will be prompted for:</p>
<ul>
<li><p><strong>File in which to save the key:</strong> Press Enter to accept the default location (<code>/home/mywebsiteuser/.ssh/id_ed25519</code>).</p>
</li>
<li><p><strong>Passphrase:</strong> <strong>Use a passphrase if possible for better security.</strong> A passphrase adds an extra layer of protection, requiring you to enter it before the private key can be used. This protects your key if someone gains unauthorized access to your VPS. If you choose not to use one (e.g., for automated deployments where passphrase prompts are problematic), understand the increased risk.</p>
</li>
</ul>
<h4 id="heading-43-verify-key-generation-and-permissions">4.3 Verify Key Generation and Permissions</h4>
<p>After generation, verify the keys exist and have correct permissions:</p>
<pre><code class="lang-csharp">ls -al ~/.ssh/
</code></pre>
<p>You should see two files: <code>id_ed25519</code> (your private key) and <code>id_ed25519.pub</code> (your public key).</p>
<p><strong>Permission Check:</strong></p>
<ul>
<li><p>The private key (<code>id_ed25519</code>) <strong>must have permissions</strong> <code>600</code> (read/write for owner only). This is critical; if others can read your private key, your security is compromised.</p>
</li>
<li><p>The public key (<code>id_ed25519.pub</code>) should have <code>644</code> (read for owner, read for group/others).</p>
</li>
<li><p>The <code>.ssh</code> directory itself should have <code>700</code> (read/write/execute for owner only).</p>
</li>
</ul>
<p>If permissions are not correct, fix them immediately:</p>
<pre><code class="lang-csharp">chmod <span class="hljs-number">600</span> ~/.ssh/id_ed25519
chmod <span class="hljs-number">644</span> ~/.ssh/id_ed25519.pub
chmod <span class="hljs-number">700</span> ~/.ssh/ <span class="hljs-meta"># Ensure the .ssh directory itself is secure</span>
</code></pre>
<h4 id="heading-44-copy-the-public-key">4.4 Copy the Public Key</h4>
<p>You need to add your public key to GitHub (or your Git hosting service). Display the public key's content:</p>
<pre><code class="lang-csharp">cat ~/.ssh/id_ed25519.pub
</code></pre>
<p>Copy the entire output, which starts with <code>ssh-ed25519</code> and ends with the comment you provided.</p>
<h4 id="heading-45-add-the-public-key-to-github">4.5 Add the Public Key to GitHub</h4>
<ol>
<li><p>Log in to your GitHub account (your personal one that owns the repository or the organization that manages it).</p>
</li>
<li><p>Navigate to <strong>Settings -&gt; SSH and GPG keys -&gt; New SSH key</strong>.</p>
</li>
<li><p><strong>Title:</strong> Give it a meaningful name, like "VPS <code>mywebsiteuser</code> key" or "Production server <code>mywebsite</code> user".</p>
</li>
<li><p><strong>Key:</strong> Paste the public key you copied earlier into this field.</p>
</li>
<li><p>Click "Add SSH key".</p>
</li>
</ol>
<h4 id="heading-46-clone-the-repository-using-the-ssh-url">4.6 Clone the Repository Using the SSH URL</h4>
<p>Now, with the SSH key set up and added to GitHub, you can securely clone your repository. Remember to be operating as the <code>mywebsiteuser</code>.</p>
<pre><code class="lang-csharp">cd /<span class="hljs-keyword">var</span>/www/mywebsite <span class="hljs-meta"># Navigate to your app's web root directory</span>
git clone git@github.com:yourgithubuser/yourrepository.git .
</code></pre>
<p><strong>Explanation:</strong></p>
<ul>
<li><p><code>git@github.com:yourgithubuser/yourrepository.git</code>: This is the <strong>SSH URL</strong> for your GitHub repository. You can find this URL on your repository's page on GitHub (click the "Code" button and select "SSH").</p>
</li>
<li><p><code>.</code>: The dot at the end instructs Git to clone the repository into the <em>current directory</em> (<code>/var/www/mywebsite</code>), rather than creating a new subdirectory.</p>
</li>
</ul>
<h3 id="heading-5-inject-environment-variables">5. Inject Environment Variables</h3>
<p>Docker Compose allows you to inject environment variables into your containers, which is a standard way to manage configuration that varies between environments (e.g., database connection strings, API keys). The <code>.env</code> file is a convenient way to manage these variables locally or on your server.</p>
<h4 id="heading-51-create-a-env-file">5.1 Create a <code>.env</code> File</h4>
<p>Navigate to your project's root directory on the VPS (<code>/var/www/mywebsite</code>):</p>
<pre><code class="lang-csharp">cd /<span class="hljs-keyword">var</span>/www/mywebsite
touch .env
</code></pre>
<p><strong>Explanation:</strong></p>
<ul>
<li><code>touch .env</code>: Creates an empty file named <code>.env</code>. This file should be placed at the same level as your <code>docker-compose.yml</code> file.</li>
</ul>
<h4 id="heading-52-add-your-variables-to-env">5.2 Add Your Variables to <code>.env</code></h4>
<p>Open the <code>.env</code> file using a text editor (e.g., <code>nano</code> or <code>vim</code>):</p>
<pre><code class="lang-csharp">nano .env
</code></pre>
<p>Inside the <code>.env</code> file, add your environment variables in a <code>KEY=VALUE</code> format, one per line. For example:</p>
<pre><code class="lang-csharp">ASPNETCORE_ENVIRONMENT=Production
CONNECTION_STRINGS__DEFAULTCONNECTION=Server=my_db_server;Database=mydb;User Id=myuser;Password=mypassword;
API_KEY=your_secret_api_key_here
</code></pre>
<p><strong>Security Note:</strong> The <code>.env</code> file on your VPS will contain sensitive information. Ensure its permissions are strict (e.g., <code>chmod 600 .env</code> if it's not already, though <code>touch</code> usually creates it with appropriate user-only write access by default). <strong>Never commit your</strong> <code>.env</code> file to your Git repository! Add it to your <code>.gitignore</code> file.</p>
<h3 id="heading-6-deploy-your-docker-compose-application">6. Deploy Your Docker Compose Application</h3>
<p>With Docker installed, the repository cloned, and environment variables configured, you're ready to bring up your application.</p>
<h4 id="heading-61-navigate-to-your-project-directory">6.1 Navigate to Your Project Directory</h4>
<pre><code class="lang-csharp">cd /<span class="hljs-keyword">var</span>/www/mywebsite
</code></pre>
<h4 id="heading-62-build-and-run-with-docker-compose">6.2 Build and Run with Docker Compose</h4>
<p>This command will read your <code>docker-compose.yml</code> file, build any necessary Docker images, and start your services.</p>
<pre><code class="lang-csharp">docker-compose up -d --build
</code></pre>
<p><strong>Explanation of the command:</strong></p>
<ul>
<li><p><code>docker-compose up</code>: This command starts the services defined in your <code>docker-compose.yml</code> file. Docker Compose will automatically create networks, volumes, and containers as specified.</p>
</li>
<li><p><code>-d</code> (detached mode): This is crucial for production deployments. It runs your containers in the background, freeing up your terminal immediately. Without <code>-d</code>, your terminal would be attached to the container logs, and closing the terminal would stop the containers.</p>
</li>
<li><p><code>--build</code>: This forces Docker Compose to rebuild your images before starting the containers. This is important if you've made changes to your <code>Dockerfile</code> or your application's code and want to ensure the latest version is deployed. If you're using pre-built images from a container registry (e.g., Docker Hub, Azure Container Registry), you might omit this flag and use <code>docker-compose pull</code> first to download the latest images. For local builds from source code, <code>--build</code> is essential.</p>
</li>
</ul>
<h4 id="heading-63-verify-your-containers">6.3 Verify Your Containers</h4>
<p>After running <code>docker-compose up -d --build</code>, you should verify that your containers are running as expected.</p>
<pre><code class="lang-csharp">docker ps
</code></pre>
<p><strong>Explanation:</strong></p>
<ul>
<li><code>docker ps</code>: Lists all currently running Docker containers.</li>
</ul>
<p>You should see your web application container (e.g., <code>mywebsite-webapp</code>) and any other services (like a database container) listed with their <code>STATUS</code> as <code>Up</code> and their <code>PORTS</code> mapping. For example:</p>
<pre><code class="lang-csharp">CONTAINER ID   IMAGE                COMMAND               CREATED         STATUS         PORTS                     NAMES
&lt;id&gt;           mywebsite-webapp     <span class="hljs-string">"dotnet Mywebsite.dll"</span>  <span class="hljs-number">2</span> minutes ago   Up <span class="hljs-number">2</span> minutes   <span class="hljs-number">0.0</span><span class="hljs-number">.0</span><span class="hljs-number">.0</span>:<span class="hljs-number">8080</span>-&gt;<span class="hljs-number">80</span>/tcp      mywebsite_webapp_1
</code></pre>
<p>Pay close attention to the <code>PORTS</code> column. This shows which port on your VPS (e.g., <code>8080</code>) is mapped to which port inside your container (e.g., <code>80</code>). Your Nginx reverse proxy will forward requests to the VPS host port.</p>
<h4 id="heading-64-check-logs-optional-but-recommended-for-debugging">6.4 Check Logs (Optional but Recommended for Debugging)</h4>
<p>To ensure your application started successfully and to debug any issues, check the container logs:</p>
<pre><code class="lang-csharp">docker-compose logs -f webapp
</code></pre>
<p><strong>Explanation:</strong></p>
<ul>
<li><p><code>docker-compose logs</code>: Displays the logs from your services.</p>
</li>
<li><p><code>-f</code> (follow): Streams new logs in real-time, similar to <code>tail -f</code>. This is extremely useful for monitoring startup or diagnosing runtime errors.</p>
</li>
<li><p><code>webapp</code>: Replace <code>webapp</code> with the service name of your web application as defined in your <code>docker-compose.yml</code> file.</p>
</li>
</ul>
<p>Press <code>Ctrl+C</code> to exit the log stream. Look for messages indicating your application has started listening on its internal port (e.g., "Now listening on: <a target="_blank" href="https://www.google.com/search?q=http://%5B::%5D:80">http://[::]:80</a>").</p>
<h3 id="heading-7-configure-your-website-for-internet-access-nginx-reverse-proxy">7. Configure Your Website for Internet Access (Nginx Reverse Proxy)</h3>
<p>Even though your Docker container is running, it's typically only accessible on the VPS itself (e.g., via <code>localhost:8080</code>). To make your application available to the internet via your domain name, you need a reverse proxy. Nginx is a popular, high-performance choice for this role. It will sit in front of your Dockerized application, handle incoming web requests, and forward them to your running Docker container.</p>
<h4 id="heading-71-install-nginx">7.1 Install Nginx</h4>
<p>If Nginx is not already installed:</p>
<pre><code class="lang-csharp">sudo apt update
sudo apt install nginx -y
sudo systemctl enable --now nginx
</code></pre>
<p><strong>Explanation:</strong></p>
<ul>
<li><code>sudo systemctl enable --now nginx</code>: Enables Nginx to start on boot and starts it immediately.</li>
</ul>
<h4 id="heading-72-create-nginx-configuration-file">7.2 Create Nginx Configuration File</h4>
<p>Nginx configurations for individual websites are usually placed in <code>/etc/nginx/sites-available/</code>. You'll create a new file for your website.</p>
<pre><code class="lang-csharp">sudo nano /etc/nginx/sites-available/mywebsite
</code></pre>
<p>Paste the following configuration. <strong>Remember to replace</strong> <code>your_domain.com</code> with your actual domain name and adjust the <code>proxy_pass</code> port if your Dockerized application isn't listening on port <code>8080</code> internally.</p>
<pre><code class="lang-csharp"><span class="hljs-meta"># /etc/nginx/sites-available/mywebsite</span>

server {
    listen <span class="hljs-number">80</span>;
    listen [::]:<span class="hljs-number">80</span>; <span class="hljs-meta"># Listen on IPv6 as well</span>
    server_name your_domain.com www.your_domain.com; <span class="hljs-meta"># Replace with your actual domain(s)</span>

    location / {
        <span class="hljs-meta"># Forward requests to your Dockerized application</span>
        proxy_pass http:<span class="hljs-comment">//localhost:8080; # Or the IP of your Docker host if not localhost</span>
        proxy_http_version <span class="hljs-number">1.1</span>;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection <span class="hljs-string">"upgrade"</span>;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme; <span class="hljs-meta"># Crucial for ASP.NET Core apps behind a proxy</span>
        proxy_cache_bypass $http_upgrade;
        <span class="hljs-meta"># Disable buffering for WebSockets/Server-Sent Events <span class="hljs-meta-keyword">if</span> your app uses them</span>
        <span class="hljs-meta"># proxy_buffering off;</span>
    }

    <span class="hljs-meta"># Optional: Add <span class="hljs-meta-keyword">error</span> pages or other configurations as needed</span>
    <span class="hljs-meta"># error_page 500 502 503 504 /50x.html;</span>
    <span class="hljs-meta"># location = /50x.html {</span>
    <span class="hljs-meta">#     root /usr/share/nginx/html;</span>
    <span class="hljs-meta"># }</span>
}
</code></pre>
<p><strong>Explanation of Nginx Directives:</strong></p>
<ul>
<li><p><code>listen 80;</code>: Nginx will listen for incoming HTTP requests on port 80.</p>
</li>
<li><p><code>listen [::]:80;</code>: Similar to above, but for IPv6 traffic.</p>
</li>
<li><p><code>server_name your_domain.com www.your_domain.com;</code>: This tells Nginx which domain names this server block should respond to. It's crucial for Nginx to route requests correctly, especially when hosting multiple sites on one server.</p>
</li>
<li><p><code>location / { ... }</code>: This block defines how Nginx handles requests for the root URL (<code>/</code>) and its subpaths.</p>
</li>
<li><p><code>proxy_pass http://localhost:8080;</code>: This is the core of the reverse proxy. It tells Nginx to forward all requests received by this server block to your Dockerized application, which is running on <code>localhost</code> (the VPS itself) at port <code>8080</code> (the host port you mapped in <code>docker-compose.yml</code>).</p>
</li>
<li><p><code>proxy_http_version 1.1;</code>: Specifies the HTTP protocol version for the proxy connection.</p>
</li>
<li><p><code>proxy_set_header ...</code>: These directives pass important client information (like original host, real IP address, and protocol scheme) from Nginx to your backend application. This is vital for applications like ASP.NET Core that might need to know the original request's scheme (HTTP vs. HTTPS) or the client's actual IP address, as they see Nginx as the direct client otherwise.</p>
</li>
</ul>
<h4 id="heading-73-create-a-symbolic-link">7.3 Create a Symbolic Link</h4>
<p>To enable your new Nginx configuration, you need to create a symbolic link from <code>sites-available</code> (where configurations are stored) to <code>sites-enabled</code> (where Nginx looks for active configurations).</p>
<pre><code class="lang-csharp">sudo ln -s /etc/nginx/sites-available/mywebsite /etc/nginx/sites-enabled/
</code></pre>
<p><strong>Explanation:</strong></p>
<ul>
<li><p><code>ln -s</code>: Creates a symbolic link (a shortcut).</p>
</li>
<li><p><code>/etc/nginx/sites-available/mywebsite</code>: The source file (your configuration).</p>
</li>
<li><p><code>/etc/nginx/sites-enabled/</code>: The destination directory where the link will be created.</p>
</li>
</ul>
<h4 id="heading-74-test-nginx-configuration">7.4 Test Nginx Configuration</h4>
<p>Before restarting Nginx, always test your configuration for syntax errors. This prevents Nginx from failing to start due to a simple typo.</p>
<pre><code class="lang-csharp">sudo nginx -t
</code></pre>
<p>You should see output similar to: <code>nginx: the configuration file /etc/nginx/nginx.conf syntax is ok</code> and <code>nginx: configuration file /etc/nginx/nginx.conf test is successful</code>. If there are any errors, fix them in your configuration file before proceeding.</p>
<h4 id="heading-75-restart-nginx">7.5 Restart Nginx</h4>
<p>Apply the new configuration by restarting Nginx. A restart is needed for Nginx to load the new server block.</p>
<pre><code class="lang-csharp">sudo systemctl restart nginx
</code></pre>
<p>If Nginx fails to restart or you encounter issues, use <code>sudo systemctl status nginx</code> to view the service's status and error logs for debugging.</p>
<h4 id="heading-76-set-your-domain-dns-to-point-to-your-vps">7.6 Set Your Domain DNS to Point to Your VPS</h4>
<p>This is done outside of your VPS, through your domain name registrar or DNS provider.</p>
<ul>
<li><p><strong>Open your domain setting from your domain provider.</strong> Log in to your domain registrar's website (e.g., GoDaddy, Namecheap, Cloudflare).</p>
</li>
<li><p><strong>Set the DNS manager.</strong> Locate the DNS management section for your domain.</p>
</li>
<li><p><strong>Adjust the domain name of the A record to point to your VPS.</strong></p>
<ul>
<li><p>You'll typically create an <code>A</code> record for your main domain (e.g., <code>your_domain.com</code>) pointing to your VPS's public IPv4 address.</p>
</li>
<li><p>You might also create a <code>CNAME</code> record for <code>www.your_domain.com</code> pointing to <code>your_domain.com</code>, or another <code>A</code> record directly to the IP.</p>
</li>
</ul>
</li>
<li><p><strong>Save the changes.</strong> DNS changes can take some time to propagate across the internet (anywhere from a few minutes to 48 hours), although typically it's much faster.</p>
</li>
</ul>
<p>Once DNS has propagated, accessing <code>http://your_domain.com</code> in a browser should now hit your Nginx server, which then forwards the request to your Dockerized application. You might still see "Welcome to nginx!" or experience issues if the default Nginx site is interfering (see troubleshooting below).</p>
<h3 id="heading-8-implement-ssl-with-certbot-lets-encrypt">8. Implement SSL with Certbot (Let's Encrypt)</h3>
<p>Securing your website with HTTPS (SSL/TLS) is non-negotiable for modern web applications. It encrypts communication between your users and your server, protects data integrity, and is a strong ranking signal for search engines. Let's Encrypt provides free, automated SSL certificates, and Certbot is the tool to manage them.</p>
<h4 id="heading-81-install-certbot">8.1 Install Certbot</h4>
<p>Certbot is often installed via Snap, a universal packaging system for Linux.</p>
<pre><code class="lang-csharp">sudo snap install core
sudo snap refresh core <span class="hljs-meta"># Ensures Snap core is up to date</span>
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot <span class="hljs-meta"># Create a symbolic link for easy access</span>
</code></pre>
<p><strong>Explanation:</strong></p>
<ul>
<li><p><code>snap install core</code>: Installs the Snap "core" components, which are foundational for running other snaps.</p>
</li>
<li><p><code>snap refresh core</code>: Updates the core snap.</p>
</li>
<li><p><code>snap install --classic certbot</code>: Installs Certbot. The <code>--classic</code> flag is needed because Certbot requires broad system access.</p>
</li>
<li><p><code>sudo ln -s /snap/bin/certbot /usr/bin/certbot</code>: Creates a symbolic link so you can run <code>certbot</code> directly from your PATH without needing to specify <code>/snap/bin/certbot</code>.</p>
</li>
</ul>
<h4 id="heading-82-obtain-and-install-ssl-certificate">8.2 Obtain and Install SSL Certificate</h4>
<p>Certbot has an Nginx plugin that can automatically configure Nginx for SSL.</p>
<pre><code class="lang-csharp">sudo certbot --nginx
</code></pre>
<p><strong>Explanation:</strong></p>
<ul>
<li><code>certbot --nginx</code>: This command tells Certbot to use its Nginx plugin to configure SSL.</li>
</ul>
<p><strong>Follow the prompts:</strong></p>
<ol>
<li><p>Certbot will ask for your email address for urgent renewal notices and security warnings.</p>
</li>
<li><p>Agree to the Let's Encrypt Terms of Service.</p>
</li>
<li><p>Choose whether to share your email with the Electronic Frontier Foundation (EFF).</p>
</li>
<li><p>Certbot will detect your Nginx configurations and list the domains it found. Select the numbers corresponding to <code>your_domain.com</code> and <code>www.your_domain.com</code>.</p>
</li>
<li><p>It will ask if you want to redirect HTTP traffic to HTTPS. <strong>Choose 2 (Redirect)</strong>. This is best practice as it ensures all traffic uses the secure HTTPS connection.</p>
</li>
</ol>
<p>Certbot will then automatically:</p>
<ul>
<li><p>Obtain the SSL certificates from Let's Encrypt.</p>
</li>
<li><p>Modify your <code>/etc/nginx/sites-available/mywebsite</code> file to include HTTPS listeners (port 443), redirect HTTP traffic (port 80) to HTTPS, and set up the correct <code>ssl_certificate</code> and <code>ssl_certificate_key</code> paths.</p>
</li>
<li><p>Configure automatic certificate renewal. Let's Encrypt certificates are valid for 90 days, and Certbot sets up a cron job or systemd timer to renew them automatically before they expire.</p>
</li>
</ul>
<p>After this, your website should be accessible via HTTPS! Try accessing <code>https://your_domain.com</code> in your browser.</p>
<h3 id="heading-9-fix-the-welcome-to-nginx-message-or-incorrect-site-loading">9. Fix the "Welcome to nginx!" Message or Incorrect Site Loading</h3>
<p>This typically happens if the default Nginx configuration file is taking precedence over your custom site configuration. Nginx serves the "Welcome to Nginx!" page from its default site.</p>
<h4 id="heading-91-inspect-sites-enabled">9.1 Inspect <code>sites-enabled</code></h4>
<p>First, let's see which Nginx site configurations are actually active:</p>
<pre><code class="lang-csharp">ls -l /etc/nginx/sites-enabled/
</code></pre>
<p>You will likely see something like this:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">default</span> -&gt; /etc/nginx/sites-available/<span class="hljs-keyword">default</span>
mywebsite -&gt; /etc/nginx/sites-available/mywebsite
</code></pre>
<p>If both <code>default</code> and <code>mywebsite</code> are symlinked here, Nginx has rules for determining which <code>server</code> block to use. If your custom <code>server_name</code> isn't an exact match, or if the <code>default_server</code> directive is used in the default config, it can pick the wrong one.</p>
<h4 id="heading-92-disable-the-default-nginx-site-recommended-approach">9.2 Disable the Default Nginx Site (Recommended Approach)</h4>
<p>This is the cleanest way to ensure your custom site configuration takes precedence.</p>
<pre><code class="lang-csharp">sudo unlink /etc/nginx/sites-enabled/<span class="hljs-keyword">default</span>
</code></pre>
<p><strong>Explanation:</strong></p>
<ul>
<li><code>unlink</code>: Removes a symbolic link. This command effectively disables the default Nginx site without deleting the original configuration file (<code>/etc/nginx/sites-available/default</code>).</li>
</ul>
<h4 id="heading-93-re-verify-and-correct-your-mywebsite-nginx-configuration">9.3 Re-verify and Correct Your <code>mywebsite</code> Nginx Configuration</h4>
<p>It's crucial that your <code>mywebsite</code> configuration (especially the <code>server_name</code> directive) is perfectly accurate for your domain(s).</p>
<pre><code class="lang-csharp">sudo nano /etc/nginx/sites-available/mywebsite
</code></pre>
<p>Ensure the <code>server_name</code> directives are exact matches for your domain(s). After Certbot runs, your file should look something like this, with both HTTP and HTTPS blocks:</p>
<pre><code class="lang-csharp"><span class="hljs-meta"># /etc/nginx/sites-available/mywebsite</span>

<span class="hljs-meta"># HTTP block - will be redirected by Certbot to HTTPS</span>
server {
    listen <span class="hljs-number">80</span>;
    listen [::]:<span class="hljs-number">80</span>;
    server_name mywebsite.id www.mywebsite.id; <span class="hljs-meta"># &lt;-- MUST MATCH YOUR DOMAIN EXACTLY</span>

    <span class="hljs-meta"># Certbot will inject the redirect here after you run it for this domain</span>
    <span class="hljs-meta"># And also the location block for .well-known/acme-challenge</span>
    <span class="hljs-meta"># For example, it adds:</span>
    <span class="hljs-meta"># return 301 https://$host$request_uri;</span>
    <span class="hljs-meta"># (Other Certbot-specific configurations will also be here)</span>
}

<span class="hljs-meta"># HTTPS block - Certbot creates/modifies this</span>
server {
    listen <span class="hljs-number">443</span> ssl http2;
    listen [::]:<span class="hljs-number">443</span> ssl http2;
    server_name mywebsite.id www.mywebsite.id; <span class="hljs-meta"># &lt;-- MUST MATCH YOUR DOMAIN EXACTLY</span>

    ssl_certificate /etc/letsencrypt/live/mywebsite.id/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/mywebsite.id/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    include /etc/letsencrypt/ssl-dhparams.conf;

    location / {
        proxy_pass http:<span class="hljs-comment">//localhost:8080; # Points to your mywebsite.web Docker container</span>
        proxy_http_version <span class="hljs-number">1.1</span>;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection <span class="hljs-string">"upgrade"</span>;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme; <span class="hljs-meta"># Crucial for ASP.NET Core apps behind a proxy</span>
        proxy_cache_bypass $http_upgrade;
    }
}
</code></pre>
<p>Make sure you have both the <code>http://</code> and <code>https://</code> server blocks for your domain. Certbot creates the HTTPS one and modifies the HTTP one to redirect.</p>
<h4 id="heading-94-test-nginx-configuration-again">9.4 Test Nginx Configuration Again</h4>
<pre><code class="lang-csharp">sudo nginx -t
</code></pre>
<p>This command checks for syntax errors in all your Nginx configuration files. If there are any, it will tell you where they are. Fix them before proceeding.</p>
<h4 id="heading-95-reload-nginx">9.5 Reload Nginx</h4>
<p>After making changes to Nginx configuration files, use <code>reload</code> to apply them without interrupting service for other domains (if you have any). If <code>reload</code> doesn't work, <code>restart</code> is a more forceful option.</p>
<pre><code class="lang-csharp">sudo systemctl reload nginx
</code></pre>
<h4 id="heading-after-these-steps">After These Steps:</h4>
<ul>
<li><p><strong>Clear your browser cache:</strong> Sometimes browsers cache redirects or old content. A hard refresh (<code>Ctrl+F5</code> or <code>Cmd+Shift+R</code>) or clearing your browser's cache can help ensure you're seeing the latest content from your server.</p>
</li>
<li><p><strong>Try accessing your website again.</strong> It should now load correctly via HTTPS.</p>
</li>
</ul>
<h3 id="heading-conclusion">Conclusion:</h3>
<p>You have successfully deployed your Dockerized web application to a Linux VPS! By following these steps, you've established a secure, organized, and scalable environment for your application. This setup leverages Docker for containerization, Nginx for efficient reverse proxying and load balancing, and Let's Encrypt for essential SSL security, all adhering to industry best practices for robust deployment.</p>
]]></content:encoded></item><item><title><![CDATA[Initial VPS Configuration Guide: Building a solid foundation for your web application]]></title><description><![CDATA[Using a Virtual Private Server (VPS) offers a powerful and budget-friendly way to gain full control over your hosting environment. Whether you're making your first deployment or migrating from shared hosting to something more robust, a proper initial...]]></description><link>https://krisoncode.com/initial-vps-configuration-guide-building-a-solid-foundation-for-your-web-application</link><guid isPermaLink="true">https://krisoncode.com/initial-vps-configuration-guide-building-a-solid-foundation-for-your-web-application</guid><category><![CDATA[vps]]></category><category><![CDATA[deployment]]></category><category><![CDATA[Devops]]></category><category><![CDATA[Linux]]></category><category><![CDATA[Web Development]]></category><dc:creator><![CDATA[Kristiadhy]]></dc:creator><pubDate>Wed, 09 Jul 2025 09:55:48 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1752054834915/0587ab99-bac5-4974-8c45-901cf61a69e8.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Using a Virtual Private Server (VPS) offers a powerful and budget-friendly way to gain full control over your hosting environment. Whether you're making your first deployment or migrating from shared hosting to something more robust, a proper initial setup makes all the difference. This guide will walk you through getting your new VPS ready—secure, optimized, and prepared for deploying your applications, especially if you're aiming for a Dockerized setup. If you aim to deploy your web app without using Docker, check out this guideline <a target="_blank" href="https://kristiadhy.hashnode.dev/guide-to-hosting-net-8-aspnet-core-and-blazor-web-assembly-on-a-linux-vps">Host .NET 8 Asp Net Core and Blazor on Linux VPS</a></p>
<p>You can skip some steps if you want to and choose what's best for you.</p>
<h3 id="heading-rent-your-virtual-private-server-vps">Rent Your Virtual Private Server (VPS).</h3>
<p>The first step is to choose a reputable hosting provider. Popular options include DigitalOcean, Vultr, and Hetzner. When selecting a plan, consider your application's resource requirements:</p>
<ul>
<li><p><strong>CPU:</strong> More cores generally translate to better performance, crucial if you anticipate significant traffic or compute-intensive tasks.</p>
</li>
<li><p><strong>RAM:</strong> Ample memory ensures your applications run smoothly, preventing slowdowns and crashes under load.</p>
</li>
<li><p><strong>Storage:</strong> Opt for <strong>SSD</strong> (Solid State Drive) storage for significantly faster read/write speeds, which benefits database operations and application loading times. Ensure you have enough capacity for your application files, databases, and any future growth.</p>
</li>
<li><p><strong>Bandwidth:</strong> Important if your application handles a large volume of data transfers, such as file downloads, streaming media, or high traffic.</p>
</li>
</ul>
<p>For a small application or testing environment, a basic plan might suffice. However, for larger or production-ready applications, investing in a more powerful plan from the start can save you headaches down the line and ensure a scalable foundation.</p>
<h3 id="heading-secure-your-root-account">Secure Your Root Account.</h3>
<p>Upon initial login to your new VPS (usually as the <code>root</code> user), the very first thing you should do is change the default password. This is a critical security measure as default passwords are often weak or publicly known.</p>
<p>To change it, simply type:</p>
<pre><code class="lang-csharp">passwd
</code></pre>
<p>You'll be prompted to enter your new password twice. Choose a strong, unique password that combines uppercase and lowercase letters, numbers, and symbols.</p>
<h3 id="heading-create-a-non-root-user">Create a Non-Root User</h3>
<p>Working directly as the <code>root</code> user is a significant security risk. The <code>root</code> user has absolute control over the system, and a single misplaced command can lead to irreversible damage. To mitigate this, it's a best practice to create a new, unprivileged user for your day-to-day operations and grant it <code>sudo</code> privileges for administrative tasks. This aligns with the principle of "least privilege" and contributes to a more secure and maintainable system.</p>
<p>To create a new user (replace <code>myusername</code> with your desired username):</p>
<pre><code class="lang-csharp">adduser myusername
</code></pre>
<p>Follow the prompts to set a strong password for this new user and fill in any additional information (you can usually press Enter to skip these if not needed).</p>
<p>Next, grant this new user <code>sudo</code> permissions, allowing them to execute commands with <code>root</code> privileges when necessary, by prefixing the command with <code>sudo</code>.</p>
<pre><code class="lang-csharp">usermod -aG sudo myusername
</code></pre>
<p>Now, you can log out of the <code>root</code> user and log in as <code>myusername</code>. From this point forward, you'll use <code>sudo</code> for any administrative operations.</p>
<h3 id="heading-enhance-security-with-ssh-keys">Enhance Security with SSH Keys.</h3>
<p>After changing your password, the next level of security involves disabling password-based SSH logins entirely and exclusively using SSH keys. SSH keys provide a much stronger authentication mechanism, making brute-force password attacks virtually impossible. This is a fundamental step in securing your server.</p>
<p><strong>Step-by-Step SSH Key Setup:</strong></p>
<ol>
<li><p><strong>Generate an SSH key on your local machine:</strong> Open your local terminal and generate a new SSH key pair. <code>ed25519</code> is the modern and recommended algorithm due to its strong security and smaller key sizes, but <code>rsa</code> is also an option.</p>
<pre><code class="lang-csharp"> ssh-keygen -t ed25519
</code></pre>
<p> Press <code>Enter</code> when prompted for a file to save the key (it will default to <code>~/.ssh/id_ed25519</code>) and when asked for a passphrase. While a passphrase adds an extra layer of security, it means you'll need to enter it every time you use the key. For convenience, many users opt not to set one for their primary key, but consider it for higher-security scenarios.</p>
</li>
<li><p><strong>Copy the public key to your server:</strong> This command securely copies your public key (<code>id_</code><a target="_blank" href="http://ed25519.pub"><code>ed25519.pub</code></a>) to the <code>authorized_keys</code> file on your VPS, allowing you to log in with your key. Replace <code>myusername</code> and <code>your-server-ip</code> with your actual details.</p>
<pre><code class="lang-csharp"> ssh-copy-id myusername@your-server-ip
</code></pre>
<p> You will be asked for your <code>myusername</code>'s password one last time.</p>
</li>
<li><p><strong>Test your SSH key login:</strong> Before proceeding, try logging in to your VPS using your new user and SSH key to ensure it works correctly.</p>
<pre><code class="lang-csharp"> ssh myusername@your-server-ip
</code></pre>
<p> If successful, you should be logged in without being prompted for a password.</p>
</li>
<li><p><strong>Disable password login on the server:</strong> Once you've confirmed SSH key login works, edit the SSH daemon configuration file to disallow password authentication. This significantly hardens your server against unauthorized access.</p>
<pre><code class="lang-csharp"> sudo nano /etc/ssh/sshd_config
</code></pre>
<p> Find the line <code>PasswordAuthentication yes</code> and change it to:</p>
<pre><code class="lang-csharp"> PasswordAuthentication no
</code></pre>
<p> You might also want to ensure <code>PermitRootLogin no</code> is set to prevent direct root logins via SSH, forcing you to use your non-root user and then <code>sudo</code> if needed.</p>
<p> Save and exit nano (Ctrl+O, Enter, Ctrl+X).</p>
</li>
<li><p><strong>Restart the SSH service:</strong> Apply the changes by restarting the SSH service.</p>
<pre><code class="lang-csharp"> sudo systemctl restart ssh
</code></pre>
<p> Now, your server is much more secure, relying solely on cryptographic SSH keys for authentication.</p>
</li>
</ol>
<h3 id="heading-install-and-configure-ufw-uncomplicated-firewall">Install and Configure UFW (Uncomplicated Firewall).</h3>
<p>A firewall is your server's first line of defense, controlling what network traffic is allowed in and out. UFW (Uncomplicated Firewall) is a user-friendly front-end for <code>iptables</code>, making it easier to manage firewall rules. It's critical to configure your firewall before deploying any applications.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text"><strong>Crucial Warning:</strong> Be extremely careful to allow SSH access <strong>before</strong> enabling UFW, or you risk locking yourself out of your VPS.</div>
</div>

<p>Here's a safe baseline configuration, ideal for web applications:</p>
<pre><code class="lang-csharp">sudo ufw <span class="hljs-keyword">default</span> deny incoming       <span class="hljs-meta"># Deny all incoming connections by default</span>
sudo ufw <span class="hljs-keyword">default</span> allow outgoing      <span class="hljs-meta"># Allow all outgoing connections by default</span>
sudo ufw allow OpenSSH               <span class="hljs-meta"># Allow SSH connections (port 22)</span>
sudo ufw allow <span class="hljs-number">80</span>/tcp                <span class="hljs-meta"># Allow HTTP traffic (port 80)</span>
sudo ufw allow <span class="hljs-number">443</span>/tcp               <span class="hljs-meta"># Allow HTTPS traffic (port 443)</span>
sudo ufw enable                      <span class="hljs-meta"># Enable the firewall</span>
</code></pre>
<p>You'll be asked to confirm enabling the firewall; type <code>y</code> and press Enter.</p>
<p>To verify your firewall's status and rules:</p>
<pre><code class="lang-csharp">sudo ufw status verbose
</code></pre>
<p>This setup allows essential services while blocking all other unsolicited incoming connections, significantly reducing your server's attack surface.</p>
<h3 id="heading-set-the-correct-timezone-and-locale">Set the Correct Timezone and Locale.</h3>
<p>Proper timezone and locale settings are essential for accurate logging, scheduling tasks, and ensuring your applications behave as expected across different geographical locations.</p>
<p><strong>Timezone Configuration:</strong></p>
<p>Set your server's timezone. For example, if you are in Jakarta, Indonesia, you'd set it to <code>Asia/Jakarta</code>.</p>
<pre><code class="lang-csharp">sudo timedatectl <span class="hljs-keyword">set</span>-timezone Asia/Jakarta
</code></pre>
<p>Verify the change:</p>
<pre><code class="lang-csharp">timedatectl
</code></pre>
<p>This command will display current system time, RTC time, and your configured timezone.</p>
<p><strong>Locale Configuration:</strong></p>
<p>The locale determines the language, character encoding, and cultural conventions for your system. For most English-speaking systems, <code>en_US.UTF-8</code> is a common and robust choice.</p>
<p>Check your current locale:</p>
<pre><code class="lang-csharp">locale
</code></pre>
<p>If you need to set a new one:</p>
<pre><code class="lang-csharp">sudo update-locale LANG=en_US.UTF<span class="hljs-number">-8</span>
</code></pre>
<p>You can list all available locales with:</p>
<pre><code class="lang-csharp">locale -a
</code></pre>
<p>After changing the locale, it's best to log out and log back in to ensure the changes are fully applied to your session.</p>
<h3 id="heading-enable-ssh-rate-limiting-with-fail2ban">Enable SSH Rate Limiting with Fail2ban.</h3>
<p>Fail2ban is a powerful intrusion prevention framework that scans log files (like those for SSH, web servers, etc.) for repeated failed login attempts and automatically bans the offending IP addresses for a specified period. This is an excellent defense against brute-force attacks.</p>
<p><strong>Installation:</strong></p>
<pre><code class="lang-csharp">sudo apt update
sudo apt install fail2ban -y
</code></pre>
<p><strong>Basic Configuration:</strong></p>
<ol>
<li><p>Copy the default configuration file to a local override. This is a best practice, as it ensures your custom settings won't be overwritten during future <code>fail2ban</code> package updates.</p>
<pre><code class="lang-csharp"> sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
</code></pre>
</li>
<li><p>Edit the local configuration file:</p>
<pre><code class="lang-csharp"> sudo nano /etc/fail2ban/jail.local
</code></pre>
<p> Look for the <code>[sshd]</code> section. Ensure it is enabled and review the <code>maxretry</code> and <code>bantime</code> settings:</p>
<p> Ini, TOML</p>
<pre><code class="lang-csharp"> [<span class="hljs-meta">sshd</span>]
 enabled = <span class="hljs-literal">true</span>
 port = ssh
 filter = sshd
 logpath = %(sshd_log)s
 maxretry = <span class="hljs-number">5</span>   ; How many failed attempts allowed before banning
 bantime = <span class="hljs-number">1</span>h   ; <span class="hljs-function">How <span class="hljs-keyword">long</span> to block the <span class="hljs-title">IP</span> (<span class="hljs-params">e.g., <span class="hljs-number">1</span>h <span class="hljs-keyword">for</span> <span class="hljs-number">1</span> hour, <span class="hljs-number">1</span>d <span class="hljs-keyword">for</span> <span class="hljs-number">1</span> day</span>)</span>
</code></pre>
<p> The <code>port</code> setting typically defaults to <code>ssh</code> (which resolves to port 22). If you've changed your SSH port, update this accordingly. <code>maxretry</code> defines the number of failed attempts before a ban, and <code>bantime</code> specifies the duration of the ban.</p>
<p> Save and exit nano.</p>
</li>
<li><p><strong>Restart and Enable Fail2ban:</strong></p>
<pre><code class="lang-csharp"> sudo systemctl restart fail2ban
 sudo systemctl enable fail2ban <span class="hljs-meta"># Ensure it starts on boot</span>
</code></pre>
</li>
<li><p><strong>Check Status:</strong></p>
<pre><code class="lang-csharp"> sudo fail2ban-client status
 sudo fail2ban-client status sshd
</code></pre>
<p> These commands will show you the active jails and any currently banned IPs for the SSH service. Fail2ban will now diligently monitor <code>/var/log/auth.log</code> (or your configured log path) and automatically ban repeat SSH failures, significantly enhancing your server's security posture.</p>
</li>
</ol>
<h3 id="heading-install-malwarerootkit-scanners">Install Malware/Rootkit Scanners.</h3>
<p>While your primary defense should be proactive security measures, having tools to detect compromises is also vital. <code>rkhunter</code> (Rootkit Hunter) is a popular utility for scanning for rootkits, backdoors, and other potential vulnerabilities.</p>
<pre><code class="lang-csharp">sudo apt install rkhunter -y &amp;&amp; \
sudo rkhunter --update &amp;&amp; \
sudo rkhunter --propupd &amp;&amp; \
sudo rkhunter --check
</code></pre>
<ul>
<li><p><code>--update</code>: Updates the data files used by <code>rkhunter</code>.</p>
</li>
<li><p><code>--propupd</code>: Updates the file properties database. You should run this after a fresh install or major system updates to prevent false positives.</p>
</li>
<li><p><code>--check</code>: Performs the actual scan.</p>
</li>
</ul>
<p>You should re-run <code>sudo rkhunter --check</code> regularly as part of your server maintenance routine to check for new issues.</p>
<h3 id="heading-uninstall-default-applications-if-unnecessary">Uninstall Default Applications (If Unnecessary).</h3>
<p>Many VPS providers pre-install common application stacks like LAMP (Linux, Apache, MySQL, PHP) to get users up and running quickly. However, if you plan to deploy your applications using Docker, these pre-installed components are often redundant and can introduce conflicts or unnecessary attack surfaces. Removing them provides a cleaner environment and ensures Docker has full control over application orchestration.</p>
<p>Here's how to remove common default software on an Ubuntu-based VPS:</p>
<pre><code class="lang-csharp"><span class="hljs-meta"># Stop and Remove Apache</span>
sudo systemctl stop apache2
sudo apt <span class="hljs-keyword">remove</span> --purge apache2 apache2-utils apache2-bin apache2<span class="hljs-number">.2</span>-common

<span class="hljs-meta"># Stop and Remove MySQL (<span class="hljs-meta-keyword">if</span> installed directly, not in Docker)</span>
sudo systemctl stop mysql
sudo apt <span class="hljs-keyword">remove</span> --purge mysql-server mysql-client mysql-common

<span class="hljs-meta"># Stop and Remove MariaDB (<span class="hljs-meta-keyword">if</span> installed directly, not in Docker)</span>
sudo systemctl stop mariadb
sudo apt <span class="hljs-keyword">remove</span> --purge mariadb-server mariadb-client

<span class="hljs-meta"># Remove PHP and its modules (<span class="hljs-meta-keyword">if</span> installed directly)</span>
sudo apt <span class="hljs-keyword">remove</span> --purge php*

<span class="hljs-meta"># Clean up any residual packages and orphaned dependencies</span>
sudo apt autoremove
sudo apt autoclean
</code></pre>
<p><strong>How to check what's installed:</strong></p>
<p>If you're unsure what services are running or installed, you can use <code>dpkg -l</code> to list packages and <code>grep</code> to filter for specific ones:</p>
<pre><code class="lang-csharp">dpkg -l | grep apache
dpkg -l | grep mysql
dpkg -l | grep php
dpkg -l | grep mariadb
</code></pre>
<p>Remove anything that's not explicitly needed for your Dockerized environment. This contributes to a "clean architecture" for your server itself, reducing clutter and potential vulnerabilities.</p>
<h3 id="heading-set-up-your-hostname">Set Up Your Hostname.</h3>
<p>When you first provision your VPS, it's often assigned a generic hostname. It's good practice to map this properly within your system for easier identification and to ensure services that rely on hostname resolution function correctly.</p>
<ol>
<li><p><strong>Check your current hostname:</strong></p>
<pre><code class="lang-csharp"> hostname
</code></pre>
</li>
<li><p><strong>Edit your</strong> <code>/etc/hosts</code> file: This file maps hostnames to IP addresses locally on your server.</p>
<pre><code class="lang-csharp"> sudo nano /etc/hosts
</code></pre>
<p> Look for a line that might resemble <code>127.0.1.1 oldhostname</code> and update it to reflect your VPS provider's assigned hostname, or a custom one if you prefer. For example:</p>
<pre><code class="lang-csharp"> <span class="hljs-number">127.0</span><span class="hljs-number">.1</span><span class="hljs-number">.1</span>   your-vps-hostname
</code></pre>
<p> Also, ensure you have the standard <a target="_blank" href="http://localhost">localhost</a> entry:</p>
<pre><code class="lang-csharp"> <span class="hljs-number">127.0</span><span class="hljs-number">.0</span><span class="hljs-number">.1</span>   localhost
</code></pre>
<p> So, a typical <code>/etc/hosts</code> file will look something like this:</p>
<pre><code class="lang-csharp"> <span class="hljs-number">127.0</span><span class="hljs-number">.0</span><span class="hljs-number">.1</span>   localhost
 <span class="hljs-number">127.0</span><span class="hljs-number">.1</span><span class="hljs-number">.1</span>   your-vps-hostname
 <span class="hljs-meta"># The following lines are desirable for IPv6 capable hosts</span>
 ::<span class="hljs-number">1</span>     localhost ip6-localhost ip6-loopback
 ff02::<span class="hljs-number">1</span> ip6-allnodes
 ff02::<span class="hljs-number">2</span> ip6-allrouters
</code></pre>
 <div data-node-type="callout">
 <div data-node-type="callout-emoji">💡</div>
 <div data-node-type="callout-text"><strong>Important Note:</strong> This <code>/etc/hosts</code> mapping only affects local name resolution within your VPS. External clients will still need to use your domain name (with proper DNS records configured at your domain registrar) to reach your server.</div>
 </div>

<p> Save and exit nano (Ctrl+O, Enter, Ctrl+X).</p>
</li>
</ol>
<h3 id="heading-install-nginx-reverse-proxy-for-dockerized-apps">Install NGINX (Reverse Proxy for Dockerized Apps).</h3>
<p>NGINX is an incredibly versatile and high-performance web server that excels as a reverse proxy. For modern, Docker-based application deployments, NGINX is almost indispensable.</p>
<p><strong>Why use NGINX?</strong></p>
<ul>
<li><p><strong>Reverse Proxy:</strong> It acts as a single entry point for all incoming web traffic, routing requests to the appropriate Docker containers based on rules you define. This decouples your application containers from direct public exposure, enhancing security.</p>
</li>
<li><p><strong>Load Balancing:</strong> NGINX can distribute incoming traffic across multiple instances of your application (e.g., multiple Docker containers), improving scalability and fault tolerance.</p>
</li>
<li><p><strong>Static File Serving:</strong> It's highly efficient at serving static assets (HTML, CSS, JavaScript, images), offloading this task from your application containers.</p>
</li>
<li><p><strong>SSL Termination:</strong> NGINX can handle SSL/TLS encryption and decryption, allowing your application containers to run on plain HTTP internally, simplifying their configuration.</p>
</li>
<li><p><strong>Security:</strong> By sitting in front of your application, NGINX can filter malicious requests and provide an additional layer of defense.</p>
</li>
</ul>
<p>In a Dockerized setup, NGINX often serves as the public-facing component, directing requests to your backend services running in containers. This aligns perfectly with a "clean architecture" by clearly separating concerns.</p>
<p><strong>Installation:</strong></p>
<pre><code class="lang-csharp">sudo apt update
sudo apt install nginx
</code></pre>
<p>After installation, verify that NGINX is running:</p>
<pre><code class="lang-csharp">sudo systemctl status nginx
</code></pre>
<p>You should see output indicating that the service is <code>active (running)</code>.</p>
<p>Enable NGINX to start automatically on boot:</p>
<pre><code class="lang-csharp">sudo systemctl enable nginx
</code></pre>
<p>To test if NGINX is working, open your VPS's IP address in a web browser. You should see the default NGINX welcome page, confirming that your web server is operational.</p>
]]></content:encoded></item><item><title><![CDATA[A Practical Guide to ASP.NET Core Configuration Best Practices.]]></title><description><![CDATA[What is application configuration?
In a .NET application, application configuration refers to the process of loading settings—typically key-value pairs—into your application or hosting environment. These settings can come from multiple sources, known...]]></description><link>https://krisoncode.com/a-practical-guide-to-aspnet-core-configuration-best-practices</link><guid isPermaLink="true">https://krisoncode.com/a-practical-guide-to-aspnet-core-configuration-best-practices</guid><category><![CDATA[asp.net core]]></category><category><![CDATA[.NET]]></category><category><![CDATA[backend]]></category><dc:creator><![CDATA[Kristiadhy]]></dc:creator><pubDate>Sat, 21 Jun 2025 08:06:53 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1750493102645/e4f0f031-11e8-4243-9c7b-942e41b63728.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-what-is-application-configuration">What is application configuration?</h2>
<p>In a .NET application, application configuration refers to the process of loading settings—typically key-value pairs—into your <strong>application or hosting environment</strong>. These settings can come from multiple sources, known as configuration providers.</p>
<h3 id="heading-host-and-application-configuration-in-aspnet-core">⚙️ Host and Application Configuration in ASP.NET Core</h3>
<p>ASP.NET Core separates configuration into two main categories:</p>
<h4 id="heading-1-host-configuration">1. <strong>Host Configuration</strong></h4>
<ul>
<li><p>Controls <strong>how the application is hosted and started</strong> (e.g., server URLs, environment).</p>
</li>
<li><p>Loaded early—before the app is built.</p>
</li>
<li><p>Examples:</p>
<ul>
<li><p><code>ASPNETCORE_ENVIRONMENT</code> – sets the environment (e.g., Development, Production)</p>
</li>
<li><p><code>DOTNET_URLS</code> – sets the URLs the app will listen on</p>
</li>
</ul>
</li>
</ul>
<h4 id="heading-2-application-configuration">2. <strong>Application Configuration</strong></h4>
<ul>
<li><p>Governs <strong>application behavior and feature settings</strong> used at runtime.</p>
</li>
<li><p>Loaded after the host is built.</p>
</li>
<li><p>Examples:</p>
<ul>
<li><p><code>ConnectionStrings:Default</code> – database connection string</p>
</li>
<li><p><code>JwtSettings:Secret</code> – authentication secret</p>
</li>
<li><p><code>MyCustomFeature:Enabled</code> – feature flags</p>
</li>
</ul>
</li>
</ul>
<p>Both types of configuration are layered from multiple sources (JSON files, env vars, CLI args, etc.), but <strong>their timing and purpose differ</strong>.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text"><strong>Tip:</strong> To control which environment-specific settings are loaded, set the <code>ASPNETCORE_ENVIRONMENT</code> or <code>DOTNET_ENVIRONMENT</code> variable to the desired environment (e.g., <code>Development</code>, <code>Staging</code>, <code>Production</code>). This determines which <code>appsettings.{Environment}.json</code> file will be used at runtime.</div>
</div>

<h3 id="heading-configuration-priority">Configuration priority.</h3>
<p>Even though <strong>host configuration</strong> is loaded first and used to build the application host, <strong>application configuration has higher effective priority at runtime</strong>.</p>
<p>🔑 Here's how ASP.NET Core resolves conflicts when the same key exists in multiple sources:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Priority</td><td>Source</td><td>Type</td></tr>
</thead>
<tbody>
<tr>
<td>1️⃣</td><td>Command-line arguments</td><td>App + Host</td></tr>
<tr>
<td>2️⃣</td><td>Environment variables (no prefix)</td><td>Application</td></tr>
<tr>
<td>3️⃣</td><td>User secrets (Development only)</td><td>Application</td></tr>
<tr>
<td>4️⃣</td><td><code>appsettings.{Environment}.json</code></td><td>Application</td></tr>
<tr>
<td>5️⃣</td><td><code>appsettings.json</code></td><td>Application</td></tr>
<tr>
<td>6️⃣</td><td><code>DOTNET_</code>, <code>ASPNETCORE_</code> environment variables</td><td><strong>Host only</strong></td></tr>
</tbody>
</table>
</div><p>✅ In short: <strong>application configuration overrides host configuration</strong> during runtime. This means your feature flags, secrets, and connection strings won’t be unintentionally overridden by host-level settings.</p>
<h3 id="heading-webapplicationbuilder-in-aspnet-core-application">🏗️ WebApplicationBuilder in ASP.NET Core Application.</h3>
<p>When you initialize an ASP.NET Core application, you'll commonly see the following line of code:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> builder = WebApplication.CreateBuilder(args);
</code></pre>
<p>This single line does a lot under the hood. One of its key responsibilities is setting up a <strong>default configuration system</strong> with a built-in order of precedence. Here's how configuration sources are loaded—from <strong>lowest</strong> to <strong>highest</strong> priority:</p>
<ol>
<li><p><code>appsettings.json</code></p>
</li>
<li><p><code>appsettings.{Environment}.json</code> (e.g., <code>appsettings.Development.json</code>)</p>
</li>
<li><p><strong>User secrets</strong> (only in the <code>Development</code> environment)</p>
</li>
<li><p><strong>Environment variables</strong></p>
</li>
<li><p><strong>Command-line arguments</strong></p>
</li>
</ol>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">This means values defined in later sources override those from earlier ones.</div>
</div>

<p>Internally, this is roughly equivalent to the following:</p>
<pre><code class="lang-csharp">Host.CreateDefaultBuilder(args)
    .ConfigureAppConfiguration((hostingContext, config) =&gt;
    {
        <span class="hljs-keyword">var</span> env = hostingContext.HostingEnvironment;

        config.AddJsonFile(<span class="hljs-string">"appsettings.json"</span>, optional: <span class="hljs-literal">true</span>, reloadOnChange: <span class="hljs-literal">true</span>)
              .AddJsonFile(<span class="hljs-string">$"appsettings.<span class="hljs-subst">{env.EnvironmentName}</span>.json"</span>, optional: <span class="hljs-literal">true</span>, reloadOnChange: <span class="hljs-literal">true</span>);

        <span class="hljs-keyword">if</span> (env.IsDevelopment())
        {
            config.AddUserSecrets&lt;Program&gt;();
        }

        config.AddEnvironmentVariables();

        <span class="hljs-keyword">if</span> (args != <span class="hljs-literal">null</span>)
        {
            config.AddCommandLine(args);
        }
    });
</code></pre>
<p>This layered configuration model gives you flexibility to manage settings in a way that’s appropriate for different environments and deployment scenarios.</p>
<h3 id="heading-common-mistake-re-adding-configuration-sources">🦀 Common Mistake: Re-adding Configuration Sources</h3>
<p>A common pitfall in ASP.NET Core is manually re-adding configuration providers <strong>after</strong> this line:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> builder = WebApplication.CreateBuilder(args);
</code></pre>
<p>For example:</p>
<pre><code class="lang-csharp">builder.Configuration.AddJsonFile(<span class="hljs-string">"appsettings.json"</span>, optional: <span class="hljs-literal">true</span>, reloadOnChange: <span class="hljs-literal">true</span>)
                     .AddJsonFile(<span class="hljs-string">$"appsettings.<span class="hljs-subst">{env.EnvironmentName}</span>.json"</span>, optional: <span class="hljs-literal">true</span>, reloadOnChange: <span class="hljs-literal">true</span>);
</code></pre>
<p>At first glance, this might seem harmless—but it's usually <strong>unnecessary and potentially harmful</strong>.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Avoid re-adding default configuration providers unless you have a specific reason to change their behavior (e.g., setting <code>optional: false</code>, changing file paths, or customizing the order). Leverage the default configuration setup and only extend it when necessary.</div>
</div>

<p>By manually adding configuration files again, you risk:</p>
<ul>
<li><p><strong>Overriding existing values unintentionally</strong></p>
</li>
<li><p><strong>Redundant file reads</strong></p>
</li>
<li><p><strong>Unexpected configuration merge behavior.</strong></p>
</li>
</ul>
<h3 id="heading-understanding-merged-configuration">🤝 Understanding Merged Configuration</h3>
<p>The configuration system in ASP.NET Core <strong>merges</strong> settings from all providers. If multiple sources define values for the same key, the <strong>last one added wins</strong>.</p>
<h4 id="heading-adding-new-keys">🔹 Adding New Keys</h4>
<p>Suppose you have the following in your <code>appsettings.json</code>:</p>
<pre><code class="lang-json"><span class="hljs-string">"JwtSetting"</span>: {
  <span class="hljs-attr">"Issuer"</span>: <span class="hljs-string">"yourIssuer"</span>,
  <span class="hljs-attr">"Audience"</span>: <span class="hljs-string">"yourAudience"</span>,
  <span class="hljs-attr">"AccessTokenExpMinute"</span>: <span class="hljs-number">10</span>,
  <span class="hljs-attr">"RefreshTokenExpiration"</span>: <span class="hljs-number">30</span>
}
</code></pre>
<p>And you define this in your <strong>user secrets</strong> (Development only):</p>
<pre><code class="lang-json"><span class="hljs-string">"JwtSetting"</span>: {
  <span class="hljs-attr">"Secret"</span>: <span class="hljs-string">"your-secret-key"</span>
}
</code></pre>
<p>The final merged configuration at runtime will be:</p>
<pre><code class="lang-json"><span class="hljs-string">"JwtSetting"</span>: {
  <span class="hljs-attr">"Issuer"</span>: <span class="hljs-string">"yourIssuer"</span>,
  <span class="hljs-attr">"Audience"</span>: <span class="hljs-string">"yourAudience"</span>,
  <span class="hljs-attr">"AccessTokenExpMinute"</span>: <span class="hljs-number">10</span>,
  <span class="hljs-attr">"RefreshTokenExpiration"</span>: <span class="hljs-number">30</span>,
  <span class="hljs-attr">"Secret"</span>: <span class="hljs-string">"your-secret-key"</span>
}
</code></pre>
<p>Each source contributes to the overall object unless a full override is performed.</p>
<h4 id="heading-overriding-existing-keys">🔹 Overriding Existing Keys</h4>
<p>If the same key is defined in multiple places, the <strong>source added last</strong> takes precedence. For example:</p>
<pre><code class="lang-json"><span class="hljs-comment">// appsettings.json</span>
<span class="hljs-string">"ApiKey"</span>: <span class="hljs-string">"ValueFromAppSettings"</span>
</code></pre>
<pre><code class="lang-json"><span class="hljs-comment">// appsettings.Development.json</span>
<span class="hljs-string">"ApiKey"</span>: <span class="hljs-string">"ValueFromDevSettings"</span>
</code></pre>
<p>Then you set an environment variable:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">set</span> ApiKey=ValueFromEnv
</code></pre>
<p>And run the application with a command-line override:</p>
<pre><code class="lang-csharp">dotnet run --ApiKey=ValueFromCommandLine
</code></pre>
<p>The final value of <code>ApiKey</code> will be:</p>
<pre><code class="lang-json"><span class="hljs-string">"ApiKey"</span>: <span class="hljs-string">"ValueFromCommandLine"</span>
</code></pre>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Each configuration provider contributes keys, and later providers can override or augment earlier values. This layered model gives you powerful flexibility to manage config cleanly across environments.</div>
</div>

<h3 id="heading-custom-configuration-sources">Custom Configuration Sources</h3>
<p>In addition to the built-in configuration providers, ASP.NET Core makes it easy to add <strong>custom configuration sources</strong>. This is especially useful for keeping sensitive data like secrets or credentials out of your codebase.</p>
<p>For example, instead of storing everything in <code>appsettings.json</code> you could store some settings in the <strong>Azure App Configuration</strong> or securely store secrets in the <strong>Azure Key Vault</strong>.</p>
<blockquote>
<p>🔗 I’ve written a detailed guide on integrating Azure Key Vault with ASP.NET Core. You can read it here: <a target="_blank" href="https://kristiadhy.hashnode.dev/how-to-secure-your-net-application-secrets-with-azure-key-vault-free-code-repository-included">Azure Key Vault: Secure .NET App Secrets</a></p>
</blockquote>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Using configuration properly in ASP.NET Core enables your application to be <strong>environment-aware</strong>, <strong>secure</strong>, and <strong>maintainable</strong>. By understanding how the configuration system merges values across sources—and by using the right source for the right purpose—you can avoid common pitfalls and keep your app flexible for development, testing, and production.</p>
<p>For best results:</p>
<ul>
<li><p>Let <code>WebApplication.CreateBuilder</code> handle the default setup.</p>
</li>
<li><p>Use additional providers (like Azure Key Vault or custom JSON files) only when necessary.</p>
</li>
<li><p>Understand and leverage the <strong>configuration precedence order</strong> to avoid surprises at runtime.</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[How to Secure Your .NET Application Secrets with Azure Key Vault (Free Code Repository Included)]]></title><description><![CDATA[Securing your application is essential, especially in production environments. Sensitive information—such as application secrets (e.g., JWT secret keys, database connection strings), certificates, and encryption keys—can pose serious risks if exposed...]]></description><link>https://krisoncode.com/how-to-secure-your-net-application-secrets-with-azure-key-vault-free-code-repository-included</link><guid isPermaLink="true">https://krisoncode.com/how-to-secure-your-net-application-secrets-with-azure-key-vault-free-code-repository-included</guid><category><![CDATA[.NET]]></category><category><![CDATA[Azure]]></category><category><![CDATA[Azure Key Vault]]></category><category><![CDATA[JWT]]></category><dc:creator><![CDATA[Kristiadhy]]></dc:creator><pubDate>Sun, 27 Apr 2025 09:41:35 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1745746743577/3716cd0f-d9a8-4e08-9c49-2e78690f5f9f.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Securing your application is essential, especially in production environments. Sensitive information—such as application secrets (e.g., JWT secret keys, database connection strings), certificates, and encryption keys—can pose serious risks if exposed. It’s important to use secure storage solutions to protect these critical assets. One of the most robust options available is <strong>Azure Key Vault</strong>, which provides a safe and centralized way to manage your application's secrets.</p>
<h2 id="heading-why-use-azure-key-vault">Why use Azure Key Vault?</h2>
<h3 id="heading-your-secret-is-stored-safely-in-the-cloud">Your secret is stored safely in the cloud.</h3>
<p>By avoiding the storage of security information within applications, you eliminate the need to embed sensitive data in the code. For instance, if an application needs to connect to a database, you can securely store the connection string in Key Vault instead of hardcoding it in the application.</p>
<p>Access to your Key Vault is also secured through both authentication and authorization. Before a caller (whether a user or an application) can access the Key Vault, they must first be properly authenticated and authorized. Authentication is handled through Microsoft Entra ID, while authorization can be managed either using Azure Role-Based Access Control (Azure RBAC) or Key Vault access policies.</p>
<h3 id="heading-easy-to-monitor">Easy to monitor.</h3>
<p>Azure Key Vault makes it easy to monitor how and when your secrets are accessed. By enabling logging for your vaults, you can track all activity in detail. You have full control over your logs — you can secure them by restricting access and deleting any logs you no longer need.</p>
<h3 id="heading-automatic-secret-refresh-without-application-restart">Automatic Secret Refresh Without Application Restart.</h3>
<p>Another powerful advantage of using Azure Key Vault is its ability to <strong>automatically refresh secrets</strong> when they change, without requiring you to restart your application.</p>
<p>For example, if you store a <strong>JWT secret key</strong> in Key Vault and later decide to update it (e.g., for security rotation), your application can pick up the updated secret automatically. This eliminates downtime and reduces the risk associated with manually restarting services to load new secrets.</p>
<p>By combining Azure Key Vault with services like <strong>Azure App Configuration</strong> and enabling <strong>dynamic refresh policies</strong>, you can ensure that your application always uses the latest secure values, improving both security and operational efficiency.</p>
<p>Tip: To automatically see secret updates without restarting services, use <code>IOptionsSnapshot&lt;T&gt;</code> instead of <code>IOptions&lt;T&gt;</code> for your settings injection</p>
<h2 id="heading-create-and-configure-azure-key-vault"><strong>Create and configure Azure Key Vault</strong></h2>
<p>Now, let’s jump into the implementation.</p>
<ul>
<li><p>Go to <a target="_blank" href="https://portal.azure.com/">https://portal.azure.com/</a> , select a service named Key Vaults, and create it.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745730323690/f797dfda-591c-4267-b80d-77c2445a7b1b.png" alt /></p>
</li>
<li><p>In the side menu, select Objects &gt; Secrets.</p>
</li>
<li><p>At the top, select the generate/import menu</p>
</li>
<li><p>Fill the name and secret value field, and then click the create button.</p>
</li>
</ul>
<p><strong><em>Note:</em></strong> <em>In the screenshot below, I use</em> <strong><em>"JwtSecret"</em></strong> <em>as the secret name. However, in the example code, I use</em> <strong><em>"JwtSettings--Secret"*</em></strong>.<br />Don’t let the difference confuse you — the concept remains the same.*</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745732498922/be79074e-a948-4d21-93bf-d7d9836a83a1.png" alt class="image--center mx-auto" /></p>
<ul>
<li>You can manage access permissions using Access Control (IAM).</li>
</ul>
<p>However, in this article, we won't dive deeper into configuring Access Control settings.</p>
<p>Now that your secrets are securely set up, it's time to integrate them into your .NET application.</p>
<h2 id="heading-configure-your-net-application">Configure your .NET application.</h2>
<p>There are two ways to connect your .NET application to Azure Key Vault: <strong>Automatic Configuration Approach</strong> and the <strong>Manual Service Approach</strong>.</p>
<h3 id="heading-automatic-configuration-approach">Automatic Configuration Approach.</h3>
<p>With this approach, you load secrets from Azure Key Vault directly into your application's configuration.</p>
<p>To do this, you need to install 3 packages (The example is using .NET CLI. You can also install using NuGet Package):</p>
<pre><code class="lang-csharp">dotnet <span class="hljs-keyword">add</span> package Azure.Identity
dotnet <span class="hljs-keyword">add</span> package Azure.Security.KeyVault.Secrets
dotnet <span class="hljs-keyword">add</span> package Azure.Extensions.AspNetCore.Configuration.Secrets
</code></pre>
<p>In the example below, I’ll show you how to configure your <code>appsettings.json</code> and <code>Program.cs</code><br /><em>Note: For better code organization, I recommend moving the setup into a separate method to keep your</em> <code>Program.cs</code> <em>clean. I’ve provided a full example in the repository linked at the end of this article.</em></p>
<p>appsettings.json</p>
<pre><code class="lang-csharp"><span class="hljs-string">"AzureKeyVault"</span>: {
  <span class="hljs-string">"VaultURI"</span>: <span class="hljs-string">"Your vault URI"</span>,
  <span class="hljs-string">"ClientId"</span>: <span class="hljs-string">"Your client id"</span>,
  <span class="hljs-string">"TenantId"</span>: <span class="hljs-string">"Your tenant id"</span>,
  <span class="hljs-string">"ClientSecret"</span>: <span class="hljs-string">"Your client secret"</span>
}
</code></pre>
<p>Program.cs</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> keyVaultSettings = <span class="hljs-keyword">new</span>
{
  VaultUri = builder.Configuration[<span class="hljs-string">"AzureKeyVault:VaultUri"</span>],
  TenantId = builder.Configuration[<span class="hljs-string">"AzureKeyVault:TenantId"</span>],
  ClientId = builder.Configuration[<span class="hljs-string">"AzureKeyVault:ClientId"</span>],
  ClientSecret = builder.Configuration[<span class="hljs-string">"AzureKeyVault:ClientSecret"</span>]
}; <span class="hljs-comment">// Taken from appsettings.json</span>

<span class="hljs-comment">// Add services to the container.</span>
builder.Configuration.AddAzureKeyVault(
          <span class="hljs-keyword">new</span> Uri(keyVaultSettings.VaultUri),
          <span class="hljs-keyword">new</span> ClientSecretCredential(
              tenantId: keyVaultSettings.TenantId,
              clientId: keyVaultSettings.ClientId,
              clientSecret: keyVaultSettings.ClientSecret),
          <span class="hljs-keyword">new</span> AzureKeyVaultConfigurationOptions
          {
            ReloadInterval = TimeSpan.FromMinutes(<span class="hljs-number">30</span>)
          }); <span class="hljs-comment">// Custom extension method to add Azure</span>
</code></pre>
<p><strong>What’s interesting here is that you can seamlessly combine values from both your</strong> <code>appsettings.json</code> <strong>and Azure Key Vault.</strong></p>
<p>For example, if your local <code>appsettings.json</code> contains a key like <code>JwtSettings:Secret</code>, and you have a corresponding secret in Azure Key Vault named <code>JwtSettings--Secret</code> (In key vault, use a double dash <code>--</code> to map to the colon <code>:</code>), the value from Azure Key Vault will automatically <strong>override</strong> the value from your local configuration.</p>
<p>Now, when you access your app configuration using the name of your secret — for example, <code>configuration["JwtSettings:Secret"]</code> — you will retrieve the value from Azure Key Vault.</p>
<h3 id="heading-manual-service-approach">Manual Service Approach.</h3>
<p>This approach uses a custom service to retrieve secrets. First, you need to install 2 packages:</p>
<pre><code class="lang-csharp">dotnet <span class="hljs-keyword">add</span> package Azure.Identity
dotnet <span class="hljs-keyword">add</span> package Azure.Security.KeyVault.Secrets
</code></pre>
<p>Next, I create a method to validate the credentials needed to access Azure Key Vault.</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> SecretClient <span class="hljs-title">CreateSecretClient</span>(<span class="hljs-params">IConfiguration configuration</span>)</span>
{
    <span class="hljs-comment">// Bind the configuration section to the AzureKeyVaultConfig class</span>
    <span class="hljs-keyword">var</span> keyVaultSetting = configuration.GetSection(<span class="hljs-string">"AzureKeyVault"</span>).Get&lt;AzureKeyVaultConfig&gt;()
                   ?? <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> InvalidOperationException(<span class="hljs-string">"Missing AzureKeyVault configuration."</span>);
     <span class="hljs-keyword">var</span> credential = <span class="hljs-keyword">new</span> ClientSecretCredential(keyVaultSetting.TenantId,
                            keyVaultSetting.ClientId, 
                            keyVaultSetting.ClientSecret);
    <span class="hljs-keyword">var</span> vaultUri = <span class="hljs-keyword">new</span> Uri(keyVaultSetting.VaultUri);
     <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> SecretClient(vaultUri, credential);
}
</code></pre>
<p>Next, I create a service that retrieves the secrets by using the <code>SecretClient</code>.</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;<span class="hljs-keyword">string</span>&gt; <span class="hljs-title">GetJwtSecretAsync</span>(<span class="hljs-params"></span>)</span>
{
     <span class="hljs-keyword">var</span> response = <span class="hljs-keyword">await</span> _secretClient.GetSecretAsync(<span class="hljs-string">"JwtSettings--Secret"</span>);
     <span class="hljs-keyword">return</span> response.Value.Value;
}
</code></pre>
<p>Now you can call your secret using the <code>GetJwtSecretAsync()</code> method.</p>
<p>When accessing Azure Key Vault from your .NET application, there are two common ways to authenticate.<br />In the above example, I used <strong>TenantId</strong>, <strong>ClientId</strong>, and <strong>ClientSecret</strong> to authenticate with Azure Key Vault. However, there's another option that I recommend, which is using <code>DefaultAzureCredential()</code>.<br />In the next section, I'll show you both authentication methods you can use to connect to your Azure Key Vault.</p>
<h3 id="heading-two-ways-to-authenticate-to-azure-key-vault">Two Ways to Authenticate to Azure Key Vault</h3>
<p>When accessing Azure Key Vault from your .NET application, there are two common ways to authenticate:</p>
<h4 id="heading-1-using-defaultazurecredential">1. Using <code>DefaultAzureCredential()</code></h4>
<p><code>DefaultAzureCredential</code> is the easiest and most flexible option for many scenarios. It automatically tries multiple authentication methods under the hood, such as:</p>
<ul>
<li><p>Environment variables</p>
</li>
<li><p>Managed Identity (for Azure-hosted apps)</p>
</li>
<li><p>Visual Studio / Azure CLI logged-in credentials (for local development)</p>
</li>
</ul>
<p>This makes it a great choice if you want a seamless experience between local development and production environments, without changing any code.</p>
<p>Example:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> credential = <span class="hljs-keyword">new</span> DefaultAzureCredential();
<span class="hljs-keyword">var</span> client = <span class="hljs-keyword">new</span> SecretClient(<span class="hljs-keyword">new</span> Uri(keyVaultSettings.VaultUri), credential);
</code></pre>
<h4 id="heading-2-using-clientsecretcredential">2. Using <code>ClientSecretCredential</code></h4>
<p><code>ClientSecretCredential</code> is a more manual and explicit approach. You provide a <strong>Tenant ID</strong>, <strong>Client ID</strong>, and <strong>Client Secret</strong> directly, typically configured through your application settings.</p>
<p>This method is useful when you want full control over the credentials being used or when running in environments where Managed Identity is not available.</p>
<p>Example:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> credential = <span class="hljs-keyword">new</span> ClientSecretCredential(
    tenantId: keyVaultSettings.TenantId,
    clientId: keyVaultSettings.ClientId,
    clientSecret: keyVaultSettings.ClientSecret);

<span class="hljs-keyword">var</span> client = <span class="hljs-keyword">new</span> SecretClient(<span class="hljs-keyword">new</span> Uri(keyVaultSettings.VaultUri), credential);
</code></pre>
<h3 id="heading-lets-get-hands-on">🛠️ <strong>Let’s Get Hands-On!</strong></h3>
<p>I've uploaded the full implementation with a simple and clean approach — dive into the code here! <a target="_blank" href="https://github.com/kristiadhy/AzureKeyVaultIntegration">Azure Key Vault Integration Repository</a></p>
<p>Happy coding!</p>
]]></content:encoded></item><item><title><![CDATA[Object-Oriented Programming: Abstraction]]></title><description><![CDATA[Hides complexity by only exposing necessary details.

This allows users to interact with objects and systems without needing to understand all the underlying implementation details.


Real-world Example

TV Remote

A TV remote has several functions l...]]></description><link>https://krisoncode.com/oop-abstraction</link><guid isPermaLink="true">https://krisoncode.com/oop-abstraction</guid><category><![CDATA[Object Oriented Programming]]></category><category><![CDATA[abstraction]]></category><category><![CDATA[C#]]></category><category><![CDATA[.NET]]></category><dc:creator><![CDATA[Kristiadhy]]></dc:creator><pubDate>Thu, 31 Oct 2024 16:31:48 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1730390181420/e6e0abf7-a55a-4ffb-b224-c3c8fe5bc522.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<ul>
<li><p>Hides complexity by only exposing necessary details.</p>
</li>
<li><p>This allows users to interact with objects and systems without needing to understand all the underlying implementation details.</p>
</li>
</ul>
<h3 id="heading-real-world-example"><strong>Real-world Example</strong></h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1730390427640/1987c6b9-d487-4731-81fd-1b1dbb208f9d.jpeg" alt class="image--center mx-auto" /></p>
<p><strong>TV Remote</strong></p>
<ul>
<li><p>A TV remote has several functions like turning the TV on or off, changing channels, increasing volume, etc.</p>
</li>
<li><p>As users, we only know that these functions will be executed by pressing the corresponding buttons on the remote.</p>
</li>
<li><p>What actually happens behind the scenes is hidden from us.</p>
</li>
</ul>
<h3 id="heading-benefits-of-using-abstraction"><strong>Benefits of Using Abstraction</strong></h3>
<ul>
<li><p><strong>Reduces Complexity</strong></p>
<p>  This principle only provides method signatures while hiding how those methods are implemented.</p>
</li>
<li><p><strong>Enhances Security</strong></p>
<p>  Because we only provide the necessary details to call a method while hiding how the method is implemented.</p>
</li>
<li><p><strong>Facilitates Development</strong></p>
<p>  Since we can make any internal system changes without affecting the users of the method.</p>
</li>
</ul>
<p><strong>Abstraction can be achieved in two ways:</strong></p>
<ul>
<li><p>Using abstract classes and abstract methods.</p>
</li>
<li><p>Using Interfaces.</p>
</li>
</ul>
<h3 id="heading-abstract-class-and-abstract-method"><strong>Abstract Class and Abstract Method</strong></h3>
<p><strong>Characteristics of an Abstract Class.</strong></p>
<ul>
<li><p>Cannot be instantiated directly.</p>
</li>
<li><p>Serves as a blueprint for other classes, meaning it can contain abstract methods (which must be implemented by its subclasses) and concrete methods (which have full implementations).</p>
</li>
</ul>
<p><strong>Characteristics of an Abstract Method</strong></p>
<ul>
<li><p>Declared in an abstract class without implementation.</p>
</li>
<li><p>Only has a method signature (method name, return type, and parameters) without implementation.</p>
</li>
<li><p>The actual implementation is left to the subclasses.</p>
</li>
</ul>
<p>Example of an abstract class with all abstract methods.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">class</span> <span class="hljs-title">IBank</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">void</span> <span class="hljs-title">ValidateCard</span>(<span class="hljs-params"></span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">void</span> <span class="hljs-title">WithdrawMoney</span>(<span class="hljs-params"></span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">void</span> <span class="hljs-title">CheckBalanace</span>(<span class="hljs-params"></span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">void</span> <span class="hljs-title">BankTransfer</span>(<span class="hljs-params"></span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">void</span> <span class="hljs-title">MiniStatement</span>(<span class="hljs-params"></span>)</span>;
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">SBI</span> : <span class="hljs-title">IBank</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">void</span> <span class="hljs-title">BankTransfer</span>(<span class="hljs-params"></span>)</span>
    {
        Console.WriteLine(<span class="hljs-string">"SBI Bank Bank Transfer"</span>);
    }
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">void</span> <span class="hljs-title">CheckBalanace</span>(<span class="hljs-params"></span>)</span>
    {
        Console.WriteLine(<span class="hljs-string">"SBI Bank Check Balanace"</span>);
    }
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">void</span> <span class="hljs-title">MiniStatement</span>(<span class="hljs-params"></span>)</span>
    {
        Console.WriteLine(<span class="hljs-string">"SBI Bank Mini Statement"</span>);
    }
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">void</span> <span class="hljs-title">ValidateCard</span>(<span class="hljs-params"></span>)</span>
    {
        Console.WriteLine(<span class="hljs-string">"SBI Bank Validate Card"</span>);
    }
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">void</span> <span class="hljs-title">WithdrawMoney</span>(<span class="hljs-params"></span>)</span>
    {
        Console.WriteLine(<span class="hljs-string">"SBI Bank Withdraw Money"</span>);
    }
}
</code></pre>
<pre><code class="lang-csharp">IBank sbi = <span class="hljs-keyword">new</span> SBI();
sbi.ValidateCard();
sbi.WithdrawMoney();
sbi.CheckBalanace();
sbi.BankTransfer();
sbi.MiniStatement();
</code></pre>
<p>In the code above, we declare a class as an abstract class by adding the abstract modifier. We also declare all its methods as abstract methods, where no implementation is allowed (only the method body). However, when we create a subclass of IBank, in the example above, SBI, all methods from IBank must be implemented by adding the override keyword to each method in the child class.</p>
<p>We also need to pay attention during object initialization. On the left side or reference type, we set the object ‘sbi’ as IBank, the abstract class, while on the right side or object type, we set it as the SBI class. When we call a method, the compiler recognizes all these methods because they are in the abstract class, but during runtime, the implementation is determined based on the object type, in this case, SBI.</p>
<p><strong>Example of an abstract class with abstract and concrete methods.</strong></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Bird</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Fly</span>(<span class="hljs-params"></span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">LayEggs</span>(<span class="hljs-params"></span>)</span>
    {
        Console.WriteLine(<span class="hljs-string">"Laying eggs"</span>);
    }
}
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Sparrow</span> : <span class="hljs-title">Bird</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Fly</span>(<span class="hljs-params"></span>)</span>
    {
        Console.WriteLine(<span class="hljs-string">"Sparrow is flying"</span>);
    }
}
</code></pre>
<p>In the code example above, we declare some methods as abstract methods and others as concrete methods. This way, when we create a subclass or child class, we must override the Fly() method because in the parent class, the method is set as an abstract method (without implementation), while the LayEggs() method is not overridden because it is a concrete method (with implementation).</p>
<h3 id="heading-interface">Interface.</h3>
<p>An <strong>interface</strong> is an abstract type used to define a contract (or blueprint) for classes that implement it.</p>
<p>Let's look at the code example directly.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">interface</span> <span class="hljs-title">ISpeakable</span>
{
    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">Speak</span>(<span class="hljs-params"></span>)</span>;  <span class="hljs-comment">// This method must be implemented by its child class.</span>
}

<span class="hljs-keyword">interface</span> <span class="hljs-title">IMoveable</span>
{
    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">Move</span>(<span class="hljs-params"></span>)</span>;
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Dog</span> : <span class="hljs-title">ISpeakable</span>, <span class="hljs-title">IMoveable</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Speak</span>(<span class="hljs-params"></span>)</span>
    {
        Console.WriteLine(<span class="hljs-string">"Bark"</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Move</span>(<span class="hljs-params"></span>)</span>
    {
        Console.WriteLine(<span class="hljs-string">"Dog is running"</span>);
    }
}
</code></pre>
<pre><code class="lang-csharp">Dog dog = <span class="hljs-keyword">new</span> Dog();
dog.Speak();
dog.Move();
</code></pre>
<p>Note: A class is said to implement an interface, not inherit from it.</p>
<p>In the code above, we can see that the Dog class implements two interfaces simultaneously, ISpeakable and IMoveable, which is allowed, unlike abstract classes that do not allow a child class to be derived from two classes simultaneously (C# allows a class to be derived from only one class).</p>
<p>The concept of interfaces is very popular and often encountered in complex projects.</p>
<h3 id="heading-differences-between-abstract-class-and-interface"><strong>Differences between Abstract Class and Interface</strong></h3>
<p>See the differences between abstract classes and interfaces in the table below.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Aspect</strong></td><td><strong>Abstract Class</strong></td><td><strong>Interface</strong></td></tr>
</thead>
<tbody>
<tr>
<td>Nature</td><td>Represents "is-a" relationship</td><td>Represents "can do" relationship</td></tr>
<tr>
<td>Method Implementation</td><td>Parent class can have abstract and concrete methods.</td><td>Only has method signatures (name, parameters, return type).</td></tr>
<tr>
<td>Data Members</td><td>Can have fields, constructors, and properties</td><td>Can have properties, events, indexers, but not fields.</td></tr>
<tr>
<td>Multiple Inheritance</td><td>Does not support multiple inheritance</td><td>Supports multiple inheritance</td></tr>
<tr>
<td>Purpose</td><td>When several classes share the same methods but also need to add some unimplemented behaviors</td><td>When defining a contract that must be implemented by a class.</td></tr>
<tr>
<td>Default Access Modifier</td><td>As a class, the default modifier is private.</td><td>Default modifier is set to public.</td></tr>
</tbody>
</table>
</div><p>We have finished discussing the concept of Abstraction in Object-Oriented Programming (OOP), thus completing our discussion on the <strong>four pillars of Object-Oriented Programming (OOP).</strong> Thank you!</p>
]]></content:encoded></item><item><title><![CDATA[Object-oriented Programming: Polymorphism]]></title><description><![CDATA[Literally, "Poly" means many, "Morph" means form. So, Polymorphism = having many forms.
Polymorphism is a concept in Object-Oriented Programming (OOP) where an entity (variable, object, method) can change into other forms.
Real-world Example

Let's t...]]></description><link>https://krisoncode.com/oop-polymorphism</link><guid isPermaLink="true">https://krisoncode.com/oop-polymorphism</guid><category><![CDATA[Object Oriented Programming]]></category><category><![CDATA[polymorphism]]></category><category><![CDATA[C#]]></category><category><![CDATA[.NET]]></category><dc:creator><![CDATA[Kristiadhy]]></dc:creator><pubDate>Thu, 31 Oct 2024 15:15:18 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1730385322744/f6e98c93-b1a0-4112-8717-ccbce6534020.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Literally, "Poly" means many, "Morph" means form. So, Polymorphism = having many forms.</p>
<p>Polymorphism is a concept in Object-Oriented Programming (OOP) where an entity (variable, object, method) can change into other forms.</p>
<h3 id="heading-real-world-example"><strong>Real-world Example</strong></h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745748991603/7c20403d-9265-46ca-9fe1-f79bd1119274.jpeg" alt class="image--center mx-auto" /></p>
<p>Let's take the example of a person who can have many roles in their life.</p>
<ul>
<li><p>At the <strong>Office</strong>, Person A behaves like an <strong>employee</strong>.</p>
</li>
<li><p>At the <strong>Mall</strong>, Person A behaves like a <strong>customer</strong>.</p>
</li>
<li><p>At <strong>Home</strong>, Person A behaves like a <strong>father</strong>.</p>
</li>
</ul>
<p><strong>Polymorphism can be achieved in two ways:</strong></p>
<ul>
<li><p>Compile-time Polymorphism (Method Overloading).</p>
</li>
<li><p>Run-time Polymorphism (Method Overriding).</p>
</li>
</ul>
<h3 id="heading-compile-time-polymorphism-method-overloading"><strong>Compile-time Polymorphism (Method Overloading)</strong></h3>
<p>Occurs when several methods have the same name but different parameters (in number, type, or order).</p>
<p><strong>Method overloading can be done under several conditions:</strong></p>
<ul>
<li><p>Done on methods within the same class.</p>
</li>
<li><p>Done on methods within a child class.</p>
</li>
<li><p>Done on constructors.</p>
</li>
</ul>
<blockquote>
<p><strong><em>Some rules for Method Overloading:</em></strong></p>
<ul>
<li><p><strong><em>Parameters must differ (in number, type, or order).</em></strong></p>
</li>
<li><p><strong><em>Return type alone cannot distinguish overloaded methods.</em></strong></p>
</li>
<li><p><strong><em>Occurs at compile time (also called Compile-time Polymorphism).</em></strong></p>
</li>
</ul>
</blockquote>
<p><strong>Example code: Method overloading in the same class.</strong></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Person</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">SummingUp</span>(<span class="hljs-params"><span class="hljs-keyword">int</span> a, <span class="hljs-keyword">int</span> b</span>)</span>
    {
        <span class="hljs-keyword">return</span> a + b;
    }
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">SummingUp</span>(<span class="hljs-params"><span class="hljs-keyword">int</span> a, <span class="hljs-keyword">int</span> b, <span class="hljs-keyword">int</span> c</span>)</span>
    {
        <span class="hljs-keyword">return</span> a + b + c;
    }
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> <span class="hljs-title">SummingUp</span>(<span class="hljs-params"><span class="hljs-keyword">double</span> a, <span class="hljs-keyword">double</span> b</span>)</span>
    {
        <span class="hljs-keyword">return</span> a + b;
    }
}
</code></pre>
<p>In the code above, we can see that there are three methods with the same name in one class. Although they have the same name, these three methods have different parameters, so the compiler recognizes them as different methods, and no error will occur.</p>
<p><strong>Example code: Inheritance-based method overloading.</strong></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">class</span> <span class="hljs-title">Person1</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">SummingUp</span>(<span class="hljs-params"><span class="hljs-keyword">int</span> a, <span class="hljs-keyword">int</span> b</span>)</span>
    {
        Console.WriteLine(a + b);
    }
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">SummingUp</span>(<span class="hljs-params"><span class="hljs-keyword">float</span> x, <span class="hljs-keyword">float</span> y</span>)</span>
    {
        Console.WriteLine(x + y);
    }
}
<span class="hljs-keyword">class</span> <span class="hljs-title">Person2</span> : <span class="hljs-title">Person1</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">SummingUp</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> s1, <span class="hljs-keyword">string</span> s2</span>)</span>
    {
        Console.WriteLine(s1 +<span class="hljs-string">" "</span>+ s2);
    }
}
</code></pre>
<p>In the code above, we perform method overloading in different classes, but they are still derived from the previous class. This way, the compiler can also recognize the method as different, so this can be done without causing errors.</p>
<p><strong>Example code: Constructor Overloading.</strong></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">class</span> <span class="hljs-title">Person</span>
{
    <span class="hljs-keyword">int</span> x, y, z;
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Person</span>(<span class="hljs-params"><span class="hljs-keyword">int</span> x</span>)</span>
    {
        Console.WriteLine(<span class="hljs-string">"Constructor1 Called"</span>);
        <span class="hljs-keyword">this</span>.x = <span class="hljs-number">10</span>;
    }
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Person</span>(<span class="hljs-params"><span class="hljs-keyword">int</span> x, <span class="hljs-keyword">int</span> y</span>)</span>
    {
        Console.WriteLine(<span class="hljs-string">"Constructor2 Called"</span>);
        <span class="hljs-keyword">this</span>.x = x;
        <span class="hljs-keyword">this</span>.y = y;
    }
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Person</span>(<span class="hljs-params"><span class="hljs-keyword">int</span> x, <span class="hljs-keyword">int</span> y, <span class="hljs-keyword">int</span> z</span>)</span>
    {
        Console.WriteLine(<span class="hljs-string">"Constructor3 Called"</span>);
        <span class="hljs-keyword">this</span>.x = x;
        <span class="hljs-keyword">this</span>.y = y;
        <span class="hljs-keyword">this</span>.z = z;
    }
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Display</span>(<span class="hljs-params"></span>)</span>
    {
        Console.WriteLine(<span class="hljs-string">$"X=<span class="hljs-subst">{x}</span>, Y=<span class="hljs-subst">{y}</span>, Z=<span class="hljs-subst">{z}</span>"</span>);
    }
}
</code></pre>
<pre><code class="lang-csharp">Person obj1 = <span class="hljs-keyword">new</span> Person(<span class="hljs-number">10</span>);
obj1.Display();
Person obj2 = <span class="hljs-keyword">new</span> Person(<span class="hljs-number">10</span>, <span class="hljs-number">20</span>);
obj2.Display();
Person obj3 = <span class="hljs-keyword">new</span> Person(<span class="hljs-number">10</span>, <span class="hljs-number">20</span>, <span class="hljs-number">30</span>);
obj3.Display();
</code></pre>
<p>In the code above, we perform method overloading on the constructor along with an example of its implementation during initialization. This method is very advantageous because if at any time we want to add parameters to the constructor, we do not need to change the logic we have previously created when declaring objects. We just need to create a new constructor with different parameters and call it by adjusting the number and type of parameters.</p>
<h3 id="heading-runtime-polymorphism-method-overriding"><strong>Runtime Polymorphism (Method Overriding)</strong></h3>
<ul>
<li><p>Method overriding occurs when a child class specifically implements a method that has been defined in its parent class. The method that allows for overriding needs to be added with a virtual modifier.</p>
</li>
<li><p>Done by adding the keyword 'override' to the method that performs the override.</p>
</li>
<li><p>The goal is for the child class to replace the behavior of the method inherited from its parent class.</p>
</li>
</ul>
<blockquote>
<p><strong><em>Some rules for Method Overriding:</em></strong></p>
<ul>
<li><p><strong><em>The modifier on the parent class method needs to be added with "virtual" and the modifier on the child class method needs to be added with "override".</em></strong></p>
</li>
<li><p><strong><em>The method in the child class must have the same name, return type, and parameters as its parent class.</em></strong></p>
</li>
<li><p><strong><em>Occurs at runtime (also called runtime polymorphism).</em></strong></p>
</li>
</ul>
</blockquote>
<p>When do we need to override a method? If the logic in the parent class method cannot meet the business requirements of the child class.</p>
<p>Here is the example code.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Animal</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">virtual</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Speak</span>(<span class="hljs-params"></span>)</span>
    {
        Console.WriteLine(<span class="hljs-string">"The animal makes a sound."</span>);
    }
}
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Dog</span> : <span class="hljs-title">Animal</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Speak</span>(<span class="hljs-params"></span>)</span>
    {
        Console.WriteLine(<span class="hljs-string">"The dog barks."</span>);
    }
}
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Cat</span> : <span class="hljs-title">Animal</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Speak</span>(<span class="hljs-params"></span>)</span>
    {
        Console.WriteLine(<span class="hljs-string">"The cat meows."</span>);
    }
}
</code></pre>
<pre><code class="lang-csharp">Animal myAnimal = <span class="hljs-keyword">new</span> Animal();
myAnimal.Speak(); <span class="hljs-comment">// "The animal makes a sound."</span>
myAnimal = <span class="hljs-keyword">new</span> Dog();
myAnimal.Speak(); <span class="hljs-comment">// "The dog barks."</span>
myAnimal = <span class="hljs-keyword">new</span> Cat();
myAnimal.Speak(); <span class="hljs-comment">// "The cat meows."</span>
</code></pre>
<p>In the example code above, we perform method overriding on the Speak() method. In the parent class, we initially determined the implementation of the Speak() method, but in the child class, we override it by providing a new implementation for the Speak() method. So when the class is initialized into an object, we can call the method and produce different outputs according to the Object Type we use.</p>
<p>Note:</p>
<ul>
<li><p>If there is no method override in the child class, the method from its parent class will be executed.</p>
</li>
<li><p>Example: If we delete the Speak() method in the Cat class, when executing the Speak() method for the Cat object type, the output will be: "The animal makes a sound," not "The cat meows" anymore.</p>
</li>
</ul>
<h3 id="heading-what-actually-happens-at-compile-time-and-run-time"><strong>What actually happens at compile time and run time?</strong></h3>
<ul>
<li><p>At compile time, the compiler checks the reference type.</p>
</li>
<li><p>At run time, the CLR checks the object type.</p>
</li>
<li><p>This is why it is called compile-time polymorphism and runtime polymorphism.</p>
</li>
</ul>
<p>The consequence is that when there is an implementation error related to the object type, the error will not be detected at compile time because the writing is considered correct. However, when run at runtime, the error will appear and be discovered.</p>
<p>We have learned about the concept of Polymorphism in OOP, next we will look at the last concept of OOP, which is <a target="_blank" href="https://kristiadhy.hashnode.dev/oop-abstraction"><strong>Abstraction</strong></a>.</p>
]]></content:encoded></item><item><title><![CDATA[Object-Oriented Programming: Encapsulation]]></title><description><![CDATA[Encapsulation is the process of combining data members (fields/properties) and behaviors (methods/functions) into a single unit (class, interface, struct).
Real-world Example

For example, a Bag and its contents. In this illustration, all the content...]]></description><link>https://krisoncode.com/oop-encapsulation</link><guid isPermaLink="true">https://krisoncode.com/oop-encapsulation</guid><category><![CDATA[encapsulation]]></category><category><![CDATA[Object Oriented Programming]]></category><category><![CDATA[C#]]></category><category><![CDATA[.NET]]></category><dc:creator><![CDATA[Kristiadhy]]></dc:creator><pubDate>Thu, 31 Oct 2024 01:14:55 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1730334801265/9fc67d92-3096-4bdc-b0d0-2032e8a80b15.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>Encapsulation</em> is the process of combining data members (<em>fields/properties</em>) and behaviors (<em>methods/functions</em>) into a single unit (<em>class, interface, struct</em>).</p>
<h3 id="heading-real-world-example"><strong>Real-world Example</strong></h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1730335116129/98ac4ce0-2dfc-4849-9730-de0767d02c4d.jpeg" alt class="image--center mx-auto" /></p>
<p>For example, a Bag and its contents. In this illustration, all the contents of the bag, such as books, pens, rulers, etc., are combined and stored in a bag. We cannot take out the pen, book, and various other items inside the bag without first opening the bag.</p>
<h3 id="heading-code-example"><strong>Code Example</strong></h3>
<pre><code class="lang-csharp"><span class="hljs-keyword">class</span> <span class="hljs-title">Bank</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">long</span> AccountNumber;
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Name;
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> Balance;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">GetBalance</span>(<span class="hljs-params"></span>)</span>
    {
    }
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">WithdrawAmount</span>(<span class="hljs-params"></span>)</span>
    {
    }
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Deposit</span>(<span class="hljs-params"></span>)</span>
    {
    }
}
</code></pre>
<p>In the example above, the Bank class is an example of <em>encapsulation</em>. The data members and <em>methods</em> of the class are bound in a single unit, which is the Bank class.</p>
<p>Here, <em>encapsulation</em> binds the implementation details of the Bank class. If there is code that wants to access the fields &amp; methods in the Bank class, it must first initialize an object of the Bank class, as shown in the code below.</p>
<pre><code class="lang-csharp">Bank bank = <span class="hljs-keyword">new</span> Bank();
<span class="hljs-comment">// The property and method below cannot be accessed without first</span>
<span class="hljs-comment">// declaring an object of the bank class.</span>
bank.AccountNumber = <span class="hljs-number">12345678</span>;
bank.Name = <span class="hljs-string">"Kristiadhy"</span>;
bank.GetBalance();
bank.WithdrawAmount();
</code></pre>
<h3 id="heading-data-hiding-in-encapsulation"><strong>Data Hiding in Encapsulation</strong></h3>
<p>The biggest advantage of encapsulation is <em>data hiding</em>, the process where we hide internal data from the outside world. Data hiding is also known as Data Encapsulation.</p>
<p>To hide and expose data, we need <em>access modifiers</em>. <em>Access Modifiers</em> are keywords that determine the accessibility level of a class, method, variable, and other members.</p>
<p>In C#, generally, access modifiers can be divided into 4 (although it can be more if combining several access modifiers), for example:</p>
<ul>
<li><p><strong>Private.</strong></p>
<p>  Members can only be accessed within the class itself.</p>
</li>
<li><p><strong>Protected.</strong></p>
<p>  Members can be accessed within the class and all its derived classes.</p>
</li>
<li><p><strong>Internal.</strong></p>
<p>  Members can be accessed within the same <em>assembly</em>.</p>
</li>
<li><p><strong>Public.</strong></p>
<p>  Members can be accessed by the same assembly or different assemblies that reference it.</p>
</li>
</ul>
<p>Here is the code example:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">BankDataEncapsulation</span>
{
    <span class="hljs-comment">// The balance field is hidden from access outside the class</span>
    <span class="hljs-comment">// by using the private access modifier</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">double</span> balance;

    <span class="hljs-comment">// Create public Setter and Getter methods</span>
    <span class="hljs-comment">// Public Getter method</span>
    <span class="hljs-comment">// This method is used to return the value of the balance variable</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> <span class="hljs-title">GetBalance</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-comment">// We can add validation if necessary    </span>
        <span class="hljs-keyword">return</span> balance;
    }

    <span class="hljs-comment">// Public Setter Method</span>
    <span class="hljs-comment">// This method is used to assign a value to the balance variable</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">SetBalance</span>(<span class="hljs-params"><span class="hljs-keyword">double</span> balance</span>)</span>
    {         
        <span class="hljs-comment">// We can add validation to check</span>
        <span class="hljs-comment">// whether the input data is correct or not.</span>
        <span class="hljs-keyword">this</span>.balance = balance;
    }
}
</code></pre>
<p>In the code example above, in the class, we have a field balance set as <em>private</em>. The field cannot be accessed by anyone outside its class (even if the class has been initialized as an object). An example can be seen in the code below.</p>
<pre><code class="lang-csharp">BankDataEncapsulation bankEncapsulation = <span class="hljs-keyword">new</span> BankDataEncapsulation();
bankEncapsulation.balance; <span class="hljs-comment">// This line will result in a compile-time error.</span>
</code></pre>
<p>So how do we manipulate the balance value in the BankDataEncapsulation class? We can do it by accessing the <em>getter</em> and <em>setter</em> methods that have been set as <em>public</em>. Please see the code example below.</p>
<pre><code class="lang-csharp">BankDataEncapsulation bankEncapsulation = <span class="hljs-keyword">new</span> BankDataEncapsulation();
bankEncapsulation.SetBalance(<span class="hljs-number">500</span>);
Console.WriteLine(bankEncapsulation.GetBalance());
</code></pre>
<p>This way, the balance field is safe and locked so that its value cannot be changed except by the methods allowed by the class through certain <em>access modifiers</em>. This ensures data security.</p>
<p>Additionally, when we want to add validation to the balance value, we can add it by modifying the <em>getter</em> and <em>setter</em> methods, so we don't need to change the code when calling the method. Here is the code example.</p>
<pre><code class="lang-csharp">    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> <span class="hljs-title">GetBalance</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-comment">// In the getter method, we add validation.</span>
        <span class="hljs-keyword">if</span>(balance &gt; <span class="hljs-number">1000000</span>)
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Exception(<span class="hljs-string">"Anda tidak bisa cek saldo diatas 1000000"</span>);  

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

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">SetBalance</span>(<span class="hljs-params"><span class="hljs-keyword">double</span> balance</span>)</span>
    {         
        <span class="hljs-comment">// We also add validation in the setter method.</span>
        <span class="hljs-keyword">if</span>(balance &lt; <span class="hljs-number">0</span>)
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Exception(<span class="hljs-string">"Saldo tidak boleh negatif"</span>);

        <span class="hljs-keyword">this</span>.balance = balance;
    }
</code></pre>
<p>We can see that even though there is additional <em>logic</em> in both methods, the code when calling the method remains the same/unchanged, still like this.</p>
<pre><code class="lang-csharp">BankDataEncapsulation bankEncapsulation = <span class="hljs-keyword">new</span> BankDataEncapsulation();
bankEncapsulation.SetBalance(<span class="hljs-number">500</span>);
Console.WriteLine(bankEncapsulation.GetBalance());
</code></pre>
<p>This is very advantageous because we don't need to make many adjustments when there is a change in <em>logic</em>. This is a simple example of the benefits of the <em>Encapsulation</em> concept.</p>
<h3 id="heading-some-benefits-of-encapsulation"><strong>Some Benefits of Encapsulation</strong></h3>
<ul>
<li><p><strong>Data Protection.</strong></p>
<p>  We can validate data before storing it in a variable.</p>
</li>
<li><p><strong>Data Hiding.</strong></p>
<p>  The <em>caller</em> will not know about the implementation of the parts inside the class.</p>
</li>
<li><p><strong>Security.</strong></p>
<p>  The principle of encapsulation helps secure our code by ensuring that other units (class, interface, etc.) cannot access data directly.</p>
</li>
<li><p><strong>Flexibility.</strong></p>
<p>  The principle of encapsulation makes our code more flexible, allowing programmers to easily change or update the code.</p>
</li>
<li><p><strong>Control.</strong></p>
<p>  The principle of encapsulation provides greater control over the data stored in variables. For example, we can control data by validating whether it is good enough to be stored in a variable.</p>
</li>
</ul>
<p>We have learned about one of the concepts of the 4 pillars of OOP, which is <strong><em>Encapsulation</em></strong>. Next, we will learn about another concept in OOP, which is <a target="_blank" href="https://kristiadhy.hashnode.dev/oop-polymorphism"><strong><em>Polymorphism</em></strong></a>.</p>
]]></content:encoded></item><item><title><![CDATA[Object-Oriented Programming : Inheritence]]></title><description><![CDATA[Inheritance allows the creation of new classes called derived classes (subclass/child class).

The class that serves as the parent of the derived class is usually called the base class (parent class/superclass).

Derived classes can use methods writt...]]></description><link>https://krisoncode.com/inheritence</link><guid isPermaLink="true">https://krisoncode.com/inheritence</guid><category><![CDATA[inheritance]]></category><category><![CDATA[Object Oriented Programming]]></category><category><![CDATA[C#]]></category><category><![CDATA[.NET]]></category><dc:creator><![CDATA[Kristiadhy]]></dc:creator><pubDate>Wed, 30 Oct 2024 07:47:15 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1730270034030/26ff9a03-2b98-4fbe-834b-d90f0f24bdcc.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<ul>
<li><p><em>Inheritance</em> allows the creation of new classes called derived classes (subclass/child class).</p>
</li>
<li><p>The class that serves as the parent of the derived class is usually called the base class (parent class/superclass).</p>
</li>
<li><p>Derived classes can use methods written in the base class, reducing code duplication.</p>
</li>
</ul>
<h3 id="heading-real-world-example"><strong>Real-world example.</strong></h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745749023206/a09d959c-4696-410a-9784-121d62994e0d.jpeg" alt class="image--center mx-auto" /></p>
<p>The relationship between animals and dogs.</p>
<ul>
<li><p>Animals are a general category that includes various living creatures with basic traits like breathing and moving.</p>
</li>
<li><p>Dogs, as a type of animal, inherit these traits but also have specific characteristics, such as barking and loyalty to their owners.</p>
</li>
<li><p>In this illustration, animals are referred to as the base class/parent class/superclass, while dogs are referred to as the derived class/child class/subclass, inheriting basic traits from animals and adding their own unique traits.</p>
</li>
</ul>
<h3 id="heading-code-example"><strong>Code example.</strong></h3>
<p>Here is an example of creating a class for animals (class Animal) and dogs (class Dog).</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Animal</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Eat</span>(<span class="hljs-params"></span>)</span>
    {
        Console.WriteLine(<span class="hljs-string">"Animal is eating."</span>);
    }
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Dog</span> : <span class="hljs-title">Animal</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Bark</span>(<span class="hljs-params"></span>)</span>
    {
        Console.WriteLine(<span class="hljs-string">"Dog is barking."</span>);
    }
}
</code></pre>
<p>Here is an example when the dog class (which is a subclass of the Animal class) is initialized into an object.</p>
<pre><code class="lang-csharp">Dog myDog = <span class="hljs-keyword">new</span> Dog();
myDog.Eat();
myDog.Bark();
</code></pre>
<p>In the code above, we can see that the variable myDog is declared with the object type 'Dog'. When calling a method, the myDog object can call the Eat() method, which is a method from its parent class, 'Animal', but can also call the Bark() method, which is a unique method of the 'Dog' class itself.</p>
<h3 id="heading-rules-of-inheritance-to-consider"><strong>Rules of Inheritance to consider.</strong></h3>
<p>In using inheritance, there are several rules to consider, including:</p>
<p><strong>Rule 1:</strong></p>
<p><strong>A child class can access members of the parent class, but the parent class can never access members purely defined in the child class.</strong></p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Code example 1</span>
Dog myDog = <span class="hljs-keyword">new</span> Dog();
myDog.Eat();
myDog.Bark(); <span class="hljs-comment">// This part does NOT result in an error.</span>

<span class="hljs-comment">// Code example 2</span>
Animal myAnimal = <span class="hljs-keyword">new</span> Animal();
myAnimal.Eat();
myAnimal.Bark(); <span class="hljs-comment">// This part results in an error.</span>
</code></pre>
<p>The last line in code example 2 above will result in an error because Bark() is a method or function specific to Dog, which is a child class, not a method belonging to Animal as the parent class of Dog.</p>
<p><strong>Rule 2:</strong></p>
<p><strong>We can initialize a parent class variable using a child class instance. With this technique, the parent class will act as a reference variable.</strong></p>
<pre><code class="lang-csharp">Animal myAnimal= <span class="hljs-keyword">new</span> Dog();
myAnimal.Eat();
myAnimal.Bark();
</code></pre>
<p>In the variable declaration above, we initialize the variable myAnimal with its object type as Dog. In the last line of that code, the compiler will recognize it as an error. Why? Because at compile time, the compiler checks the reference variable (left side), while the object type (right side) is checked at runtime (we will explore more about what happens at compile time and runtime in the topic of Polymorphism). Since at compile time the reference variable (left side) is used, which is the Animal class, and that class does not have a Bark() method/function, an error occurs.</p>
<p><strong>Rule 3:</strong></p>
<p><strong>If the parent class has a constructor, that constructor must be accessible by the child class.</strong></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Animal</span>
{
    Animal() <span class="hljs-comment">// Constructor from the parent class</span>
    {
        Console.WriteLine(<span class="hljs-string">"Animal Constructor is Called"</span>);
    }
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Eat</span>(<span class="hljs-params"></span>)</span>
    {
        Console.WriteLine(<span class="hljs-string">"Animal is eating."</span>);
    }
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Dog</span> : <span class="hljs-title">Animal</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Dog</span>(<span class="hljs-params"></span>) <span class="hljs-comment">// Constructor from the child class</span></span>
    {
        Console.WriteLine(<span class="hljs-string">"Dog Constructor is Called"</span>);
    }
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Bark</span>(<span class="hljs-params"></span>)</span>
    {
        Console.WriteLine(<span class="hljs-string">"Dog is barking."</span>);
    }
}
</code></pre>
<p>In the section above, an error will occur because the animal constructor does not allow access by other classes outside itself (the default modifier on a class is private). The solution is to provide a modifier that allows the child class to access the constructor of its parent class, for example: By adding the "Public" access modifier to the Animal constructor, no error will occur.</p>
<p><strong>Rule 4:</strong></p>
<p><strong>If the parent class constructor is given parameters, the child class constructor cannot implicitly call its parent constructor without passing parameters.</strong></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Animal</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Animal</span>(<span class="hljs-params"><span class="hljs-keyword">int</span> number</span>)</span>
    {
        Console.WriteLine(<span class="hljs-string">$"Animal Constructor is Called : <span class="hljs-subst">{number}</span>"</span>);
    }
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Eat</span>(<span class="hljs-params"></span>)</span>
    {
        Console.WriteLine(<span class="hljs-string">"Animal is eating."</span>);
    }
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Dog</span> : <span class="hljs-title">Animal</span>
{
    <span class="hljs-comment">// When creating a constructor for the child class, you must also </span>
    <span class="hljs-comment">// pass parameters to its base class.</span>
    <span class="hljs-comment">// If not (if the code ": base(10)" is not written), an error will occur.</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Dog</span>(<span class="hljs-params"></span>) : <span class="hljs-title">base</span>(<span class="hljs-params"><span class="hljs-number">10</span></span>)</span>
    {
        Console.WriteLine(<span class="hljs-string">"Dog Constructor is Called"</span>);
    }
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Bark</span>(<span class="hljs-params"></span>)</span>
    {
        Console.WriteLine(<span class="hljs-string">"Dog is barking."</span>);
    }
}
</code></pre>
<p>Notice the code above, when declaring the constructor in the child class, we pass parameters to the base class constructor or its parent class, so the code is correct and not in error. However, if “: base(10)” is not written, meaning no parameters are passed to the parent class, an error will occur.</p>
<h3 id="heading-types-of-inheritance"><strong>Types of inheritance.</strong></h3>
<p><strong>Single Inheritance.</strong></p>
<p>Where a class, known as a derived class, is based on another class, known as the base class (or parent class).</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Animal</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Eat</span>(<span class="hljs-params"></span>)</span>
    {
        Console.WriteLine(<span class="hljs-string">"Animal is eating."</span>);
    }
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Dog</span> : <span class="hljs-title">Animal</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Bark</span>(<span class="hljs-params"></span>)</span>
    {
        Console.WriteLine(<span class="hljs-string">"Dog is barking."</span>);
    }
}
</code></pre>
<p><strong>Multilevel Inheritance.</strong></p>
<p>Where a class is derived from another derived class, creating an inheritance chain.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Grandfather</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Display</span>(<span class="hljs-params"></span>)</span>
    {
        Console.WriteLine(<span class="hljs-string">"This is the grandfather class"</span>);
    }
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Father</span> : <span class="hljs-title">Grandfather</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Show</span>(<span class="hljs-params"></span>)</span>
    {
        Console.WriteLine(<span class="hljs-string">"This is the father class"</span>);
    }
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Child</span> : <span class="hljs-title">Father</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">DisplayChild</span>(<span class="hljs-params"></span>)</span>
    {
        Console.WriteLine(<span class="hljs-string">"This is the child class"</span>);
    }
}
</code></pre>
<p><strong>Hierarchical Inheritance.</strong></p>
<p>Where multiple classes are derived from a single base class, forming a tree-like structure.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Parent</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Display</span>(<span class="hljs-params"></span>)</span>
    {
        Console.WriteLine(<span class="hljs-string">"This is the parent class"</span>);
    }
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Child1</span> : <span class="hljs-title">Parent</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Show1</span>(<span class="hljs-params"></span>)</span>
    {
        Console.WriteLine(<span class="hljs-string">"This is the first child class"</span>);
    }
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Child2</span> : <span class="hljs-title">Parent</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Show2</span>(<span class="hljs-params"></span>)</span>
    {
        Console.WriteLine(<span class="hljs-string">"This is the second child class"</span>);
    }
}
</code></pre>
<p>We can see this more clearly in the following image.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1730274259783/f899d574-da84-41f8-88dd-0d5959f1f44a.png" alt class="image--center mx-auto" /></p>
<p>We have learned about the concept of <strong><em>Inheritance</em></strong> in OOP, next we will look at the next concept of OOP, which is <a target="_blank" href="https://kristiadhy.hashnode.dev/oop-encapsulation"><strong><em>Encapsulation</em></strong></a>.</p>
]]></content:encoded></item><item><title><![CDATA[Object-Oriented Programming: Class vs Object]]></title><description><![CDATA[Object-oriented programming (OOP) is a programming model that uses the approach of classes and objects in designing or developing an application.
The main goal of Object-Oriented Programming (OOP) is to organize code in a way that reflects real-world...]]></description><link>https://krisoncode.com/class-vs-object</link><guid isPermaLink="true">https://krisoncode.com/class-vs-object</guid><category><![CDATA[Object Oriented Programming]]></category><category><![CDATA[object]]></category><category><![CDATA[class]]></category><category><![CDATA[C#]]></category><category><![CDATA[.NET]]></category><dc:creator><![CDATA[Kristiadhy]]></dc:creator><pubDate>Wed, 30 Oct 2024 06:25:22 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1730269372565/9cffa484-01cb-4f02-bbe5-f780b11d057c.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Object-oriented programming (OOP) is a programming model that uses the approach of <strong>classes</strong> and <strong>objects</strong> in designing or developing an application.</p>
<p>The main goal of Object-Oriented Programming (OOP) is to organize code in a way that reflects real-world entities and interactions, making applications more robust and easier to develop.</p>
<h3 id="heading-class-vs-object"><strong>Class vs Object</strong></h3>
<p><strong>Class</strong></p>
<p>A class is a <em>blueprint</em> or <em>template</em> that contains data and behavior <em>(method/function)</em> that can be accessed by creating an <em>instance</em> (object) of that class. For more clarity, let's look at the following image:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1730098454014/ccdbd71e-d5f9-4f1e-9a73-f92d2ead896d.jpeg" alt class="image--center mx-auto" /></p>
<p>The image above is an illustration of a <em>blueprint</em> or <em>template</em> of a car. The image is not the actual physical car, but just a sketch, which we call the car <em>class</em>.</p>
<p>The "Car" class has attributes such as color, brand, and model, as well as methods or functions like move and stop.</p>
<p><strong>Object</strong></p>
<p>An object is an <em>instance</em> or realization of a <em>class</em>, an <em>object</em> is like the physical form of a <em>class</em>. Objects can have their own data values that differ from one object to another. For more clarity, let's look at the following image.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1730098719960/8cf814d8-a8eb-4262-a9b7-968319b11063.jpeg" alt class="image--center mx-auto" /></p>
<p>The image above is no longer a <em>blueprint</em> or <em>template</em>, but has become a car object, which is called an <em>object</em>.</p>
<p>Now we can assign values to the car object's attributes according to the list of attributes specified in its <em>blueprint</em> or <em>class</em> (color, brand, and model), for example:</p>
<ul>
<li><p>Color = Blue.</p>
</li>
<li><p>Brand = BMW.</p>
</li>
<li><p>Model = i5 (just an example, I don't know what type of BMW the image is XD).</p>
</li>
</ul>
<p>We can also execute the behavior or methods of the car (called <em>method/function</em>) such as the "move" and "stop" methods. When we execute its <em>method/function</em>, the car will perform the "move" or "stop" command.</p>
<h3 id="heading-code-example"><strong>Code Example</strong></h3>
<p>Here is a code example for <em>class</em> and <em>object</em> in the C# programming language.</p>
<p>Example code for <em>class</em>:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Car</span>
{
    <span class="hljs-comment">// This is an AutoProperty (C# 3.0 and higher)</span>
    <span class="hljs-comment">// used to generate a private field for you</span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Color { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Brand { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Model { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Drive</span>(<span class="hljs-params"></span>)</span>
    {
        Console.WriteLine(<span class="hljs-string">"The car is driving."</span>);
    }
}
</code></pre>
<p>Example code for <em>object</em>:</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// This is an object of the Car class.</span>
Car myCar = <span class="hljs-keyword">new</span> Car();
myCar.Color = <span class="hljs-string">"Blue"</span>;
myCar.Brand = <span class="hljs-string">"BMW"</span>;
myCar.Model = <span class="hljs-string">"i5"</span>;
myCar.Drive();
</code></pre>
<p>Here is the difference between <em>class</em> and <em>object</em> in a table:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Aspect</strong></td><td><strong>Class</strong></td><td><strong>Object</strong></td></tr>
</thead>
<tbody>
<tr>
<td>Definition</td><td>Blueprint or template for creating objects.</td><td>An instance or realization of a class.</td></tr>
<tr>
<td>Memory</td><td>Does not consume memory until the class is initialized.</td><td>Consumes memory when the object is created.</td></tr>
<tr>
<td>Attributes</td><td>Defines the attributes (field/property) of the object.</td><td>Has values associated with its attributes.</td></tr>
<tr>
<td>Behavior</td><td>Defines the behavior (method) of the object.</td><td>Can call the behavior (method) defined by its class.</td></tr>
<tr>
<td>Usage</td><td>Used to create objects.</td><td>Used to perform operations based on the class blueprint.</td></tr>
</tbody>
</table>
</div><p>We have learned more about classes and objects, next we will look at the <strong>4 basic principles of Object Oriented Programming (OOP)</strong>, starting with the first principle, <a target="_blank" href="https://kristiadhy.hashnode.dev/inheritence"><strong>Inheritance</strong></a>.</p>
]]></content:encoded></item><item><title><![CDATA[Deploying .NET 8 ASP .NET Core and Blazor Web Assembly Applications to Linux VPS]]></title><description><![CDATA[In this article, I'll show you how to manually deploy an Asp .Net Core or Blazor Web Assembly 8.0 application to your Linux VPS. If you want to set up your Linux VPS server before deploying your web apps, you can check out this guide: Guide to Hostin...]]></description><link>https://krisoncode.com/deploying-net-8-asp-net-core-and-blazor-web-assembly-applications-to-linux-vps</link><guid isPermaLink="true">https://krisoncode.com/deploying-net-8-asp-net-core-and-blazor-web-assembly-applications-to-linux-vps</guid><category><![CDATA[.NET]]></category><category><![CDATA[asp.net core]]></category><category><![CDATA[Blazor Webassembly]]></category><category><![CDATA[vps]]></category><dc:creator><![CDATA[Kristiadhy]]></dc:creator><pubDate>Thu, 05 Sep 2024 08:05:42 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/npxXWgQ33ZQ/upload/3691d15d9dc0f8ad69950dbab879113d.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this article, I'll show you how to manually deploy an Asp .Net Core or Blazor Web Assembly 8.0 application to your Linux VPS. If you want to set up your Linux VPS server before deploying your web apps, you can check out this guide: <a target="_blank" href="https://kristiadhy.hashnode.dev/guide-to-hosting-net-8-aspnet-core-and-blazor-web-assembly-on-a-linux-vps">Guide to Hosting .NET 8 ASP.NET Core and Blazor Web Assembly on a Linux VPS</a>. If you're interested in learning how to automatically update your web app using automated CI/CD with GitHub Actions, I've covered that in a separate article.</p>
<h3 id="heading-publish-your-web-app-project">Publish your web app project.</h3>
<p>You must publish your website to a folder before deploying it to a Linux VPS. In your visual studio, you can right click on your project and select publish. Set your public profile to folder.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725520353362/75ad6fb7-a431-4508-9e68-74e91ce51218.png" alt class="image--center mx-auto" /></p>
<p>Set your folder location.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725520381275/45df0b8a-87b6-41f1-968e-8102461a9b80.png" alt class="image--center mx-auto" /></p>
<p>And in your publish configuration, you can set it up as follows.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725520165300/55d45c12-9c2b-41ee-b8b6-10fb7b0e7471.jpeg" alt class="image--center mx-auto" /></p>
<p>After you succeed, check it out and make sure everything is working correctly. If you need to make any adjustments, republish it.</p>
<h3 id="heading-copy-the-project-to-your-vps">Copy the project to your VPS.</h3>
<p>Now please login to your Linux VPS server using FTP client, in my case I use WinSCP.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725520801912/778d1bcd-1e54-48fe-abf7-6e3317a2afa5.png" alt class="image--center mx-auto" /></p>
<p>After you log in successfully, drag all the files from your 'publish' folder into your website folder location on the VPS server, for example, <code>/var/www/yourdomainname.com/</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725520702582/92cf5479-d3f5-4fd9-8f6c-4e9be5ea2108.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">⚠</div>
<div data-node-type="callout-text">Some tutorials say you should only copy the wwwroot folder. This is because the project is mostly Blazor Web Assembly standalone, which uses static site hosting environments like GitHub Pages, Azure Static Web Apps, or other platforms designed for serving static files directly. If your project has other requirements, like configuration files, DLLs, or hosted your Blazor WASM together with your ASP .Net core Web API, you'll need to copy all the files into the 'publish' folder. The server will serve the application from wwwroot, but it also needs other things outside the wwwroot folder.</div>
</div>

<h3 id="heading-edit-your-virtual-host-configuration-file">Edit your virtual host configuration file.</h3>
<p>Next, you'll want to configure the virtual host file. Head over to <code>/etc/apache2/sites-available</code> and edit your virtual host file, <code>yourdomainname.com.conf</code>, by adding a few lines (I've put the comments in there for you).</p>
<pre><code class="lang-apache"><span class="hljs-section">&lt;VirtualHost yourdomainname.com<span class="hljs-number">:443</span>&gt;</span>
    <span class="hljs-attribute">ServerAdmin</span> admin@yourdomainname.com
    <span class="hljs-attribute"><span class="hljs-nomarkup">ServerName</span></span> yourdomainname.com
    <span class="hljs-attribute">ServerAlias</span> www.yourdomainname.com
    <span class="hljs-attribute"><span class="hljs-nomarkup">DocumentRoot</span></span> /var/www/yourdomainname.com/wwwroot
    <span class="hljs-comment"># ---Start here---</span>
    <span class="hljs-attribute">ProxyPreserveHost</span>   <span class="hljs-literal">On</span>
    <span class="hljs-attribute">ProxyPassMatch</span>      ^/_blazor/(.*) http://localhost:<span class="hljs-number">5000</span>/_blazor/$<span class="hljs-number">1</span>
    <span class="hljs-attribute">ProxyPass</span>           /_blazor ws://localhost:<span class="hljs-number">5000</span>/_blazor
    <span class="hljs-attribute">ProxyPass</span>           / http://localhost:<span class="hljs-number">5000</span>/
    <span class="hljs-attribute">ProxyPassReverse</span>    / http://localhost:<span class="hljs-number">5000</span>/
    <span class="hljs-comment"># ---End here---</span>
    <span class="hljs-attribute">ErrorLog</span> <span class="hljs-variable">${APACHE_LOG_DIR}</span>/error.log
    <span class="hljs-attribute">CustomLog</span> <span class="hljs-variable">${APACHE_LOG_DIR}</span>/access.log combined
    <span class="hljs-attribute">SSLEngine</span> <span class="hljs-literal">on</span>
    <span class="hljs-attribute">SSLCertificateFile</span> /etc/ssl/private/certificate.crt
    <span class="hljs-attribute">SSLCertificateKeyFile</span> /etc/ssl/private/private.key
    <span class="hljs-attribute">SSLCertificateChainFile</span> /etc/ssl/private/ca-bundle.crt
<span class="hljs-section">&lt;/VirtualHost&gt;</span>
</code></pre>
<p>You can read it here for more details <a target="_blank" href="https://learn.microsoft.com/en-us/aspnet/core/blazor/host-and-deploy/server?view=aspnetcore-8.0">Host and deploy ASP.NET Core server-side Blazor apps | Microsoft Learn</a></p>
<h3 id="heading-enable-some-proxy-services">Enable some proxy services.</h3>
<p>After that you need to enable some proxy services. Please run these commands using your SSH:</p>
<pre><code class="lang-apache"><span class="hljs-attribute">a2enmod</span> proxy
<span class="hljs-attribute">a2enmod</span> proxy_wstunnel
<span class="hljs-attribute">a2enmod</span> proxy_http
<span class="hljs-attribute">a2enmod</span> proxy_balancer
<span class="hljs-attribute">a2enmod</span> lbmethod_byrequests
</code></pre>
<p>I got this from here <a target="_blank" href="https://youtu.be/bXK-F-uL7Qo?si=rn-XLTIb4WjbnQr8&amp;t=612">Deploying DotNet Core to Linux | Coding Droplets</a>, thanks to Coding Droplets.</p>
<p>Now you can run your Blazor app. You can use this command:</p>
<pre><code class="lang-apache"><span class="hljs-attribute">cd</span> /var/www/yourdomainname.com
<span class="hljs-attribute">dotnet</span> run YourWebAppName.dll
</code></pre>
<div data-node-type="callout">
<div data-node-type="callout-emoji">⚠</div>
<div data-node-type="callout-text">You'll need to register your application as a service that runs in the background. Otherwise, when you close the terminal, the web service will stop too.</div>
</div>

<p>To register your web app as a service and running in the background, go to the next step.</p>
<h3 id="heading-create-a-service-unit-file">Create a service unit file.</h3>
<p>Use your FTP client again, navigate to <code>/etc/systemd/system/</code> and make a service file. You can name whatever you want for example <code>YourWebService.service</code>. Inside the file you can write like this:</p>
<pre><code class="lang-apache">[<span class="hljs-attribute">Unit</span>]
<span class="hljs-attribute">Description</span> = My Blazor web app service.

[<span class="hljs-attribute">Service</span>]
<span class="hljs-attribute">WorkingDirectory</span> = /var/www/yourdomainname.com
<span class="hljs-attribute">ExecStart</span> = /usr/bin/dotnet /var/www/yourdomainname.com/YourWebAppName.dll
<span class="hljs-attribute">Restart</span> = always
<span class="hljs-attribute">RestartSec</span> = <span class="hljs-number">10</span>
<span class="hljs-attribute">KillSignal</span> = SIGINT
<span class="hljs-attribute">SysLogIdentifier</span> = YourWebAppName
<span class="hljs-attribute">User</span> = YourUserName
<span class="hljs-attribute">Environment</span> = ASPNETCORE_ENVIRONMENT = Production

[<span class="hljs-attribute">install</span>]
<span class="hljs-attribute">WantedBy</span> = multi.user.target
</code></pre>
<p>Now, enable and Run the service.</p>
<pre><code class="lang-apache"><span class="hljs-attribute">systemctl</span> start YourWebAppName
<span class="hljs-attribute">systemctl</span> enable YourWebAppName
</code></pre>
<p>Now that your web app service is up and running in the background, go ahead and open your website to test it out!</p>
]]></content:encoded></item><item><title><![CDATA[Guide to hosting .NET 8 ASP.NET Core and Blazor Web Assembly on a Linux VPS]]></title><description><![CDATA[To deploy your Asp .Net Core or Blazor Web Assembly 8.0 application to production, you have several options. You might be familiar with AWS and Azure, but a VPS could be an appealing choice if you're looking for a more budget-friendly solution.

💡
I...]]></description><link>https://krisoncode.com/guide-to-hosting-net-8-aspnet-core-and-blazor-web-assembly-on-a-linux-vps</link><guid isPermaLink="true">https://krisoncode.com/guide-to-hosting-net-8-aspnet-core-and-blazor-web-assembly-on-a-linux-vps</guid><category><![CDATA[.NET]]></category><category><![CDATA[asp.net core]]></category><category><![CDATA[Blazor Webassembly]]></category><category><![CDATA[vps]]></category><category><![CDATA[hosting]]></category><dc:creator><![CDATA[Kristiadhy]]></dc:creator><pubDate>Thu, 05 Sep 2024 04:33:31 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1725509969585/ecc92f28-e086-465b-8183-605f3596a4fa.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>To deploy your Asp .Net Core or Blazor Web Assembly 8.0 application to production, you have several options. You might be familiar with AWS and Azure, but a VPS could be an appealing choice if you're looking for a more budget-friendly solution.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">If you've already got a VPS service set up for your .net app, you can skip this article and check out the article on deploying your .net app. It's at <a target="_blank" href="https://kristiadhy.hashnode.dev/deploying-net-8-asp-net-core-and-blazor-web-assembly-applications-to-linux-vps">Deploying your .net app to Linux VPS</a>.</div>
</div>

<p>I previously used Azure to host Asp .Net Core or Blazor Web Assembly 8.0 application and it was easy. You simply select and set up the service in the Azure portal, link your GitHub account, publish your application, and point to your Azure account, and your website app will go online. Now let's explore another method using a VPS, which is also pretty simple if we're willing to understand the details.</p>
<p>Before you can host your Asp .Net Core or Blazor Web Assembly 8.0 application on a Linux VPS, you need to acquire and set it up.</p>
<h3 id="heading-get-a-vps-service">Get a VPS service.</h3>
<p>First, pick any provider that suits you. VPS prices are usually pretty affordable. Just remember, before you start installing Linux OS on your VPS server, <strong>make sure the OS version is compatible with the .Net version you want to install</strong>, in this case, .Net 8. You can check the supported .NET releases and the versions of Ubuntu they're supported here: <a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/core/install/linux-ubuntu#supported-distributions">.NET and Ubuntu overview - .NET | Microsoft Learn.</a> In my case, I use Ubuntu 20.04, just make sure to select the right OS during the initial VPS registration. A web server is typically pre-installed when you register for a VPS. If it’s not, you can choose from popular options like Nginx or Apache. This time, I’m going with Apache.</p>
<h3 id="heading-install-the-net-80-package">Install the .NET 8.0 package.</h3>
<p>After the Apache is installed on your server, now it's time to install the .Net 8.0 package. You can choose between the SDK and runtime options, depending on what you need. Check out this link for details: <a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/core/install/linux-ubuntu-install?tabs=dotnet8&amp;pivots=os-linux-ubuntu-2004">https://learn.microsoft.com/en-us/dotnet/core/install/linux-ubuntu-install?tabs=dotnet8&amp;pivots=os-linux-ubuntu-2004</a>.</p>
<p>Next, make sure you add the Microsoft package signing key to your trusted keys and include the package repository.</p>
<pre><code class="lang-apache"><span class="hljs-attribute">wget</span> https://packages.microsoft.com/config/ubuntu/<span class="hljs-number">20</span>.<span class="hljs-number">04</span>/packages-microsoft-prod.deb -O packages-microsoft-prod.deb sudo dpkg -i packages-microsoft-prod.deb rm packages-microsoft-prod.deb
</code></pre>
<p>To install the .NET runtime, just run the following commands:</p>
<pre><code class="lang-apache"><span class="hljs-attribute">sudo</span> apt-get update &amp;&amp; sudo apt-get install -y aspnetcore-runtime-<span class="hljs-number">8</span>.<span class="hljs-number">0</span>
</code></pre>
<h3 id="heading-create-a-directory-for-your-website">Create a directory for your website.</h3>
<p>You can do the following:</p>
<pre><code class="lang-apache"><span class="hljs-attribute">mkdir</span> -p /var/www/yourdomainname.com
</code></pre>
<p>Set the ownership of the directory. If you have set up a separate user, you can configure it for that user. But I haven't set up a specific user in this guide, so I'm still using root.</p>
<pre><code class="lang-apache"><span class="hljs-attribute">sudo</span> chown -R $USER:$USER /var/www/yourdomainname.com
</code></pre>
<p>Next, make sure the permissions on the directory allow you to read, write and execute files. And only give read and execute permissions to groups and others.</p>
<p>You can run the command below.</p>
<pre><code class="lang-apache"><span class="hljs-attribute">sudo</span> chmod -R <span class="hljs-number">755</span> /var/www/yourdomainname.com
</code></pre>
<h3 id="heading-change-the-default-virtual-host-configuration">Change the default virtual host configuration.</h3>
<p>Go to <code>/etc/apache2/sites-available/</code>, and you will find a file like this <code>000-default.conf</code>. This is the default virtual host configuration, you can copy its contents and create a new virtual host file for your site, you can name it <code>yourdomainname.com.conf</code>. Edit the contents as shown in the example below:</p>
<pre><code class="lang-apache"><span class="hljs-section">&lt;VirtualHost *<span class="hljs-number">:80</span>&gt;</span>
<span class="hljs-attribute">ServerAdmin</span> admin@yourdomainname.com
<span class="hljs-attribute"><span class="hljs-nomarkup">ServerName</span></span> yourdomainname.com
<span class="hljs-attribute">ServerAlias</span> www.yourdomainname.com
<span class="hljs-attribute"><span class="hljs-nomarkup">DocumentRoot</span></span> /var/www/yourdomainname.com
<span class="hljs-attribute">ErrorLog</span> <span class="hljs-variable">${APACHE_LOG_DIR}</span>/error.log
<span class="hljs-attribute">CustomLog</span> <span class="hljs-variable">${APACHE_LOG_DIR}</span>/access.log combined
<span class="hljs-section">&lt;/VirtualHost&gt;</span>
</code></pre>
<p>Replace <code>yourdomainname.com</code> with your domain name and adjust the document root to the folder path that will be used to store website data. The next step is to enable the virtual host configuration you have created.</p>
<p>Run the following command:</p>
<pre><code class="lang-apache"><span class="hljs-attribute">a2ensite</span> yourdomainname.com
</code></pre>
<p>Disable the default configuration and check that the virtual host configuration is correct by using the command below:</p>
<pre><code class="lang-apache"><span class="hljs-attribute">sudo</span> a<span class="hljs-number">2</span>dissite <span class="hljs-number">000</span>-default.conf
<span class="hljs-attribute">sudo</span> apache<span class="hljs-number">2</span>ctl configtest
</code></pre>
<p>If it is correct, the 'syntax OK' message will appear. Now restart the Apache service.</p>
<pre><code class="lang-apache"><span class="hljs-attribute">service</span> apache<span class="hljs-number">2</span> restart
</code></pre>
<p>Now you can test by accessing the domain name via your web browser.</p>
<h3 id="heading-install-and-upload-the-ssl-to-your-server">Install and upload the SSL to your server.</h3>
<p>First, you need to buy the SSL and choose a provider that suits you. In my case, I use Jagoan hosting service <a target="_blank" href="https://www.jagoanhosting.com/">https://www.jagoanhosting.com/</a>. You can find out how to configure it from the provider you bought the SSL from. For me, I use the following (You can change the website's language to English):</p>
<ol>
<li><p><a target="_blank" href="https://www.jagoanhosting.com/tutorial/tutorial-cpanel-2/tutorial-aktivasi-ssl">SSL Activation Tutorial via Member Area from Jagoan Hosting</a></p>
</li>
<li><p><a target="_blank" href="https://www.jagoanhosting.com/tutorial/tutorial-vps/cara-install-ssl-di-apache-ubuntu">How to Install SSL on Apache Ubuntu - Knowledge Base Jagoan Hosting Indonesia</a></p>
</li>
</ol>
<p>To simplify it I will summarize it briefly as follows:</p>
<ol>
<li><p>Generate the CSR.</p>
</li>
<li><p>Copy the private key to your storage and keep it.</p>
</li>
<li><p>Validate your SSL. There are some options to do this: By DNS name, by email, or by using HTTP/HTTPS.</p>
</li>
<li><p>Download your SSL certificate, it contains <strong>3 CA files and 1 CRT file</strong>.</p>
</li>
<li><p>Make a CA bundle file by combining the 3 CA files you have downloaded.</p>
</li>
<li><p>Now you have 3 files: private key, CA bundle, and the domain certificate.</p>
</li>
<li><p>Enable SSL module in Apache: <code>a2enmod ssl</code> and then restart the Apache service <code>apache2 service restart</code> .</p>
</li>
<li><p>Create a folder to store your SSL <code>mkdir -p /etc/ssl/private</code> and set the role to it <code>chmod 700 /etc/ssl/private</code>.</p>
</li>
<li><p>Upload your SSL to the server by using FTP client, in my case I use WinSCP.</p>
</li>
<li><p>Edit your virtual host configuration by adding these lines:</p>
<pre><code class="lang-apache">…
<span class="hljs-attribute">SSLEngine</span> <span class="hljs-literal">on</span>
<span class="hljs-attribute">SSLCertificateFile</span> /etc/ssl/private/certificate.crt
<span class="hljs-attribute">SSLCertificateKeyFile</span> /etc/ssl/private/private.key
<span class="hljs-attribute">SSLCertificateChainFile</span> /etc/ssl/private/ca-bundle.crt
…
</code></pre>
<p>Then restart apache with the command:</p>
<pre><code class="lang-apache"><span class="hljs-attribute">apache2</span> service restart
</code></pre>
<p>Now your Linux VPS should be ready. It's time to deploy your ASP .NET Core or Blazor Web Assembly 8.0 application!</p>
</li>
</ol>
]]></content:encoded></item></channel></rss>