<?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" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Ludmal De Silva - .Net Programmer]]></title><description><![CDATA[Hello there, I have written many software applications mainly using .Net tech and has a great passion for AI. ]]></description><link>https://blog.ludmal.com</link><image><url>https://substackcdn.com/image/fetch/$s_!Oqta!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ef5d19c-ff54-4ac4-a5af-471da1a046a7_1280x1280.png</url><title>Ludmal De Silva - .Net Programmer</title><link>https://blog.ludmal.com</link></image><generator>Substack</generator><lastBuildDate>Wed, 08 Apr 2026 04:34:11 GMT</lastBuildDate><atom:link href="https://blog.ludmal.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Ludmal De Silva]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[ludmal@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[ludmal@substack.com]]></itunes:email><itunes:name><![CDATA[Ludmal De Silva]]></itunes:name></itunes:owner><itunes:author><![CDATA[Ludmal De Silva]]></itunes:author><googleplay:owner><![CDATA[ludmal@substack.com]]></googleplay:owner><googleplay:email><![CDATA[ludmal@substack.com]]></googleplay:email><googleplay:author><![CDATA[Ludmal De Silva]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Killed by the First Train: What that 1830 Tragedy says about AI today]]></title><description><![CDATA[Back in 1830, Britain threw a huge party to show off its brand-new Liverpool & Manchester Railway, the first train line meant for everyday passengers.]]></description><link>https://blog.ludmal.com/p/killed-by-the-first-train-what-that</link><guid isPermaLink="false">https://blog.ludmal.com/p/killed-by-the-first-train-what-that</guid><dc:creator><![CDATA[Ludmal De Silva]]></dc:creator><pubDate>Tue, 27 May 2025 00:24:03 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Oqta!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ef5d19c-ff54-4ac4-a5af-471da1a046a7_1280x1280.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Back in 1830, Britain threw a huge party to show off its brand-new Liverpool &amp; Manchester Railway, the first train line meant for everyday passengers. Brass bands played, politicians waved from open coaches, and crowds lined the track to cheer the future. Halfway through the trip the trains paused at a little stop called Parkside so the engines could take on water. One of the VIPs on board, Liverpool politician William Huskisson, decided to step down onto the track bed to shake hands with the Duke of Wellington, who was sitting in another carriage on the oposite rail. In all the excitement Huskisson forgot&#8212;or maybe never really understood&#8212;that the other line was still in use. While he chatted, George Stephenson&#8217;s famous locomotive, the <em>Rocket</em>, came racing along at what people then considered break-neck speed, about forty kilometres an hour. Huskisson tried to scramble back into his coach, but the door swung the wrong way and left him stuck in the locomotive&#8217;s path. The <em>Rocket</em> hit him hard, crushing his leg, and despite a desperate dash to the nearest doctor he died that evening. His death stunned the country. Only hours earlier everyone had been cheering the miracle of steam; now a respected public figure had been killed simply because no one had laid down clear rules to keep people off a live track. The shock forced railway owners and lawmakers to act fast: they fenced off lines, added signal systems, trained drivers properly, and set up inspectors to probe every crash. In other words, progress only became truly safe once eveyone admitted how dangerous it could be.</p><p>Fast-forward to today and think about artificial intelligence. Chatbots draft contracts, cars drive themselves, and image tools create pictures that look real, all in a matter of seconds. The technology feels just as magical as steam engines must have felt in 1830, and it&#8217;s spreading just as quickly. But, like those early trains, AI can harm us in ways most of us don&#8217;t yet see. A language model can invent fake legal cases that fool a lawyer, a driverless car can misread a street and cause a crash, and a cloned voice can trick a parent into sending money to a scammer. The systems keep learning and scaling, yet we still don&#8217;t fully understand how or why they sometimes fail. That puts us in a Parkside moment of our own: we&#8217;re standing on the tracks, taking selfies, while an invisible locomotive comes around the bend. If we want the benefits of AI without the horror story, we need the modern versions of fences and signals. Independent testers should stress-check new models before they go public; clear rules must spell out who is responsible when things go wrong; and high-risk uses&#8212;health care, finance, critical infrastructure&#8212;should require certified operators who actually know what they&#8217;re turning loose. Good regulation isn&#8217;t a buzz-kill; it&#8217;s the safety net that lets everyone ride with confidence. The railway age only took off after people saw the danger and fixed it; AI will be no different, unless we ignore the warning and find ourselves repeating Huskisson&#8217;s tragic lesson.</p>]]></content:encoded></item><item><title><![CDATA[Understanding RAG(Retrieval-Augmented Generation)]]></title><description><![CDATA[Retrieval-Augmented Generation (RAG) is information retrieval and language generation to produce context-aware, acurate, and domain-specific responses.]]></description><link>https://blog.ludmal.com/p/understanding-ragretrieval-augmented</link><guid isPermaLink="false">https://blog.ludmal.com/p/understanding-ragretrieval-augmented</guid><dc:creator><![CDATA[Ludmal De Silva]]></dc:creator><pubDate>Tue, 19 Nov 2024 22:36:56 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!imfP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46767e07-dced-4dd4-bdd5-c43973631500_2662x1476.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Retrieval-Augmented Generation (RAG) is <strong>information retrieval</strong> and <strong>language generation</strong> to produce context-aware, acurate, and domain-specific responses. RAG integrates two main operations:</p><ol><li><p><strong>Retrieval</strong>: Finding the most relevant context from a large dataset or knowledge base.</p></li><li><p><strong>Generation</strong>: Using the retrived information as input to a generative AI model to produce a coherent and meaningful response.</p></li></ol><p>RAG's strength lies in its ability to combine external knowledge with a pre-trained model's language capabilities, ensuring outputs that are contextually relevant.</p><h3>How Retrieval Works: Vector Space and Semantic Search</h3><p>The retrieval process in RAG relies heavily on <strong>vector representations</strong> and <strong>similarity search</strong> within a vector space. Here's how this works:</p><ol><li><p><strong>Embedding the Query</strong>:</p><ul><li><p>When a user submits a query, it is transformed into a high-dimensional vector(see the diagmra below) representation using a pre-trained <strong>embedding model</strong> (e.g., OpenAI's embeddings).</p></li><li><p>These embeddings encode the semantic meaning of the query into a numerical format.</p></li></ul></li><li><p><strong>Knowledge Base Embedding</strong>:</p><ul><li><p>The documents or data within the knowledge base are also preprocessed and stored as vectors in a <strong>vector database</strong> (e.g., Pinecone or Supabase).</p></li><li><p>Each document or chunk (There are several chunking strategies. our framework uses the best combination for the given knowledge data) of text is represented by its semantic vector, ensuring that documents with similar meanings are clustered together in the vector space.</p></li></ul></li><li><p><strong>Similarity Search</strong>:</p><ul><li><p>The system calculates the similarity between the query vector and the document vectors using <strong>cosine similarity</strong> or other distance metrics.</p></li><li><p>Documents with the highest similarity scores are retrieved as the most relevant context.</p></li></ul></li><li><p><strong>Fine-Tuning Retrieval</strong>:</p><ul><li><p>Advanced implementations include <strong>dense passage retrieval (DPR)</strong> or <strong>hybrid retrieval</strong> (combining semantic and keyword-based search) to enhance accuracy, which me can consider for scenarios where accuracy is critical.Benefits of Using Vector Space Retrieval</p></li></ul></li></ol><p>Using vector space retrieval offers several advantages:</p><ol><li><p><strong>Semantic Understanding</strong>: Unlike keyword-based systems, vector representations capture the meaning of text, ensuring retrieval is based on context rather than exact matches.</p></li><li><p><strong>Scalability</strong>: Vector databases handle large-scale document collections efficiently, enabling rapid retrieval even in massive datasets.</p></li><li><p><strong>Domain Adaptability</strong>: By fine-tuning embeddings, vector space retrieval can be tailored for specific industries or use cases</p></li></ol><h3>Infonex RAG framework</h3><p>At Infonex, we have created a RAG framework that simplifies data chunking through vectorization and enables seamless retrieval using semantic search. This framework offers efficient and flexible chunking strategies. By pre-training it with your company's knowledge base, you can leverage its easy-to-integrate library for streamlined data management. If you'd like more information or need assistance implementing a similar strategy for your company&#8217;s data, feel free to email us at <strong>team@infonex.com.au</strong> or reach out on X (formerly Twitter) at <strong>@ludmal</strong>.<br></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!EUcZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe57faa75-0034-4eba-9e49-d58a47e7316c_450x263.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!EUcZ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe57faa75-0034-4eba-9e49-d58a47e7316c_450x263.png 424w, https://substackcdn.com/image/fetch/$s_!EUcZ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe57faa75-0034-4eba-9e49-d58a47e7316c_450x263.png 848w, https://substackcdn.com/image/fetch/$s_!EUcZ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe57faa75-0034-4eba-9e49-d58a47e7316c_450x263.png 1272w, https://substackcdn.com/image/fetch/$s_!EUcZ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe57faa75-0034-4eba-9e49-d58a47e7316c_450x263.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!EUcZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe57faa75-0034-4eba-9e49-d58a47e7316c_450x263.png" width="450" height="263" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e57faa75-0034-4eba-9e49-d58a47e7316c_450x263.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:263,&quot;width&quot;:450,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:38355,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!EUcZ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe57faa75-0034-4eba-9e49-d58a47e7316c_450x263.png 424w, https://substackcdn.com/image/fetch/$s_!EUcZ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe57faa75-0034-4eba-9e49-d58a47e7316c_450x263.png 848w, https://substackcdn.com/image/fetch/$s_!EUcZ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe57faa75-0034-4eba-9e49-d58a47e7316c_450x263.png 1272w, https://substackcdn.com/image/fetch/$s_!EUcZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe57faa75-0034-4eba-9e49-d58a47e7316c_450x263.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><br>See our RAG Product here: <br><a href="https://index.lightspire.ai">https://index.lightspire.ai</a></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!imfP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46767e07-dced-4dd4-bdd5-c43973631500_2662x1476.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!imfP!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46767e07-dced-4dd4-bdd5-c43973631500_2662x1476.png 424w, https://substackcdn.com/image/fetch/$s_!imfP!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46767e07-dced-4dd4-bdd5-c43973631500_2662x1476.png 848w, https://substackcdn.com/image/fetch/$s_!imfP!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46767e07-dced-4dd4-bdd5-c43973631500_2662x1476.png 1272w, https://substackcdn.com/image/fetch/$s_!imfP!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46767e07-dced-4dd4-bdd5-c43973631500_2662x1476.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!imfP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46767e07-dced-4dd4-bdd5-c43973631500_2662x1476.png" width="1456" height="807" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/46767e07-dced-4dd4-bdd5-c43973631500_2662x1476.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:807,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:295126,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!imfP!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46767e07-dced-4dd4-bdd5-c43973631500_2662x1476.png 424w, https://substackcdn.com/image/fetch/$s_!imfP!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46767e07-dced-4dd4-bdd5-c43973631500_2662x1476.png 848w, https://substackcdn.com/image/fetch/$s_!imfP!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46767e07-dced-4dd4-bdd5-c43973631500_2662x1476.png 1272w, https://substackcdn.com/image/fetch/$s_!imfP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46767e07-dced-4dd4-bdd5-c43973631500_2662x1476.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><h3>Conclusion</h3><p>RAG is a sophisticated AI framework that bridges the gap between static pre-trained models and real-time, dynamic information retrieval. By leveraging vector spaces for retrieval and generative models for response crafting. Infonex RAG framework capable of delivering accurate, context-aware, and up-to-date answers, making them indispensable for applications like customer support, knowledge management, and specialized domains. </p><p><br></p>]]></content:encoded></item><item><title><![CDATA[Event-Driven Microservices Architecture with .NET]]></title><description><![CDATA[Microservices have gained immense popularity due to their scalability, flexibility, and alignment with modern distributed systems.]]></description><link>https://blog.ludmal.com/p/event-driven-microservices-architecture</link><guid isPermaLink="false">https://blog.ludmal.com/p/event-driven-microservices-architecture</guid><dc:creator><![CDATA[Ludmal De Silva]]></dc:creator><pubDate>Fri, 06 Sep 2024 07:03:04 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Oqta!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ef5d19c-ff54-4ac4-a5af-471da1a046a7_1280x1280.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Microservices have gained immense popularity due to their scalability, flexibility, and alignment with modern distributed systems. One of the most effective ways to build highly scalable and resilient microservices is through an event-driven architecture. In this blog post, we will dive deep into <strong>event-driven microservices architecture in .NET</strong>, explore its benefits, key concepts, and demonstrate how to implement it with real code examples.</p><h3>Table of Contents</h3><p>1. What is Event-Driven Architecture?</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.ludmal.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Ludmal De Silva - .Net Programmer! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>2. Key Components of Event-Driven Microservices</p><p>3. Benefits of Event-Driven Architecture</p><p>4. Implementation of Event-Driven Microservices in .NET</p><ul><li><p>Step 1: Setting up a Publisher Microservice</p></li><li><p>Step 2: Creating a Consumer Microservice</p></li><li><p>Step 3: Event Handling and Event Bus (RabbitMQ Example)</p></li></ul><p>5. Error Handling and Message Reliability</p><p>6. Conclusion</p><h4>1. What is Event-Driven Architecture?</h4><p>In an event-driven architecture, services communicate by producing and consuming events. This architecture decouples microservices, allowing them to interact asynchronously. When a microservice performs a significant action, like creating a new order or completing a payment, it can publish an event. Other microservices that are interested in this event can then react accordingly without knowing the details of the event producer.</p><p><strong>Example:</strong> </p><p>In an e-commerce application, the <code>OrderService </code>may publish an event like <code>OrderCreated</code>. Other services like <code>InventoryService </code>and <code>BillingService </code>can subscribe to the event and update stock levels or process payments, respectively.</p><h4>2. Key Components of Event-Driven Microservices</h4><p>Event-driven microservices architecture is based on three key components:</p><p>1. <code>Event Producers</code>: These are the microservices that create and publish events. For example, when a new order is created, the <code>OrderService </code>publishes an <code>OrderCreated</code> event.</p><p>2. <code>Event Consumers</code>: These microservices listen for events and react to them. For example, <code>InventoryService </code>listens to <code>OrderCreated</code> events and reduces the inventory of the ordered product.</p><p>3. <code>Event Bus</code>: This is the communication channel through which events are transferred. Event buses like <code>RabbitMQ</code>, <code>Azure Service Bus</code>, or <code>Kafka</code> act as the middleware between the producer and consumer.</p><h4>3. Benefits of Event-Driven Architecture</h4><ol><li><p><strong>Loose Coupling</strong>: Producers and consumers are decoupled. They do not need to know about each other, making the system more modular and easier to maintain.</p></li><li><p><strong>Scalability</strong>: Asynchronous messaging allows microservices to scale independently.</p></li><li><p><strong>Resilience</strong>: Failures in one service do not block others. Consumers can handle events at their own pace.</p></li><li><p><strong>Extensibility</strong>: New services can be added without modifying the existing ones.</p></li></ol><h4>4. Implementation of Event-Driven Microservices in .NET</h4><p>Let's now implement an event-driven architecture in .NET using <code>RabbitMQ</code> as the event bus. We will have two services: <code>OrderService</code> (Publisher) and <code>InventoryService</code> (Consumer).</p><h5>Step 1: Setting up a Publisher Microservice (OrderService)</h5><p>In this step, we&#8217;ll create the <code>OrderService</code>, which will publish events when an order is created.</p><p><strong>Code Example: </strong><code>OrderService </code><strong>(Event Publisher)</strong></p><p>1. Install necessary RabbitMQ NuGet packages:</p><pre><code>   dotnet add package RabbitMQ.Client</code></pre><p>2. Define the event model:</p><pre><code>   public class OrderCreatedEvent
   {
       public int OrderId { get; set; }
       public string ProductName { get; set; }
       public int Quantity { get; set; }
   }</code></pre><p>3. Publish an event to RabbitMQ</p><pre><code>using RabbitMQ.Client;
using System.Text;
using Newtonsoft.Json;

public class EventPublisher
{
    public void PublishOrderCreatedEvent(OrderCreatedEvent orderEvent)
    {
        var factory = new ConnectionFactory() { HostName = "localhost" };
        using (var connection = factory.CreateConnection())
        using (var channel = connection.CreateModel())
        {
            channel.ExchangeDeclare(exchange: "order_exchange", type: "fanout");

            var message = JsonConvert.SerializeObject(orderEvent);
            var body = Encoding.UTF8.GetBytes(message);

            channel.BasicPublish(
                exchange: "order_exchange",
                routingKey: "",
                basicProperties: null,
                body: body);

            Console.WriteLine($"[x] Published OrderCreatedEvent for OrderId: {orderEvent.OrderId}");
        }
    }
}</code></pre><p>4. Trigger event when an order is created:</p><pre><code>public class OrderService
{
    private readonly EventPublisher _eventPublisher = new EventPublisher();

    public void CreateOrder(int orderId, string productName, int quantity)
    {
        // Business logic for order creation
        var orderCreatedEvent = new OrderCreatedEvent
        {
            OrderId = orderId,
            ProductName = productName,
            Quantity = quantity
        };

        _eventPublisher.PublishOrderCreatedEvent(orderCreatedEvent);
    }
}</code></pre><h5>Step 2: Creating a Consumer Microservice (InventoryService)</h5><p>Next, we&#8217;ll create the <code>InventoryService</code> that listens to <code>OrderCreated</code> events and updates inventory.</p><p><strong>Code Example: InventoryService (Event Consumer)</strong></p><p>1. Install the RabbitMQ package (same as the publisher).</p><p>2. Set up the consumer to subscribe to the RabbitMQ queue:</p><pre><code>using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System.Text;
using Newtonsoft.Json;

public class EventConsumer
{
    public void ConsumeOrderCreatedEvent()
    {
        var factory = new ConnectionFactory() { HostName = "localhost" };
        using (var connection = factory.CreateConnection())
        using (var channel = connection.CreateModel())
        {
            channel.ExchangeDeclare(exchange: "order_exchange", type: "fanout");
            var queueName = channel.QueueDeclare().QueueName;
            channel.QueueBind(queue: queueName, 
                              exchange: "order_exchange", 
                              routingKey: "");

            var consumer = new EventingBasicConsumer(channel);
            consumer.Received += (model, ea) =&gt;
            {
                var body = ea.Body.ToArray();
                var message = Encoding.UTF8.GetString(body);
                var orderEvent = JsonConvert.DeserializeObject&lt;OrderCreatedEvent&gt;(message);
                
                // Handle the event (e.g., update inventory)
                Console.WriteLine($"[x] Received OrderCreatedEvent for OrderId: {orderEvent.OrderId}");
            };

            channel.BasicConsume(queue: queueName, 
                                 autoAck: true, 
                                 consumer: consumer);

            Console.WriteLine(" [x] Waiting for events...");
            Console.ReadLine();
        }
    }
}</code></pre><p>3. Handling the event:</p><pre><code>public class InventoryService
{
    private readonly EventConsumer _eventConsumer = new EventConsumer();

    public void StartListening()
    {
        _eventConsumer.ConsumeOrderCreatedEvent();
    }
}</code></pre><h5>Step 3: Running the Microservices</h5><p>To run the services:</p><p>- Start the <code>OrderService</code> which creates an order and publishes an event.</p><p>- Start the <code>InventoryService</code> which listens to the event and processes it.</p><pre><code>class Program
{
    static void Main(string[] args)
    {
        var orderService = new OrderService();
        orderService.CreateOrder(1, "Laptop", 5);

        var inventoryService = new InventoryService();
        inventoryService.StartListening();
    }
}</code></pre><h4>5. Error Handling and Message Reliability</h4><p>In a real-world scenario, robust error handling and ensuring message delivery are essential. Here are some common strategies:</p><ul><li><p><strong>Retries</strong>: Use retries in case of failures when processing events.</p></li><li><p><strong>Dead Letter Queues (DLQ)</strong>: Messages that fail repeatedly can be moved to a DLQ for later inspection.</p></li><li><p><strong>Idempotency</strong>: Ensure that processing an event multiple times doesn't cause issues (e.g., reduce stock only once per order).</p></li></ul><p>You can implement retry logic and error handling using libraries like <strong>Polly</strong> in your microservices to ensure resilience.</p><pre><code>Policy

   .Handle&lt;Exception&gt;()
   .Retry(3)
   .Execute(() =&gt; { /* Process event */ });</code></pre><h4>6. Conclusion</h4><p>Event-driven microservices architecture in .NET allows for building highly decoupled, scalable, and resilient systems. By leveraging message brokers like RabbitMQ, services can communicate asynchronously without tightly coupling themselves. This architecture also simplifies the addition of new features without requiring changes to existing services.</p><p>In this post, we demonstrated how to implement a basic event-driven microservice architecture in .NET using RabbitMQ. With concepts like retries, dead-letter queues, and idempotency, you can build a system that is not only scalable but also fault-tolerant. In the next blog post, we'll explore how to use the MassTransit library to simplify integration with various messaging services, while leveraging its built-in support for resilience, retries, and the outbox pattern.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.ludmal.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Ludmal De Silva - .Net Programmer! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Building Resilient HTTP Clients with Polly: Retry and Circuit Breaker Patterns]]></title><description><![CDATA[In today's interconnected world, many applications rely on external APIs and services.]]></description><link>https://blog.ludmal.com/p/building-resilient-http-clients-with</link><guid isPermaLink="false">https://blog.ludmal.com/p/building-resilient-http-clients-with</guid><dc:creator><![CDATA[Ludmal De Silva]]></dc:creator><pubDate>Mon, 02 Sep 2024 09:45:37 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Oqta!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ef5d19c-ff54-4ac4-a5af-471da1a046a7_1280x1280.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In today's interconnected world, many applications rely on external APIs and services. However, network calls can fail due to various reasons such as temporary network issues, server overloads, or maintenance downtime. To build robust and fault-tolerant applications, it's crucial to implement resilience patterns. In this blog post, we'll explore how to use Polly, a .NET resilience and transient-fault-handling library, to create a resilient HTTP client using retry and circuit breaker patterns.</p><h3>Understanding Polly Retry Handler</h3><p>The retry pattern is a simple yet effective way to handle transient failures. When a request fails, instead of immediately throwing an exception, the application waits for a short period and then retries the request. This can often resolve issues caused by temporary network glitches or brief service unavailability.</p><p>Polly's retry handler allows you to specify:</p><p>1. The number of retry attempts</p><p>2. The delay between retries (which can be fixed or can increase with each attempt)</p><p>3. The types of exceptions or return results that should trigger a retry</p><p>In our example, we're using an exponential backoff strategy, where the delay increases exponentially with each retry attempt.</p><h3>Understanding Circuit Breaker Policy</h3><p>The circuit breaker pattern prevents an application from repeatedly trying to execute an operation that's likely to fail. It's like an electrical circuit breaker: when a problem is detected, it "trips" and stops the flow to protect the system.</p><p>The circuit breaker has three states:</p><p>1. Closed: When everything is normal, the circuit is closed, and requests are allowed through.</p><p>2. Open: If the number of failures exceeds a threshold, the circuit opens, and requests are not allowed through for a certain period.</p><p>3. Half-Open: After the timeout period, the circuit switches to half-open, allowing a limited number of requests through to test if the problem still exists.</p><p>This pattern is particularly useful for preventing cascading failures in distributed systems.</p><h3>Implementing Resilient HTTP Clients</h3><p>Let's break down the code and see how we're implementing these patterns:<br><br>We need to install following nuget packages:</p><pre><code>dotnet add package Polly
dotnet add package Microsoft.Extensions.Http.Polly</code></pre><pre><code>public static void AddResilientApiClient(this IServiceCollection services, ApiClientConfiguration apiClientConfiguration)
{
    services.AddHttpClient("ResilientHttpClient")
        .AddPolicyHandler(GetRetryPolicy(apiClientConfiguration))
        .AddPolicyHandler(GetCircuitBreakerPolicy(apiClientConfiguration));
}</code></pre><p>This method extends <code>IServiceCollection</code> to add a named <code>HttpClient</code> with both retry and circuit breaker policies.</p><h4>Retry Policy</h4><pre><code>private static IAsyncPolicy&lt;HttpResponseMessage&gt; GetRetryPolicy(ApiClientConfiguration config)
{
    return HttpPolicyExtensions
        .HandleTransientHttpError()
        .WaitAndRetryAsync(
            config.RetryCount,
            retryAttempt =&gt; TimeSpan.FromSeconds(Math.Pow(2, retryAttempt) * config.RetryAttemptInSeconds)
        );
}</code></pre><p>This method creates a retry policy that:</p><ul><li><p>Handles transient HTTP errors (NetworkError, 5xx, and 408 status codes)</p></li><li><p>Retries for a specified number of times</p></li><li><p>Uses exponential backoff for the delay between retries</p></li></ul><h4>Circuit Breaker Policy</h4><pre><code>private static IAsyncPolicy&lt;HttpResponseMessage&gt; GetCircuitBreakerPolicy(ApiClientConfiguration config)
{
    return HttpPolicyExtensions
        .HandleTransientHttpError()
        .CircuitBreakerAsync(
            config.HandledEventsAllowedBeforeBreaking,
            TimeSpan.FromSeconds(config.DurationOfBreakInSeconds)
        );
}</code></pre><p>This method creates a circuit breaker policy that:</p><ul><li><p>Handles the same transient HTTP errors as the retry policy</p></li><li><p>Opens the circuit after a specified number of consecutive failures</p></li><li><p>Keeps the circuit open for a specified duration before allowing a trial request</p></li></ul><h3>Usage</h3><p>To use this resilient HTTP client in your application, you would typically:</p><p>1. Define your `ApiClientConfiguration` with appropriate values.</p><p>2. Call `AddResilientApiClient` in your service configuration.</p><p>3. Inject and use the named `HttpClient` in your services.</p><p>For example:</p><pre><code>public class ApiClientConfiguration
{
    public int RetryCount { get; set; }
    public int RetryAttemptInSeconds { get; set; }
    public int HandledEventsAllowedBeforeBreaking { get; set; }
    public int DurationOfBreakInSeconds { get; set; }
}

services.AddResilientApiClient(new ApiClientConfiguration
{
    RetryCount = 3,
    RetryAttemptInSeconds = 2,
    HandledEventsAllowedBeforeBreaking = 5,
    DurationOfBreakInSeconds = 30
});</code></pre><p>Then, in your service:</p><pre><code>public class MyApiService

{
    private readonly HttpClient _httpClient;
    public MyApiService(IHttpClientFactory httpClientFactory)
    {
        _httpClient = httpClientFactory.CreateClient("ResilientHttpClient");
    }
    Use _httpClient for your API calls
}</code></pre><h3>Conclusion</h3><p>By implementing retry and circuit breaker patterns with Polly, we can create more resilient applications that can better handle transient failures and prevent cascading failures in distributed systems. This approach not only improves the reliability of our applications but also enhances the user experience by reducing the impact of temporary issues.</p><p>Remember, while these patterns can significantly improve your application's resilience, they're not a silver bullet. It's important to combine them with other best practices such as logging, monitoring, and alerting to create truly robust systems.</p>]]></content:encoded></item><item><title><![CDATA[Collection expressions in C# 12 ]]></title><description><![CDATA[Collection expressions in C# 12 are a new feature that simplifies the initialization of collection types.]]></description><link>https://blog.ludmal.com/p/collection-expressions-in-c-12</link><guid isPermaLink="false">https://blog.ludmal.com/p/collection-expressions-in-c-12</guid><dc:creator><![CDATA[Ludmal De Silva]]></dc:creator><pubDate>Wed, 07 Feb 2024 02:18:11 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Oqta!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ef5d19c-ff54-4ac4-a5af-471da1a046a7_1280x1280.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Collection expressions in C# 12 are a new feature that simplifies the initialization of collection types. With collection expressions, you can directly initialize collections such as lists, dictionaries, and arrays with the values you want, without the need for explicit constructors or method calls. </p><p>This feature allows you to write more concise and readable code when working with collections. It eliminates the need for repetitive initialization code, making your code more efficient and easier to maintain. Here are some of the samples. Also note that &#8216;var&#8217; cannot be used when declaring collections with the expressions.</p><pre><code>//Before
var names = new List&lt;string&gt; { "bill", "steve", "mark", "elon" }

//After
string[] names = ["bill", "steve", "mark", "elon"];

//Before
var numbers = new List&lt;int&gt; { 1, 2, 3, 4, 5 };

//After
int[] numbers = [1, 2, 3, 4, 5];</code></pre><p>The new syntax is much cooler and allows you to use the spread element, as shown below.</p><pre><code>string[] names1 = ["bill", "steve", "mark", "elon"];
string[] names2 = ["bill", "steve", "mark", "elon"];
List&lt;string&gt; allNames = [..names1, ..names2];</code></pre><p>Start utilizing these features to enhance the readability and elegance of your code.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.ludmal.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Ludmal De Silva - .Net Programmer! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[.NET Configuration with IOptions, IOptionsMonitor, and IOptionsSnapshot]]></title><description><![CDATA[Configuration management is a critical aspect of modern software development.]]></description><link>https://blog.ludmal.com/p/net-configuration-with-ioptions-ioptionsmonitor</link><guid isPermaLink="false">https://blog.ludmal.com/p/net-configuration-with-ioptions-ioptionsmonitor</guid><dc:creator><![CDATA[Ludmal De Silva]]></dc:creator><pubDate>Wed, 31 Jan 2024 20:17:04 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!ZUSQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F42eaade3-5a96-4fc7-a2a7-5849c468349a_1758x1414.gif" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ZUSQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F42eaade3-5a96-4fc7-a2a7-5849c468349a_1758x1414.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ZUSQ!,w_424,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F42eaade3-5a96-4fc7-a2a7-5849c468349a_1758x1414.gif 424w, https://substackcdn.com/image/fetch/$s_!ZUSQ!,w_848,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F42eaade3-5a96-4fc7-a2a7-5849c468349a_1758x1414.gif 848w, https://substackcdn.com/image/fetch/$s_!ZUSQ!,w_1272,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F42eaade3-5a96-4fc7-a2a7-5849c468349a_1758x1414.gif 1272w, https://substackcdn.com/image/fetch/$s_!ZUSQ!,w_1456,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F42eaade3-5a96-4fc7-a2a7-5849c468349a_1758x1414.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ZUSQ!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F42eaade3-5a96-4fc7-a2a7-5849c468349a_1758x1414.gif" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/42eaade3-5a96-4fc7-a2a7-5849c468349a_1758x1414.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:6479551,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ZUSQ!,w_424,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F42eaade3-5a96-4fc7-a2a7-5849c468349a_1758x1414.gif 424w, https://substackcdn.com/image/fetch/$s_!ZUSQ!,w_848,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F42eaade3-5a96-4fc7-a2a7-5849c468349a_1758x1414.gif 848w, https://substackcdn.com/image/fetch/$s_!ZUSQ!,w_1272,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F42eaade3-5a96-4fc7-a2a7-5849c468349a_1758x1414.gif 1272w, https://substackcdn.com/image/fetch/$s_!ZUSQ!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F42eaade3-5a96-4fc7-a2a7-5849c468349a_1758x1414.gif 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!iBVL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdcc86c06-a239-42fd-a939-e6c66f347c1b_1758x1414.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!iBVL!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdcc86c06-a239-42fd-a939-e6c66f347c1b_1758x1414.gif 424w, https://substackcdn.com/image/fetch/$s_!iBVL!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdcc86c06-a239-42fd-a939-e6c66f347c1b_1758x1414.gif 848w, https://substackcdn.com/image/fetch/$s_!iBVL!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdcc86c06-a239-42fd-a939-e6c66f347c1b_1758x1414.gif 1272w, https://substackcdn.com/image/fetch/$s_!iBVL!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdcc86c06-a239-42fd-a939-e6c66f347c1b_1758x1414.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!iBVL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdcc86c06-a239-42fd-a939-e6c66f347c1b_1758x1414.gif" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/dcc86c06-a239-42fd-a939-e6c66f347c1b_1758x1414.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:3083153,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!iBVL!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdcc86c06-a239-42fd-a939-e6c66f347c1b_1758x1414.gif 424w, https://substackcdn.com/image/fetch/$s_!iBVL!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdcc86c06-a239-42fd-a939-e6c66f347c1b_1758x1414.gif 848w, https://substackcdn.com/image/fetch/$s_!iBVL!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdcc86c06-a239-42fd-a939-e6c66f347c1b_1758x1414.gif 1272w, https://substackcdn.com/image/fetch/$s_!iBVL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdcc86c06-a239-42fd-a939-e6c66f347c1b_1758x1414.gif 1456w" sizes="100vw"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!d1zF!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa169be4b-ba49-46f1-bd1e-391f83326b8c_1758x1414.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!d1zF!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa169be4b-ba49-46f1-bd1e-391f83326b8c_1758x1414.gif 424w, https://substackcdn.com/image/fetch/$s_!d1zF!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa169be4b-ba49-46f1-bd1e-391f83326b8c_1758x1414.gif 848w, https://substackcdn.com/image/fetch/$s_!d1zF!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa169be4b-ba49-46f1-bd1e-391f83326b8c_1758x1414.gif 1272w, https://substackcdn.com/image/fetch/$s_!d1zF!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa169be4b-ba49-46f1-bd1e-391f83326b8c_1758x1414.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!d1zF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa169be4b-ba49-46f1-bd1e-391f83326b8c_1758x1414.gif" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a169be4b-ba49-46f1-bd1e-391f83326b8c_1758x1414.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:3083153,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!d1zF!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa169be4b-ba49-46f1-bd1e-391f83326b8c_1758x1414.gif 424w, https://substackcdn.com/image/fetch/$s_!d1zF!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa169be4b-ba49-46f1-bd1e-391f83326b8c_1758x1414.gif 848w, https://substackcdn.com/image/fetch/$s_!d1zF!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa169be4b-ba49-46f1-bd1e-391f83326b8c_1758x1414.gif 1272w, https://substackcdn.com/image/fetch/$s_!d1zF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa169be4b-ba49-46f1-bd1e-391f83326b8c_1758x1414.gif 1456w" sizes="100vw"></picture><div></div></div></a></figure></div><p></p><p>Configuration management is a critical aspect of modern software development. It allows developers to externalize application settings and parameters, making it easier to change application behavior without modifying code. In the .NET ecosystem, managing configuration has been greatly simplified with the introduction of `IOptions`, `IOptionsMonitor`, and `IOptionsSnapshot`. In this blog post, we'll explore these powerful tools and provide practical examples of how to use them in C#.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.ludmal.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Ludmal De Silva - .Net Programmer! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>IOptions</h2><p><code>IOptions </code>is part of the <code>Microsoft.Extensions.Options</code> library, which provides a framework for managing application configuration settings. It's a simple way to access configuration values in your application. To get started, you need to define a class representing your configuration:</p><pre><code>public class AppSettings

{

    public string ApiKey { get; set; }

    public int MaxItemsPerPage { get; set; }

}</code></pre><p>Next, you need to register this class and its associated configuration section in your <code>program.cs</code>:</p><pre><code>services.Configure&lt;AppSettings&gt;(Configuration.GetSection("AppSettings"));</code></pre><p>Now, you can use `<code>Options</code> to access these configuration values in your application:</p><pre><code>public class SomeService

{

    private readonly IOptions&lt;AppSettings&gt; _appSettings;

    public SomeService(IOptions&lt;AppSettings&gt; appSettings)

    {

        _appSettings = appSettings;

    }

    public string GetApiKey()

    {

        return _appSettings.Value.ApiKey;

    }

    public int GetMaxItemsPerPage()

    {

        return _appSettings.Value.MaxItemsPerPage;

    }

}</code></pre><p><code>IOptions</code> provides access to configuration values during application startup, and the values are cached for the application's lifetime.</p><h2>IOptionsMonitor</h2><p>While <code>IOptions</code> is suitable for most scenarios, sometimes you need the ability to dynamically update configuration values without restarting your application. This is where <code>IOptionsMonitor</code> comes into play. It allows you to create a configuration that can be monitored for changes.</p><p>First, define your configuration class as before:</p><pre><code>public class AppSettings

{

    public string ApiKey { get; set; }

    public int MaxItemsPerPage { get; set; }

}</code></pre><p>Then, register the class and its configuration section in your <code>program.cs</code>, but this time, use <code>IOptionsMonitor</code>:</p><pre><code>services.Configure&lt;AppSettings&gt;(Configuration.GetSection("AppSettings"));

services.AddSingleton&lt;IOptionsMonitor&lt;AppSettings&gt;, OptionsMonitor&lt;AppSettings&gt;&gt;();</code></pre><p>Now, you can use <code>IOptionsMonitor </code>to access your configuration values:</p><pre><code>public class SomeService

{

    private readonly IOptionsMonitor&lt;AppSettings&gt; _appSettings;

    public SomeService(IOptionsMonitor&lt;AppSettings&gt; appSettings)

    {

        _appSettings = appSettings;

    }

    public string GetApiKey()

    {

        return _appSettings.CurrentValue.ApiKey;

    }

    public int GetMaxItemsPerPage()

    {

        return _appSettings.CurrentValue.MaxItemsPerPage;

    }

}</code></pre><p>With <code>IOptionsMonitor</code>, you can react to configuration changes in real-time without needing to restart your application.</p><h2>IOptionsSnapshot</h2><p><code>IOptionsSnapshot</code> is yet another tool in your configuration toolbox. It provides a scoped view of configuration settings, ideal for short-lived operations or background tasks. To use it, follow the same setup as with <code>IOptions</code>:</p><pre><code>public class AppSettings

{

    public string ApiKey { get; set; }

    public int MaxItemsPerPage { get; set; }

}</code></pre><p>// <code>program.cs</code></p><pre><code>services.Configure&lt;AppSettings&gt;(Configuration.GetSection("AppSettings"));</code></pre><p>Then, inject <code>IOptionsSnapshot</code> into your scoped components:</p><pre><code>public class ScopedService

{

    private readonly IOptionsSnapshot&lt;AppSettings&gt; _appSettings;

    public ScopedService(IOptionsSnapshot&lt;AppSettings&gt; appSettings)

    {

        _appSettings = appSettings;

    }

    public string GetApiKey()

    {

        return _appSettings.Value.ApiKey;

    }

    public int GetMaxItemsPerPage()

    {

        return _appSettings.Value.MaxItemsPerPage;

    }

}</code></pre><p><code>IOptionsSnapshot</code> provides a snapshot of configuration values, which is scoped to the current request or operation. This is particularly useful in scenarios where you need a unique set of configuration values for each user or operation.</p><h2>Conclusion</h2><p>In this blog post, we've explored three powerful tools for managing configuration in .NET applications: <code>IOptions</code>, <code>IOptionsMonitor</code>, and <code>IOptionsSnapshot</code>. By understanding the differences and use cases for each of these, you can efficiently manage configuration settings in your C# applications. Whether you need cached values, real-time updates, or scoped configurations, these options have got you covered, helping you build more flexible and maintainable applications.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.ludmal.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Ludmal De Silva - .Net Programmer! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Simplify your configuration with this pattern]]></title><description><![CDATA[The pattern described here is widely recognized as one of the most commonly employed and elegant approaches for configuring settings.]]></description><link>https://blog.ludmal.com/p/elegent-way-to-add-configurations</link><guid isPermaLink="false">https://blog.ludmal.com/p/elegent-way-to-add-configurations</guid><dc:creator><![CDATA[Ludmal De Silva]]></dc:creator><pubDate>Thu, 25 Jan 2024 19:54:30 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!ql7r!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe6c265c-7058-4c56-9db0-9c9691cf7340_1024x1024.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ql7r!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe6c265c-7058-4c56-9db0-9c9691cf7340_1024x1024.webp" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ql7r!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe6c265c-7058-4c56-9db0-9c9691cf7340_1024x1024.webp 424w, https://substackcdn.com/image/fetch/$s_!ql7r!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe6c265c-7058-4c56-9db0-9c9691cf7340_1024x1024.webp 848w, https://substackcdn.com/image/fetch/$s_!ql7r!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe6c265c-7058-4c56-9db0-9c9691cf7340_1024x1024.webp 1272w, https://substackcdn.com/image/fetch/$s_!ql7r!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe6c265c-7058-4c56-9db0-9c9691cf7340_1024x1024.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ql7r!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe6c265c-7058-4c56-9db0-9c9691cf7340_1024x1024.webp" width="490" height="490" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fe6c265c-7058-4c56-9db0-9c9691cf7340_1024x1024.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:490,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;A simple and generic flowchart with a clear and professional design. The flowchart should include a start point, followed by a sequence of three rectangular process steps, each connected by arrows. Include two diamond-shaped decision points, each leading to different paths based on 'Yes' or 'No' choices. The flowchart should culminate in an end point. Use a color scheme of blue and gray for the shapes and black for the text and arrows, ensuring good readability and a clean, modern appearance. The overall design should be suitable for business or educational purposes.&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="A simple and generic flowchart with a clear and professional design. The flowchart should include a start point, followed by a sequence of three rectangular process steps, each connected by arrows. Include two diamond-shaped decision points, each leading to different paths based on 'Yes' or 'No' choices. The flowchart should culminate in an end point. Use a color scheme of blue and gray for the shapes and black for the text and arrows, ensuring good readability and a clean, modern appearance. The overall design should be suitable for business or educational purposes." title="A simple and generic flowchart with a clear and professional design. The flowchart should include a start point, followed by a sequence of three rectangular process steps, each connected by arrows. Include two diamond-shaped decision points, each leading to different paths based on 'Yes' or 'No' choices. The flowchart should culminate in an end point. Use a color scheme of blue and gray for the shapes and black for the text and arrows, ensuring good readability and a clean, modern appearance. The overall design should be suitable for business or educational purposes." srcset="https://substackcdn.com/image/fetch/$s_!ql7r!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe6c265c-7058-4c56-9db0-9c9691cf7340_1024x1024.webp 424w, https://substackcdn.com/image/fetch/$s_!ql7r!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe6c265c-7058-4c56-9db0-9c9691cf7340_1024x1024.webp 848w, https://substackcdn.com/image/fetch/$s_!ql7r!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe6c265c-7058-4c56-9db0-9c9691cf7340_1024x1024.webp 1272w, https://substackcdn.com/image/fetch/$s_!ql7r!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe6c265c-7058-4c56-9db0-9c9691cf7340_1024x1024.webp 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The pattern described here is widely recognized as one of the most commonly employed and elegant approaches for configuring settings. It has been extensively utilized in both internal .NET libraries and third-party libraries. This pattern can serve as a valuable guide when registering configurations in program or startup classes for your internal libraries. For instance, if you are developing a library and wish to allow client developers to configure options during startup, this pattern can be of great assistance.</p><p>To illustrate this concept, let's consider the hypothetical scenario of designing a <code>ApiRetryOptions</code> class with two retry options &#8212; <code>MaxRetries</code> &amp; <code>DelayInSeconds</code>. Within this class, default values are assigned to the <code>MaxRetries</code> and <code>DelayInSeconds</code> properties.</p><pre><code><code>public class ApiRetryOptions
{
    public int MaxRetries { get; set; } = 3;
    public int DelayInSeconds { get; set; } = 1000;
}

</code></code></pre><p>Next, we create an extension method for this class, enabling us to register it during startup:</p><pre><code><code>public static class ApiRetryOptionsExtensions
{
    public static void AddApiRetryOptions(this IServiceCollection services, Action&lt;ApiRetryOptions&gt;? options = null)
    {
        if (options != null) services.Configure(options);
    }
}

</code></code></pre><p>When registering the class with the Service Collection, it is important to note the use of the <code>Action</code> delegate. In C#, an <code>Action</code> represents a method with no parameters and no return value. In this case, we require an Action delegate to be registered with the built-in service configuration. The .NET framework provides a convenient method called <code>services.Configure(Action&lt;&gt;)</code> that allows us to accomplish this, as demonstrated in the example above.</p><p>Now, let's proceed to register this configuration in the program class. The beauty of this pattern lies in its ability to facilitate easy configuration during startup for any library registration. In this example, we override the default values:</p><pre><code><code>builder.Services.AddApiRetryOptions(options =&gt;
{
    options.MaxRetries = 1;
    options.MaxRetries = 4000;
});

</code></code></pre><p>Finally, we can integrate this configuration into our client code using the <code>IOptions</code> class:</p><pre><code><code>app.MapGet("/retry", (IOptions&lt;ApiRetryOptions&gt; retry) =&gt; retry.Value.MaxRetries);
</code></code></pre><p>By adopting this pattern, you can align your library configuration with the established conventions used in .NET libraries, thereby ensuring consistency and coherence.</p>]]></content:encoded></item><item><title><![CDATA[Ahead of Time Compilation (AOT) in .NET 8 ]]></title><description><![CDATA[Ahead of Time Compilation (AOT) is a technology that has been gaining momentum in the world of software development, and .NET 8 brings exciting advancements in this area.]]></description><link>https://blog.ludmal.com/p/ahead-of-time-compilation-aot-in</link><guid isPermaLink="false">https://blog.ludmal.com/p/ahead-of-time-compilation-aot-in</guid><dc:creator><![CDATA[Ludmal De Silva]]></dc:creator><pubDate>Wed, 10 Jan 2024 05:30:15 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!o9CY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1ec4afb-82f6-489d-9fc2-ccf12e8a85d4_1024x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!o9CY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1ec4afb-82f6-489d-9fc2-ccf12e8a85d4_1024x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!o9CY!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1ec4afb-82f6-489d-9fc2-ccf12e8a85d4_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!o9CY!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1ec4afb-82f6-489d-9fc2-ccf12e8a85d4_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!o9CY!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1ec4afb-82f6-489d-9fc2-ccf12e8a85d4_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!o9CY!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1ec4afb-82f6-489d-9fc2-ccf12e8a85d4_1024x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!o9CY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1ec4afb-82f6-489d-9fc2-ccf12e8a85d4_1024x1024.png" width="1024" height="1024" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a1ec4afb-82f6-489d-9fc2-ccf12e8a85d4_1024x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2449524,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!o9CY!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1ec4afb-82f6-489d-9fc2-ccf12e8a85d4_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!o9CY!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1ec4afb-82f6-489d-9fc2-ccf12e8a85d4_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!o9CY!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1ec4afb-82f6-489d-9fc2-ccf12e8a85d4_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!o9CY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1ec4afb-82f6-489d-9fc2-ccf12e8a85d4_1024x1024.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.ludmal.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.ludmal.com/subscribe?"><span>Subscribe now</span></a></p><p>Ahead of Time Compilation (AOT) is a technology that has been gaining momentum in the world of software development, and .NET 8 brings exciting advancements in this area. AOT offers significant advantages in terms of performance and security, making it an essential feature for modern .NET applications. Let's explore AOT in .NET 8 and its benefits.</p><p>What is Ahead of Time Compilation (AOT)?</p><p>AOT is a compilation technique that converts high-level code, such as C# or F#, into native machine code before the application is run. Unlike Just-In-Time (JIT) compilation, which compiles code at runtime, AOT compiles code ahead of time, resulting in several advantages:&nbsp;</p><p><strong>Performance Boost:</strong> AOT-compiled code runs faster since it doesn't require runtime compilation. This leads to reduced startup times and improved overall application performance.</p><p><strong>Predictable Behavior: </strong>AOT eliminates the JIT warm-up time, ensuring consistent and predictable application behavior across different executions.</p><p><strong>Improved Security:</strong> AOT reduces the attack surface by removing the need for a JIT compiler at runtime, making it harder for attackers to exploit vulnerabilities.</p><p>.NET 8 introduces enhanced AOT support, making it easier than ever to leverage this technology in your applications. Here are some key improvements:</p><p><strong>Single-File AOT: </strong>.NET 8 allows you to create single-file AOT-compiled applications, simplifying deployment and distribution.</p><p><strong>Cross-Platform AOT: </strong>AOT is no longer limited to Windows. .NET 8 brings cross-platform AOT support, enabling AOT-compiled apps to run on various operating systems.</p><p><strong>Improved Interoperability:</strong> .NET 8 enhances the interoperability between AOT-compiled code and JIT-compiled code, ensuring smooth integration of AOT into existing projects.</p><p>In .NET 8, AOT makes your software faster, safer, and works on different devices. I Love it since it makes the Minimal Apis even faster.&nbsp;</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.ludmal.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Ludmal&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[How to add Api key validation in Swagger]]></title><description><![CDATA[Just a quick post on how to add api key validation in swagger docs.]]></description><link>https://blog.ludmal.com/p/how-to-add-api-key-validation-in-swagger</link><guid isPermaLink="false">https://blog.ludmal.com/p/how-to-add-api-key-validation-in-swagger</guid><dc:creator><![CDATA[Ludmal De Silva]]></dc:creator><pubDate>Sat, 16 Dec 2023 21:11:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!c3oz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b26afe0-cc6d-4d44-958f-00e52fd67366_1024x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!c3oz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b26afe0-cc6d-4d44-958f-00e52fd67366_1024x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!c3oz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b26afe0-cc6d-4d44-958f-00e52fd67366_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!c3oz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b26afe0-cc6d-4d44-958f-00e52fd67366_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!c3oz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b26afe0-cc6d-4d44-958f-00e52fd67366_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!c3oz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b26afe0-cc6d-4d44-958f-00e52fd67366_1024x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!c3oz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b26afe0-cc6d-4d44-958f-00e52fd67366_1024x1024.png" width="1024" height="1024" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7b26afe0-cc6d-4d44-958f-00e52fd67366_1024x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1917352,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!c3oz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b26afe0-cc6d-4d44-958f-00e52fd67366_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!c3oz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b26afe0-cc6d-4d44-958f-00e52fd67366_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!c3oz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b26afe0-cc6d-4d44-958f-00e52fd67366_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!c3oz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b26afe0-cc6d-4d44-958f-00e52fd67366_1024x1024.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>Just a quick post on how to add api key validation in swagger docs. Pretty easy and here is the code to add in <code>AddSwaggerGen</code> in the <code>program.cs</code> file. You can define your own Api key validation middleware.</p><pre><code>
&nbsp;&nbsp; &nbsp;builder.Services.AddSwaggerGen(c =&gt;
&nbsp;&nbsp; &nbsp;{
    &nbsp;&nbsp; &nbsp;c.AddSecurityDefinition("api_key", new OpenApiSecurityScheme
    &nbsp;&nbsp; &nbsp;{
        &nbsp;&nbsp; &nbsp;Type = SecuritySchemeType.ApiKey,
        &nbsp;&nbsp; &nbsp;Name = "Authorization",
        &nbsp;&nbsp; &nbsp;In = ParameterLocation.Header,
        &nbsp;&nbsp; &nbsp;Description = "API key needed to access the endpoints."
    &nbsp;&nbsp; &nbsp;});

    &nbsp;&nbsp; &nbsp;// Define your security requirement (optional)
    &nbsp;&nbsp; &nbsp;c.AddSecurityRequirement(new OpenApiSecurityRequirement
    &nbsp;&nbsp; &nbsp;{
       &nbsp;&nbsp; &nbsp; {
            &nbsp;&nbsp; &nbsp;new OpenApiSecurityScheme
           &nbsp;&nbsp; &nbsp; {
               &nbsp;&nbsp; &nbsp; Reference = new OpenApiReference
                &nbsp;&nbsp; &nbsp;{
                &nbsp;&nbsp; &nbsp;    Type = ReferenceType.SecurityScheme,
                &nbsp;&nbsp; &nbsp;    Id = "api_key"
               &nbsp;&nbsp; &nbsp; }
            &nbsp;&nbsp; &nbsp;},
           &nbsp;&nbsp; &nbsp; new string[] { }
        &nbsp;&nbsp; &nbsp;}
    &nbsp;&nbsp; &nbsp;});
&nbsp;&nbsp; &nbsp;});
</code></pre>]]></content:encoded></item><item><title><![CDATA[Title: Announcing My New Book: Crafting Minimal APIs with a Functional Twist!]]></title><description><![CDATA[I am thrilled to share with all of you a journey I've passionately embarked on &#8211; writing a book dedicated to the world of Minimal APIs with a functional approach.]]></description><link>https://blog.ludmal.com/p/title-announcing-my-new-book-crafting</link><guid isPermaLink="false">https://blog.ludmal.com/p/title-announcing-my-new-book-crafting</guid><dc:creator><![CDATA[Ludmal De Silva]]></dc:creator><pubDate>Wed, 06 Dec 2023 07:48:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Hzne!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87882fa8-c79f-4def-8669-f054e8ad20e7_1226x1914.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Hzne!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87882fa8-c79f-4def-8669-f054e8ad20e7_1226x1914.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Hzne!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87882fa8-c79f-4def-8669-f054e8ad20e7_1226x1914.png 424w, https://substackcdn.com/image/fetch/$s_!Hzne!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87882fa8-c79f-4def-8669-f054e8ad20e7_1226x1914.png 848w, https://substackcdn.com/image/fetch/$s_!Hzne!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87882fa8-c79f-4def-8669-f054e8ad20e7_1226x1914.png 1272w, https://substackcdn.com/image/fetch/$s_!Hzne!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87882fa8-c79f-4def-8669-f054e8ad20e7_1226x1914.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Hzne!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87882fa8-c79f-4def-8669-f054e8ad20e7_1226x1914.png" width="1226" height="1914" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/87882fa8-c79f-4def-8669-f054e8ad20e7_1226x1914.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1914,&quot;width&quot;:1226,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:378084,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Hzne!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87882fa8-c79f-4def-8669-f054e8ad20e7_1226x1914.png 424w, https://substackcdn.com/image/fetch/$s_!Hzne!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87882fa8-c79f-4def-8669-f054e8ad20e7_1226x1914.png 848w, https://substackcdn.com/image/fetch/$s_!Hzne!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87882fa8-c79f-4def-8669-f054e8ad20e7_1226x1914.png 1272w, https://substackcdn.com/image/fetch/$s_!Hzne!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87882fa8-c79f-4def-8669-f054e8ad20e7_1226x1914.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>I am thrilled to share with all of you a journey I've passionately embarked on &#8211; writing a book dedicated to the world of Minimal APIs with a functional approach. This book is not just a guide; it's a deep dive into the efficient and innovative world of Minimal APIs, explored through the lens of functional programming. I've poured my experience and insights into this work, aiming to offer a fresh perspective on building lean, effective APIs. Whether you're a seasoned developer or just starting out, this book promises to enrich your understanding and skills in creating powerful, minimalistic APIs with a functional twist. Stay tuned for more updates and snippets from my book!</p><p>Coming Soon!</p>]]></content:encoded></item><item><title><![CDATA[Azure Service Bus Queue RetryOptions]]></title><description><![CDATA[It's crucial to effectively handle transient errors during message processing.]]></description><link>https://blog.ludmal.com/p/azure-service-bus-queue-retryoptions</link><guid isPermaLink="false">https://blog.ludmal.com/p/azure-service-bus-queue-retryoptions</guid><dc:creator><![CDATA[Ludmal De Silva]]></dc:creator><pubDate>Wed, 15 Nov 2023 03:51:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!z9Ef!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8306c756-733e-44dd-971b-f899b4a400d1_1622x847.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!z9Ef!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8306c756-733e-44dd-971b-f899b4a400d1_1622x847.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!z9Ef!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8306c756-733e-44dd-971b-f899b4a400d1_1622x847.png 424w, https://substackcdn.com/image/fetch/$s_!z9Ef!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8306c756-733e-44dd-971b-f899b4a400d1_1622x847.png 848w, https://substackcdn.com/image/fetch/$s_!z9Ef!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8306c756-733e-44dd-971b-f899b4a400d1_1622x847.png 1272w, https://substackcdn.com/image/fetch/$s_!z9Ef!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8306c756-733e-44dd-971b-f899b4a400d1_1622x847.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!z9Ef!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8306c756-733e-44dd-971b-f899b4a400d1_1622x847.png" width="1456" height="760" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8306c756-733e-44dd-971b-f899b4a400d1_1622x847.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:760,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2386731,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!z9Ef!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8306c756-733e-44dd-971b-f899b4a400d1_1622x847.png 424w, https://substackcdn.com/image/fetch/$s_!z9Ef!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8306c756-733e-44dd-971b-f899b4a400d1_1622x847.png 848w, https://substackcdn.com/image/fetch/$s_!z9Ef!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8306c756-733e-44dd-971b-f899b4a400d1_1622x847.png 1272w, https://substackcdn.com/image/fetch/$s_!z9Ef!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8306c756-733e-44dd-971b-f899b4a400d1_1622x847.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>It's crucial to effectively handle transient errors during message processing. Many developers often attempt to create their own solutions for this issue, but there is already an elegant, built-in solution in the Azure Service Bus client. The key is to create a RetryOption and pass it to the Service Bus client during its creation. This straightforward approach leverages the native capabilities of Azure Service Bus to manage transient errors efficiently.</p><pre><code>builder.AddServiceBusClient(settings.ConnectionStrings.AzureWebJobsServiceBus).ConfigureOptions(options =&gt;
    {
        options.RetryOptions = new ServiceBusRetryOptions()
        {
            Delay = TimeSpan.FromSeconds(30), MaxDelay = TimeSpan.FromSeconds(30),
            Mode = ServiceBusRetryMode.Exponential, MaxRetries = 3
        };
    });</code></pre><p></p>]]></content:encoded></item><item><title><![CDATA[Structured logging .Net]]></title><description><![CDATA[Structured logging is an approach to logging that captures data in a way that's easy to parse and analyze, unlike traditional logging, which often involves plain text messages.]]></description><link>https://blog.ludmal.com/p/structured-logging-net</link><guid isPermaLink="false">https://blog.ludmal.com/p/structured-logging-net</guid><dc:creator><![CDATA[Ludmal De Silva]]></dc:creator><pubDate>Thu, 02 Nov 2023 19:52:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!p3NG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F06dd8d83-652c-4aef-ac73-0b5d40d4bdd1_512x512" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!p3NG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F06dd8d83-652c-4aef-ac73-0b5d40d4bdd1_512x512" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!p3NG!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F06dd8d83-652c-4aef-ac73-0b5d40d4bdd1_512x512 424w, https://substackcdn.com/image/fetch/$s_!p3NG!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F06dd8d83-652c-4aef-ac73-0b5d40d4bdd1_512x512 848w, https://substackcdn.com/image/fetch/$s_!p3NG!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F06dd8d83-652c-4aef-ac73-0b5d40d4bdd1_512x512 1272w, https://substackcdn.com/image/fetch/$s_!p3NG!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F06dd8d83-652c-4aef-ac73-0b5d40d4bdd1_512x512 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!p3NG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F06dd8d83-652c-4aef-ac73-0b5d40d4bdd1_512x512" width="512" height="512" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/06dd8d83-652c-4aef-ac73-0b5d40d4bdd1_512x512&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:512,&quot;width&quot;:512,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!p3NG!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F06dd8d83-652c-4aef-ac73-0b5d40d4bdd1_512x512 424w, https://substackcdn.com/image/fetch/$s_!p3NG!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F06dd8d83-652c-4aef-ac73-0b5d40d4bdd1_512x512 848w, https://substackcdn.com/image/fetch/$s_!p3NG!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F06dd8d83-652c-4aef-ac73-0b5d40d4bdd1_512x512 1272w, https://substackcdn.com/image/fetch/$s_!p3NG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F06dd8d83-652c-4aef-ac73-0b5d40d4bdd1_512x512 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">programming</figcaption></figure></div><p>Structured logging is an approach to logging that captures data in a way that's easy to parse and analyze, unlike traditional logging, which often involves plain text messages. In structured logging, log entries are composed of discrete fields, such as time stamps, log levels, messages, and other contextual information.</p><p>Here is an example:</p><p> _logger.LogInformation("Request received {@Request}", request);</p><p><strong>Why it is important? Well there are few main reasons.&nbsp;</strong></p><p><strong>Searchability and Filtering</strong>: Structured logs allow for easier searching and filtering since each part of the log message is a distinct field. This makes it straightforward to find all logs related to a specific event, error code, or user action. As you can see in the following example, logs are written in a json format where you can easily search.&nbsp;</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!uB-8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8b011b0-f794-43bf-ab3a-6284ba0590ca_564x159.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!uB-8!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8b011b0-f794-43bf-ab3a-6284ba0590ca_564x159.png 424w, https://substackcdn.com/image/fetch/$s_!uB-8!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8b011b0-f794-43bf-ab3a-6284ba0590ca_564x159.png 848w, https://substackcdn.com/image/fetch/$s_!uB-8!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8b011b0-f794-43bf-ab3a-6284ba0590ca_564x159.png 1272w, https://substackcdn.com/image/fetch/$s_!uB-8!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8b011b0-f794-43bf-ab3a-6284ba0590ca_564x159.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!uB-8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8b011b0-f794-43bf-ab3a-6284ba0590ca_564x159.png" width="564" height="159" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c8b011b0-f794-43bf-ab3a-6284ba0590ca_564x159.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:159,&quot;width&quot;:564,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!uB-8!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8b011b0-f794-43bf-ab3a-6284ba0590ca_564x159.png 424w, https://substackcdn.com/image/fetch/$s_!uB-8!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8b011b0-f794-43bf-ab3a-6284ba0590ca_564x159.png 848w, https://substackcdn.com/image/fetch/$s_!uB-8!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8b011b0-f794-43bf-ab3a-6284ba0590ca_564x159.png 1272w, https://substackcdn.com/image/fetch/$s_!uB-8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8b011b0-f794-43bf-ab3a-6284ba0590ca_564x159.png 1456w" sizes="100vw"></picture><div></div></div></a></figure></div><p><br><strong>Performance: </strong>When you use structured logging with deferred execution, such as with Serilog or NLog, the actual string interpolation doesn't happen unless the log level is enabled. This means you avoid unnecessary string manipulation if, for example, your debug logs are turned off in a production environment.</p><p><strong>Why you shouldn't use logging with string interpolation?</strong></p><p>Utilizing string interpolation in logging compromises the capability to efficiently search or filter through log entries. Additionally, it necessitates memory allocation for each log entry created, due to the fact that, unlike structured logging, the template is not established at compile-time, resulting in potentially higher overhead and less optimal performance.</p><p> _logger.LogInformation($"Request received {JsonSerializer.Serialize(request)}");</p><p>In conclusion, it is imperative to exercise discretion when implementing structured logging, particularly to mitigate the risks of inadvertently logging sensitive information or excessively large objects. Developers have the capacity to introduce entire objects into the log data, which could lead to breaches of privacy, security concerns, and potential performance issues due to the increased size and complexity of the log data. Therefore, it is essential to establish and adhere to best practices regarding what data should be logged, ensuring that the logs remain informative and valuable without compromising security or performance.</p>]]></content:encoded></item><item><title><![CDATA[.NET 8 Dependency Injection Keyed Services]]></title><description><![CDATA[In .NET 8, Inversion of Control (IOC) has been enhanced to support keyed services, enabling more nuanced dependency injection in application architectures.]]></description><link>https://blog.ludmal.com/p/net-8-dependency-injection-keyed</link><guid isPermaLink="false">https://blog.ludmal.com/p/net-8-dependency-injection-keyed</guid><dc:creator><![CDATA[Ludmal De Silva]]></dc:creator><pubDate>Wed, 18 Oct 2023 06:23:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Oqta!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ef5d19c-ff54-4ac4-a5af-471da1a046a7_1280x1280.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In .NET 8, Inversion of Control (IOC) has been enhanced to support keyed services, enabling more nuanced dependency injection in application architectures.&nbsp;</p><p>With keyed services, developers can associate specific keys with particular service implementations, granting more fine-grained control over service retrieval from the IOC container. This means that when a consumer requests a service, it can specify a key to receive a particular implementation of the service interface.&nbsp;</p><p>This flexibility is crucial for scenarios where multiple implementations of an interface exist, and the decision to use one over another is determined at runtime. Keyed services in .NET 8&#8217;s IOC container therefore facilitate a more dynamic, adaptable, and modular application architecture.&nbsp;</p><p>Here is a simple example of the Keyed services</p><p>Multiple implementation for the same interface</p><pre><code>&nbsp;
        public interface IGreetingService
        {
            string GetGreeting();
        }

        public class EnglishGreetingService : IGreetingService
        {
            public string GetGreeting() =&gt; "Hello!";
        }

        public class SpanishGreetingService : IGreetingService
        {
            public string GetGreeting() =&gt; "&#161;Hola!";
        }

        //Register the implementation with a key

        builder.Services.AddKeyedSingleton&lt;IGreetingService, EnglishGreetingService&gt;("English");
        builder.Services.AddKeyedSingleton&lt;IGreetingService, SpanishGreetingService&gt;("Spanish");

        //Use the key to inject to the required functions
            app.MapGet("/greet", ([FromKeyedServices("English")] IGreetingService english,[FromKeyedServices("Spanish")]
        IGreetingService spanish) =&gt;
        $"English:{english.GetGreeting()} Spanish: {spanish.GetGreeting()}").WithName("GreetingEndpoint");</code></pre><p>Hope this helps!</p>]]></content:encoded></item><item><title><![CDATA[Request Throttling in Minimal Api]]></title><description><![CDATA[Throttling in Minimal API refers to the practice of limiting the number of requests a client can make within a certain time period.]]></description><link>https://blog.ludmal.com/p/request-throttling-in-minimal-api</link><guid isPermaLink="false">https://blog.ludmal.com/p/request-throttling-in-minimal-api</guid><dc:creator><![CDATA[Ludmal De Silva]]></dc:creator><pubDate>Wed, 14 Jun 2023 20:40:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Oqta!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ef5d19c-ff54-4ac4-a5af-471da1a046a7_1280x1280.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Throttling in Minimal API refers to the practice of limiting the number of requests a client can make within a certain time period. It helps prevent abuse and ensures fair usage of API resources. By implementing throttling mechanisms, developers can control the rate at which clients can access their APIs, improving performance and protecting against potential overloading or denial of service attacks.</p><p>Typically these requests are handled via Api Gateway policies. However, .Net provides build in middleware to handle this effectively.</p><pre><code>&nbsp;&nbsp; &nbsp;builder.Services.AddRateLimiter(r =&gt; r
    &nbsp;&nbsp; &nbsp;.AddFixedWindowLimiter(policyName: "fixed", options =&gt;
    &nbsp;&nbsp; &nbsp;{
        &nbsp;&nbsp; &nbsp;options.PermitLimit = 4;
        &nbsp;&nbsp; &nbsp;options.Window = TimeSpan.FromSeconds(12);
    &nbsp;&nbsp; &nbsp;}));

&nbsp;&nbsp; &nbsp;var app = builder.Build();
&nbsp;&nbsp; &nbsp;app.UseRateLimiter();

&nbsp;&nbsp; &nbsp;app.MapGet("/", () =&gt; Results.Ok($"Hello World"))
    &nbsp;&nbsp; &nbsp;.RequireRateLimiting("fixed");</code></pre><pre><code>
</code></pre>]]></content:encoded></item><item><title><![CDATA[Mediatr Pipelines]]></title><description><![CDATA[MediatR is a popular open-source library in C# that provides a simple and elegant way to implement the Mediator pattern and build pipelines in your application.]]></description><link>https://blog.ludmal.com/p/mediatr-pipelines</link><guid isPermaLink="false">https://blog.ludmal.com/p/mediatr-pipelines</guid><dc:creator><![CDATA[Ludmal De Silva]]></dc:creator><pubDate>Thu, 25 May 2023 19:24:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Oqta!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ef5d19c-ff54-4ac4-a5af-471da1a046a7_1280x1280.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>MediatR is a popular open-source library in C# that provides a simple and elegant way to implement the Mediator pattern and build pipelines in your application. The library helps decouple components by promoting loose coupling and encapsulation of requests and handlers.</p><p>With MediatR, you define requests as plain C# classes representing a unit of work or a command, and you create handlers to process these requests. The library then handles the routing and execution of the requests to their corresponding handlers.</p><p>One of the key features of MediatR is its support for pipelines. A pipeline in MediatR is a sequence of behavior or middleware that can be applied before and after the execution of request handlers. Each behavior in the pipeline can intercept and modify the request, perform additional processing, or handle cross-cutting concerns such as validation, logging, caching, or authorization.</p><p>Following code example shows a simple Logging and Exception handling pipeline for Medatr requests.&nbsp;</p><p>public class AddUserCommand : IRequest&lt;Unit&gt;<br>{<br>public string Username { get; set; }<br>public string Email { get; set; }<br>}<br><br>public class AddUserCommandHandler : IRequestHandler&lt;AddUserCommand, Unit&gt;<br>{<br>private readonly IUserService _userService;<br><br>public AddUserCommandHandler(IUserService userService)<br>{<br>_userService = userService;<br>}<br><br>public Task&lt;Unit&gt; Handle(AddUserCommand request, CancellationToken cancellationToken)<br>{<br>_userService.AddUser(request.Username, request.Email);<br>return Task.FromResult(Unit.Value);<br>}<br>}</p><p>//Simple logging behavior<br>public class LoggingBehavior&lt;TRequest, TResponse&gt; : IPipelineBehavior&lt;TRequest, TResponse&gt;<br>{<br>private readonly ILogger&lt;LoggingBehavior&lt;TRequest, TResponse&gt;&gt; _logger;<br><br>public LoggingBehavior(ILogger&lt;LoggingBehavior&lt;TRequest, TResponse&gt;&gt; logger)<br>{<br>_logger = logger;<br>}<br><br>public async Task&lt;TResponse&gt; Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate&lt;TResponse&gt; next)<br>{<br>_logger.LogInformation($"Handling {typeof(TRequest).Name}");<br><br>var response = await next();<br><br>_logger.LogInformation($"Finished handling {typeof(TRequest).Name}");<br><br>return response;<br>}<br>}<br></p><p>//Simple Exception handling behavior<br>public class ExceptionHandlingBehavior&lt;TRequest, TResponse&gt; : IPipelineBehavior&lt;TRequest, TResponse&gt;<br>{<br>private readonly ILogger&lt;ExceptionHandlingBehavior&lt;TRequest, TResponse&gt;&gt; _logger;<br><br>public ExceptionHandlingBehavior(ILogger&lt;ExceptionHandlingBehavior&lt;TRequest, TResponse&gt;&gt; logger)<br>{<br>_logger = logger;<br>}<br><br>public async Task&lt;TResponse&gt; Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate&lt;TResponse&gt; next)<br>{<br>try<br> {<br>return await next();<br>}<br>catch (Exception ex)<br>{<br>_logger.LogError(ex, $"Exception occurred while handling {typeof(TRequest).Name}");<br>throw;<br>}<br>}<br>}</p><p>Next step is to configure the pipeline in startup class.</p><p>//Configure the MediatR pipeline in StartUp Class<br>var services = new ServiceCollection();<br>services.AddMediatR(typeof(Startup));<br><br>// Register any other dependencies your handlers might require<br>services.AddTransient&lt;IUserService, UserService&gt;();<br><br>// Configure pipeline behaviors<br>services.AddTransient(typeof(IPipelineBehavior&lt;,&gt;), typeof(LoggingBehavior&lt;,&gt;));<br>services.AddTransient(typeof(IPipelineBehavior&lt;,&gt;), typeof(ExceptionHandlingBehavior&lt;,&gt;));</p><p>By utilizing MediatR's pipeline capabilities, you can easily insert and compose multiple behaviors in a flexible manner, providing a powerful way to modify and extend the behavior of your application's requests without tightly coupling them to specific implementations.</p><p>The pipeline in MediatR is typically implemented using a combination of decorators and the Decorator Pattern. Decorators wrap and modify the behavior of the underlying handler, allowing you to add or modify functionality at various points in the pipeline.</p><p>In summary, MediatR is a versatile library that simplifies the implementation of the Mediator pattern and facilitates the creation of pipelines in C# applications. It promotes decoupling, modularity, and extensibility, making it easier to handle requests, apply behaviors, and build scalable and maintainable applications.</p><p><a href="https://github.com/jbogard/MediatR">https://github.com/jbogard/MediatR&nbsp;</a></p>]]></content:encoded></item><item><title><![CDATA[Simplified Messaging using MassTransit]]></title><description><![CDATA[MassTransit is an open-source message bus framework for .NET that makes it easier to build distributed applications by providing a way to communicate between different components or services within a system. https://masstransit.io/]]></description><link>https://blog.ludmal.com/p/simplified-messaging-using-masstransit</link><guid isPermaLink="false">https://blog.ludmal.com/p/simplified-messaging-using-masstransit</guid><dc:creator><![CDATA[Ludmal De Silva]]></dc:creator><pubDate>Fri, 12 May 2023 09:36:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Oqta!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ef5d19c-ff54-4ac4-a5af-471da1a046a7_1280x1280.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>MassTransit is an open-source message bus framework for .NET that makes it easier to build distributed applications by providing a way to communicate between different components or services within a system.&nbsp;<a href="https://masstransit.io/">https://masstransit.io/</a></p><p>In simple terms, MassTransit allows different parts of a system to send and receive messages, regardless of where they are located or how they are implemented. It provides a way to abstract away the details of communication protocols and message serialization, allowing developers to focus on the business logic of their applications.&nbsp;</p><p>I've used MassTransit many years ago and wanted to highlight the usage of it and the simplicty it provide to integrate with different message brokers.&nbsp;</p><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!etCv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a38c258-b499-492f-a77b-f943c359d7d9_1600x1167.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!etCv!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a38c258-b499-492f-a77b-f943c359d7d9_1600x1167.png 424w, https://substackcdn.com/image/fetch/$s_!etCv!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a38c258-b499-492f-a77b-f943c359d7d9_1600x1167.png 848w, https://substackcdn.com/image/fetch/$s_!etCv!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a38c258-b499-492f-a77b-f943c359d7d9_1600x1167.png 1272w, https://substackcdn.com/image/fetch/$s_!etCv!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a38c258-b499-492f-a77b-f943c359d7d9_1600x1167.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!etCv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a38c258-b499-492f-a77b-f943c359d7d9_1600x1167.png" width="320" height="233" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1a38c258-b499-492f-a77b-f943c359d7d9_1600x1167.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:233,&quot;width&quot;:320,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!etCv!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a38c258-b499-492f-a77b-f943c359d7d9_1600x1167.png 424w, https://substackcdn.com/image/fetch/$s_!etCv!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a38c258-b499-492f-a77b-f943c359d7d9_1600x1167.png 848w, https://substackcdn.com/image/fetch/$s_!etCv!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a38c258-b499-492f-a77b-f943c359d7d9_1600x1167.png 1272w, https://substackcdn.com/image/fetch/$s_!etCv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a38c258-b499-492f-a77b-f943c359d7d9_1600x1167.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a><p>I have written a .Net 7 mininal api sample in MassTransit. Have a look at it and see how simple it is to integrate. This will eliminate tons of plumbing code to get the messaging working.&nbsp;</p><h2>&nbsp;&nbsp; &nbsp;<a href="HTTPS://GITHUB.COM/LUDMAL/MASSTRANSITSAMPLE">HTTPS://GITHUB.COM/LUDMAL/MASSTRANSITSAMPLE</a></h2>]]></content:encoded></item><item><title><![CDATA[Minimal Api]]></title><description><![CDATA[Minimal API in .NET Core is a new approach to building web APIs with minimal ceremony and less boilerplate code.]]></description><link>https://blog.ludmal.com/p/minimal-api</link><guid isPermaLink="false">https://blog.ludmal.com/p/minimal-api</guid><dc:creator><![CDATA[Ludmal De Silva]]></dc:creator><pubDate>Thu, 27 Apr 2023 19:55:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Oqta!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ef5d19c-ff54-4ac4-a5af-471da1a046a7_1280x1280.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Minimal API in .NET Core is a new approach to building web APIs with minimal ceremony and less boilerplate code. It is a feature that was introduced in .NET 6 and has been improved in subsequent versions, including .NET 7.</p><p>With Minimal API, developers can create HTTP endpoints with fewer lines of code and without having to set up complex routing or middleware configurations. This is achieved by providing a simplified syntax for defining endpoints, which reduces the amount of code required to create an API.</p><p>A simple example:</p><p><br>&nbsp;&nbsp; &nbsp;using Microsoft.AspNetCore.Mvc;<br>&nbsp;&nbsp; &nbsp;using Microsoft.Extensions.Logging;<br><br>&nbsp;&nbsp; &nbsp;var builder = WebApplication.CreateBuilder(args);<br><br>&nbsp;&nbsp; &nbsp;var app = builder.Build();<br><br>&nbsp;&nbsp; &nbsp;app.MapGet("/", () =&gt; "Hello World!");<br><br>&nbsp;&nbsp; &nbsp;app.Run();</p><p>The goal of Minimal API is to enable developers to focus on writing business logic rather than dealing with infrastructure concerns. It provides a streamlined development experience, making it easier and faster to build APIs. Additionally, Minimal API integrates seamlessly with other .NET Core technologies, such as Dependency Injection and Entity Framework Core.</p><p>Another example for coherent code structure:</p><p>using Microsoft.AspNetCore.Mvc;<br>using Microsoft.Extensions.Logging;<br><br>var builder = WebApplication.CreateBuilder(args);<br><br>var app = builder.Build();<br><br>app.MapPost("/change-password", UserEndpoints.ChangePassword);<br><br>app.Run();<br><br>public static class UserEndpoints<br>{<br>public static async Task&lt;IResult&gt; ChangePassword(</p><p>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;HttpContext context,</p><p>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;ChangePasswordRequest request,<br>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;IUserService userService)<br>{<br>//Logic here<br> return await Task.FromResult(Results.Ok());<br>}<br>}</p><p>Overall, Minimal API in .NET Core provides a lightweight, modern approach to building web APIs, enabling developers to quickly create high-performance, scalable APIs with minimal effort.&nbsp;</p><p>I will be writing quite a bit of minimal api usages and best practices in future. So stay tuned.&nbsp;&nbsp;</p>]]></content:encoded></item><item><title><![CDATA[Pattern matching using C# Switch expressions]]></title><description><![CDATA[Switch expressions pattern matching provides developers with a concise and expressive way to handle complex conditional logic.]]></description><link>https://blog.ludmal.com/p/pattern-matching-using-c-switch</link><guid isPermaLink="false">https://blog.ludmal.com/p/pattern-matching-using-c-switch</guid><dc:creator><![CDATA[Ludmal De Silva]]></dc:creator><pubDate>Wed, 26 Apr 2023 06:02:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Oqta!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ef5d19c-ff54-4ac4-a5af-471da1a046a7_1280x1280.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Switch expressions pattern matching provides developers with a concise and expressive way to handle complex conditional logic. It allows you to match patterns within a switch expression, rather than just values.</p><p>One of the key benefits of switch expressions pattern matching is that it reduces the amount of code you need to write to handle different cases. This can make your code more readable, maintainable, and efficient.</p><p>Here's an example of how you can use switch expressions pattern matching in C#:</p><pre><code>public string Execute(ICommand command) =&gt; command switch
{
    OpenCommand o     =&gt; "Open Command",
    CloseCommand o    =&gt; "Close Command",
    ExecuteCommand o  =&gt; "Execute Command",
    _                 =&gt; throw new ArgumentOutOfRangeException(nameof(command), command, null)
};
</code></pre><p>In the above example, we define a method called Execute that takes an ICommand object as a parameter. We then use a switch expression to match the type of the command and return the corresponding action. Also it is far easier to use pattern matching on the properties of the paratmers.&nbsp;</p><pre><code>public string Execute(ICommand command) =&gt; command switch
{
    { Valid: true, Value: &gt; 10 }        =&gt; "Open Command",
    { Valid: false, Value: &lt;= 10 }      =&gt; "Close Command",
    ExecuteCommand o                   =&gt; "Execute Command",
    _                                  =&gt; throw new ArgumentOutOfRangeException(nameof(command), command, null)
};
</code></pre><p>The switch expression uses the arrow notation (=&gt;) to match the pattern and return the result. The _ symbol acts as a catch-all case, which throws an exception if an invalid command is passed in.</p><p>Tuples significantly improves the pattern matching as shown in the below example.</p><pre><code>private static string FormatMobileNumber(string number) =&gt; 
    (number.StartsWith("+6"), number.StartsWith("6"), number.StartsWith("04")) switch
    {
        (true,  _,     _)    =&gt; number,
        (false, true,  _)    =&gt; $"+61{number[1..]}",
        (false, false, true) =&gt; $"+61{number[1..]}",
        _                    =&gt; number
    };
</code></pre><p>Overall, switch expressions pattern matching is a powerful feature in C# that can help you write more expressive and maintainable code. Whether you're working on a small project or a large enterprise application, it's definitely worth considering using switch expressions pattern matching in your code.</p>]]></content:encoded></item><item><title><![CDATA[AI Product improvement cycle]]></title><description><![CDATA[Artificial Intelligence (AI) & Machine Learning(ML) has significant advantage over traditional algorithms which we used to improve our products.]]></description><link>https://blog.ludmal.com/p/ai-product-improvement-cycle</link><guid isPermaLink="false">https://blog.ludmal.com/p/ai-product-improvement-cycle</guid><dc:creator><![CDATA[Ludmal De Silva]]></dc:creator><pubDate>Fri, 21 Apr 2017 23:07:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Oqta!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ef5d19c-ff54-4ac4-a5af-471da1a046a7_1280x1280.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Artificial Intelligence (AI) &amp; Machine Learning(ML) has significant advantage over traditional algorithms which we used to improve our products. This is mainly due to the fact that ML improves with big data unlike the traditional algorithms.</p><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!dncA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7a12791-0711-4580-b749-7edfe724ef4f_320x240.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!dncA!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7a12791-0711-4580-b749-7edfe724ef4f_320x240.png 424w, https://substackcdn.com/image/fetch/$s_!dncA!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7a12791-0711-4580-b749-7edfe724ef4f_320x240.png 848w, https://substackcdn.com/image/fetch/$s_!dncA!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7a12791-0711-4580-b749-7edfe724ef4f_320x240.png 1272w, https://substackcdn.com/image/fetch/$s_!dncA!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7a12791-0711-4580-b749-7edfe724ef4f_320x240.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!dncA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7a12791-0711-4580-b749-7edfe724ef4f_320x240.png" width="320" height="239" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a7a12791-0711-4580-b749-7edfe724ef4f_320x240.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:239,&quot;width&quot;:320,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!dncA!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7a12791-0711-4580-b749-7edfe724ef4f_320x240.png 424w, https://substackcdn.com/image/fetch/$s_!dncA!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7a12791-0711-4580-b749-7edfe724ef4f_320x240.png 848w, https://substackcdn.com/image/fetch/$s_!dncA!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7a12791-0711-4580-b749-7edfe724ef4f_320x240.png 1272w, https://substackcdn.com/image/fetch/$s_!dncA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7a12791-0711-4580-b749-7edfe724ef4f_320x240.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a><p>Big data is the key for the ML &amp; AI. It helps ML learns and improve the accuracy. This is the main reason, companies such as Google benefits vastly from ML &amp; AI. Moreover, AI &amp; ML can improve the product significantly. When the product quality improves more users tend to use it and this generates more data. More data can be used for ML &amp; AI to improve the product hence an infinite loop of improving the product. This is what I called -- &#8220;AI Product improvement cycle&#8221;</p><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!TVI9!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc827c304-3a37-49b6-af09-8da4b5838f22_240x320.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!TVI9!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc827c304-3a37-49b6-af09-8da4b5838f22_240x320.png 424w, https://substackcdn.com/image/fetch/$s_!TVI9!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc827c304-3a37-49b6-af09-8da4b5838f22_240x320.png 848w, https://substackcdn.com/image/fetch/$s_!TVI9!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc827c304-3a37-49b6-af09-8da4b5838f22_240x320.png 1272w, https://substackcdn.com/image/fetch/$s_!TVI9!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc827c304-3a37-49b6-af09-8da4b5838f22_240x320.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!TVI9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc827c304-3a37-49b6-af09-8da4b5838f22_240x320.png" width="240" height="320" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c827c304-3a37-49b6-af09-8da4b5838f22_240x320.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:320,&quot;width&quot;:240,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!TVI9!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc827c304-3a37-49b6-af09-8da4b5838f22_240x320.png 424w, https://substackcdn.com/image/fetch/$s_!TVI9!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc827c304-3a37-49b6-af09-8da4b5838f22_240x320.png 848w, https://substackcdn.com/image/fetch/$s_!TVI9!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc827c304-3a37-49b6-af09-8da4b5838f22_240x320.png 1272w, https://substackcdn.com/image/fetch/$s_!TVI9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc827c304-3a37-49b6-af09-8da4b5838f22_240x320.png 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><p>AI &amp; ML has become an essential part of any product development. Therefore, analysing and implementing ML algorithms will improve the quality of the product which can leads to more users.</p>]]></content:encoded></item><item><title><![CDATA[AWS.Net - Simple library for AWS services. i.e. S3, SQS & SES]]></title><description><![CDATA[Have worked on many AWS projects but found their library wasn't designed for simplicity.]]></description><link>https://blog.ludmal.com/p/awsnet-simple-library-for-aws-services</link><guid isPermaLink="false">https://blog.ludmal.com/p/awsnet-simple-library-for-aws-services</guid><dc:creator><![CDATA[Ludmal De Silva]]></dc:creator><pubDate>Thu, 20 Oct 2016 02:39:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Oqta!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ef5d19c-ff54-4ac4-a5af-471da1a046a7_1280x1280.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Have worked on many AWS projects but found their library wasn't designed for simplicity. So thought of writing my own library for my pet projects with AWS. It's very simple and easy to integrate S3, SQS &amp; SES.<br></p><p><a href="https://github.com/ludmal/AWS.Net">Visit my Github project for more details on how to use it.</a>&nbsp; -&nbsp;<a href="https://github.com/ludmal/AWS.Net">https://github.com/ludmal/AWS.Net</a><br></p><p> For example, sending a message to the SQS is easy as this.&nbsp;</p><pre><code>var service = new SqsService&lt;EmailMessage&gt;(new AwsCredentials
{
  RegionEndpoint = RegionEndpoint.USWest2
});

service.QueueUrl = ConfigurationManager.AppSettings["EmailQueue"];

var response = service.Push(new HelloEmail());</code></pre><p> And retrieving the message with Generic object is very simple.</p><pre><code>var service = new SqsService&lt;EmailMessage&gt;(new AwsCredentials
{
 //SQS Service Region
 RegionEndpoint = RegionEndpoint.USWest2
});

//SQS Queue Url
service.QueueUrl = ConfigurationManager.AppSettings["EmailQueue"];

var items = service.Process();</code></pre>]]></content:encoded></item></channel></rss>