<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Vimal</title>
    <description>The latest articles on DEV Community by Vimal (@vimaltwit).</description>
    <link>https://dev.to/vimaltwit</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F491251%2Fb4b64054-dbb7-4675-97a0-45c283b560a7.JPG</url>
      <title>DEV Community: Vimal</title>
      <link>https://dev.to/vimaltwit</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vimaltwit"/>
    <language>en</language>
    <item>
      <title>The Math Behind Machine Learning: A Beginner’s Map</title>
      <dc:creator>Vimal</dc:creator>
      <pubDate>Fri, 30 Oct 2026 07:41:31 +0000</pubDate>
      <link>https://dev.to/vimaltwit/the-math-behind-machine-learning-a-beginners-map-5ah4</link>
      <guid>https://dev.to/vimaltwit/the-math-behind-machine-learning-a-beginners-map-5ah4</guid>
      <description>&lt;p&gt;Machine learning can seem like a collection of mysterious algorithms. But many of its core ideas are built from a handful of &lt;strong&gt;mathematical tools&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Think of these tools as parts of a workflow: &lt;strong&gt;represent data, compare examples, describe uncertainty, and improve predictions.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frh0a4vnljoj8h2way5x1.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frh0a4vnljoj8h2way5x1.jpeg" alt=" " width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Linear algebra: giving data a shape
&lt;/h2&gt;

&lt;p&gt;A machine-learning model needs data in a form it can work with. &lt;strong&gt;Linear algebra&lt;/strong&gt; provides that form.You may already know the equation of a straight line:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;y = ax + b&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Here, &lt;code&gt;x&lt;/code&gt; is the input, &lt;code&gt;y&lt;/code&gt; is the output, &lt;code&gt;a&lt;/code&gt; is commonly known as &lt;strong&gt;slope&lt;/strong&gt;, and &lt;code&gt;b&lt;/code&gt; commonly known as &lt;strong&gt;intercept&lt;/strong&gt; tells us where the line crosses the y-axis. For example, if y = 2x + 1, then every time x increases by 1, y increases by 2.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; y
 5 |             *
 4 |          *
 3 |       *
 2 |    *
 1 | *
 0 +---------------- x
    0  1  2  3  4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each &lt;code&gt;*&lt;/code&gt; is a point (x, y) on the line. A graph makes the relationship between inputs and outputs visible.&lt;/p&gt;

&lt;p&gt;In terms of machine-learning model given &lt;code&gt;y = ax + b&lt;/code&gt;, the model uses input &lt;code&gt;x&lt;/code&gt; to predict output &lt;code&gt;y&lt;/code&gt;. During training, it adjusts &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt; to make its predictions better.&lt;/p&gt;

&lt;p&gt;A line on a graph is a simple model; vectors and matrices give us a compact way to represent and calculate its predictions.&lt;/p&gt;

&lt;p&gt;Imagine describing a house using three numbers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ size, bedrooms, age ]
[ 1200, 3,         20 ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That list of numbers is a &lt;strong&gt;vector&lt;/strong&gt;: one object represented by several values. A collection of objects can be arranged into a &lt;strong&gt;matrix&lt;/strong&gt;, like a spreadsheet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;              size   bedrooms   age
House A       1200      3        20
House B       1800      4         5
House C        900      2        30
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;In short:&lt;/strong&gt; vectors describe individual examples; matrices organize many examples.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Analytic geometry: deciding what is similar
&lt;/h2&gt;

&lt;p&gt;Once data is represented as vectors, we can compare examples mathematically.&lt;/p&gt;

&lt;p&gt;For instance, two houses with similar size, bedroom count, and age may be considered similar. A model can use this idea to make predictions: if two inputs are alike, their predicted outputs like price of the house may also be alike.&lt;/p&gt;

&lt;p&gt;Geometry gives us ways to describe &lt;strong&gt;similarity&lt;/strong&gt; and &lt;strong&gt;distance&lt;/strong&gt; between vectors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In short:&lt;/strong&gt; geometry helps answer, “Which examples are close to this one?”&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Matrix decomposition: uncovering useful patterns
&lt;/h2&gt;

&lt;p&gt;A large matrix can contain patterns that are hard to spot by looking at every number. &lt;strong&gt;Matrix decomposition&lt;/strong&gt; breaks a matrix into simpler pieces that can reveal important structure.&lt;/p&gt;

&lt;p&gt;This can help with tasks such as finding patterns in data or making some learning operations more efficient.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In short:&lt;/strong&gt; decomposition helps simplify data without losing the patterns a model needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Probability: handling noise and uncertainty
&lt;/h2&gt;

&lt;p&gt;Real-world data is rarely perfect. Measurements may be inaccurate, labels may be mistaken, and future outcomes may be unpredictable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Probability theory&lt;/strong&gt; gives us a language for describing this uncertainty. It helps us reason about questions such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How much variation might be noise?&lt;/li&gt;
&lt;li&gt;How likely is a particular outcome?&lt;/li&gt;
&lt;li&gt;How confident should we be in a prediction?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;In short:&lt;/strong&gt; probability helps a model represent what it knows—and what it doesn’t know for sure.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Vector calculus: understanding how changes affect a model
&lt;/h2&gt;

&lt;p&gt;A model’s predictions depend on its &lt;strong&gt;parameters&lt;/strong&gt;—the adjustable values it learns from data. Changing those parameters can improve or worsen its performance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vector calculus&lt;/strong&gt; helps describe how a function changes as its inputs change. One especially useful idea is the &lt;strong&gt;gradient&lt;/strong&gt;: it indicates the direction in which a function increases most quickly.&lt;/p&gt;

&lt;p&gt;For learning, we often use the gradient to figure out how to adjust parameters to reduce errors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In short:&lt;/strong&gt; gradients tell us how parameter changes affect performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Optimization: improving the model
&lt;/h2&gt;

&lt;p&gt;Training often means finding parameter values that make a model perform well. &lt;strong&gt;Optimization&lt;/strong&gt; is the process of searching for those values.&lt;/p&gt;

&lt;p&gt;A simple way to picture it is walking downhill on a landscape:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The landscape represents the model’s error.&lt;/li&gt;
&lt;li&gt;Your position represents the current parameter values.&lt;/li&gt;
&lt;li&gt;The gradient points toward a direction of change.&lt;/li&gt;
&lt;li&gt;The goal is to reach a low point, where the error is smaller.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The process repeats: calculate performance, adjust parameters, and check again.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In short:&lt;/strong&gt; optimization uses mathematical search to improve a model.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the pieces work together
&lt;/h2&gt;

&lt;p&gt;Here’s the full story:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyd153xvp0emrb4qk93gr.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyd153xvp0emrb4qk93gr.jpeg" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Linear algebra&lt;/strong&gt; turns examples into vectors and matrices.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Geometry&lt;/strong&gt; helps compare those examples.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Matrix decomposition&lt;/strong&gt; can reveal patterns in the data.&lt;/li&gt;
&lt;li&gt;The model makes predictions, while &lt;strong&gt;probability&lt;/strong&gt; helps describe uncertainty.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vector calculus&lt;/strong&gt; calculates how changes to parameters affect performance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optimization&lt;/strong&gt; uses that information to improve the model.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You don’t need to master all of these ideas before beginning machine learning. But knowing what each one is for makes the subject easier to navigate: &lt;strong&gt;linear algebra represents the data, geometry compares it, probability describes uncertainty, and calculus and optimization help the model learn and improve predictions.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>beginners</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>AI as an Experience Layer</title>
      <dc:creator>Vimal</dc:creator>
      <pubDate>Tue, 20 Oct 2026 08:07:15 +0000</pubDate>
      <link>https://dev.to/vimaltwit/ai-as-an-experience-layer-3el7</link>
      <guid>https://dev.to/vimaltwit/ai-as-an-experience-layer-3el7</guid>
      <description>&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;Modern digital platforms are no longer built around a single user interface or a single application runtime. As software systems mature, they increasingly expose the same business data through multiple channels: transactional systems, APIs, data warehouses, analytics surfaces, reporting layers, and AI-powered agents.&lt;/p&gt;

&lt;p&gt;This architectural shift matters because AI is not just another feature bolted onto an app. It is becoming a new surfacing layer over the platform itself. In the same way that web apps, mobile apps, and dashboards expose business capabilities to users, AI agents and copilots can expose operational and analytical capabilities to intelligent systems.&lt;/p&gt;

&lt;p&gt;The key idea is simple: the underlying platform remains the source of truth, while different layers consume and present that truth in different ways.&lt;/p&gt;

&lt;h2&gt;
  
  
  High-level architecture
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fozmmhu8da8lysg8b2eck.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fozmmhu8da8lysg8b2eck.png" alt=" " width="800" height="388"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this architecture matters
&lt;/h2&gt;

&lt;p&gt;The traditional architecture model assumes one main interface to the system: the web app, the mobile app, or the internal API layer. But modern platforms are multi-surface systems.&lt;/p&gt;

&lt;p&gt;A user might interact through a web dashboard, a BI report, an internal operations console, or an AI assistant. Each path reads or writes the same business domain in a different way, but each path depends on the same core data foundation.&lt;/p&gt;

&lt;p&gt;This is where AI becomes strategically important: it is no longer just a user interaction pattern, but a platform capability that can be surfaced as a controlled access layer over operational and analytical data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Layer responsibilities
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Data platform layer
&lt;/h3&gt;

&lt;p&gt;This layer contains the authoritative operational data and the analytical data stores. The operational database handles transactional workflows and the system-of-record behavior. The warehouse or lakehouse is optimized for analytics, data modeling, and broader downstream consumption.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Application layer
&lt;/h3&gt;

&lt;p&gt;This layer exposes business behavior through APIs and internal services. It enforces validation, domain rules, orchestration, and access control. The underlying technology stack is intentionally abstracted here; the architecture is concerned with capabilities, not a specific framework.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. ETL and integration layer
&lt;/h3&gt;

&lt;p&gt;This layer moves data from operational systems into curated analytical stores. ETL and streaming pipelines clean, transform, and unify data so reporting and AI workloads consume trusted, structured information rather than brittle transactional data directly.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Reporting and analytics layer
&lt;/h3&gt;

&lt;p&gt;This layer turns curated data into business insight. Dashboards, semantic models, scorecards, and metrics provide a human-readable layer on top of the data platform so stakeholders can monitor performance and make decisions.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. AI layer: Agent host, LLM, MCP, and Skills
&lt;/h3&gt;

&lt;p&gt;The AI layer combines familiar components with two platform-specific elements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Agent host&lt;/strong&gt; (for example, VS Code or Copilot) provides the user experience and coordinates the conversation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LLM&lt;/strong&gt; interprets requests and produces responses or tool-call decisions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MCP&lt;/strong&gt; gives the host and model a standard way to discover and invoke platform capabilities.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skills&lt;/strong&gt; provide domain terminology and workflow guidance for using those capabilities appropriately.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;MCP and Skills solve different problems and work best together:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;MCP&lt;/th&gt;
&lt;th&gt;Skills&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Primary role&lt;/td&gt;
&lt;td&gt;Connects an agent to tools and other exposed capabilities&lt;/td&gt;
&lt;td&gt;Explains the domain and how work should be done&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Provides&lt;/td&gt;
&lt;td&gt;Discoverable tool definitions, input schemas, and results&lt;/td&gt;
&lt;td&gt;Terminology, workflow steps, constraints, and examples&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Answers&lt;/td&gt;
&lt;td&gt;“What can the agent call, and how?”&lt;/td&gt;
&lt;td&gt;“Which approach makes sense in this domain?”&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Without it&lt;/td&gt;
&lt;td&gt;The agent may lack a consistent way to access platform capabilities&lt;/td&gt;
&lt;td&gt;The agent may use tools without enough business context&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;MCP is an integration contract, not an authorization system; access controls must still be enforced by the host, MCP server, and underlying services. Skills guide model behavior but do not replace validation or business rules in those services.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design principles
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Separation of concerns
&lt;/h3&gt;

&lt;p&gt;Operational, analytical, reporting, and AI workloads should be separated by purpose. Each layer should be optimized for its specific responsibility instead of trying to do everything in one runtime.&lt;/p&gt;

&lt;h3&gt;
  
  
  Source-of-truth discipline
&lt;/h3&gt;

&lt;p&gt;The transactional system remains the authoritative source of record, while the warehouse provides curated analytical data. Reporting and AI systems should consume trusted data rather than duplicate operational logic or bypass governance controls.&lt;/p&gt;

&lt;h3&gt;
  
  
  Governed tool exposure
&lt;/h3&gt;

&lt;p&gt;MCP matters because it gives the AI a bounded interface instead of full direct access to everything. This is the difference between an AI system that can act safely and one that can only talk generically about the platform.&lt;/p&gt;

&lt;h3&gt;
  
  
  Domain grounding
&lt;/h3&gt;

&lt;p&gt;Skills matter because they connect the AI to the actual business language and workflow patterns of the organization. This is what turns a general-purpose model into a useful domain-aware collaborator.&lt;/p&gt;

&lt;h3&gt;
  
  
  Multi-surface product design
&lt;/h3&gt;

&lt;p&gt;A platform should not assume one user channel. Instead, it should support multiple surfaces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;human users through web and mobile experiences,&lt;/li&gt;
&lt;li&gt;analysts through BI and reporting,&lt;/li&gt;
&lt;li&gt;agents through MCP or similar tool surfaces,&lt;/li&gt;
&lt;li&gt;and operational workflows through APIs and internal services.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Framework independence
&lt;/h3&gt;

&lt;p&gt;The architectural pattern should not be tied to a single framework or language. APIs can be built in .NET, Node.js, Python, Java, or any other stack. The architecture is about capabilities, boundaries, and responsibilities—not vendor lock-in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why AI is becoming a surfacing layer
&lt;/h2&gt;

&lt;p&gt;AI is increasingly becoming a new access surface over the platform, much like an API or dashboard is. It is not merely a chatbot sitting on top of the UI; it is an interface that can interpret, reason, and act over enterprise data when properly connected to the right tools and context.&lt;/p&gt;

&lt;p&gt;That makes AI a strategic platform concern rather than just an application feature. When done well, it provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;natural-language interaction,&lt;/li&gt;
&lt;li&gt;operational assistance,&lt;/li&gt;
&lt;li&gt;workflow guidance,&lt;/li&gt;
&lt;li&gt;and faster access to business insight through structured tool exposure.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But this only works when the platform has a solid foundation: trusted data, curated integrations, and clear access boundaries.&lt;/p&gt;

&lt;p&gt;The real differentiator is not simply “AI in the product.” The differentiator is how the platform exposes capabilities to the model and how much domain context the model receives. That is where MCP and Skills become foundational.&lt;/p&gt;

&lt;p&gt;MCP gives the model a formal way to discover and invoke capabilities. Skills give the model the operational understanding needed to act correctly. Together, they turn AI from a clever interface into a grounded, enterprise-aware operating layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Strategic implication
&lt;/h2&gt;

&lt;p&gt;The modern platform architecture is becoming a layered ecosystem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;transactional systems handle live operations,&lt;/li&gt;
&lt;li&gt;APIs expose business capabilities,&lt;/li&gt;
&lt;li&gt;ETL pipelines bring data into analytical stores,&lt;/li&gt;
&lt;li&gt;BI surfaces provide business visibility,&lt;/li&gt;
&lt;li&gt;and AI acts as a new interaction layer over the same platform capabilities.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AI does not replace these systems. It adds another interface for interacting with them, one that requires governance, semantic context, and well-defined tooling to be useful and safe.&lt;/p&gt;

&lt;p&gt;This is where MCP and Skills become strategic differentiators. A team that adds a chatbot without MCP and domain-specific skills is merely adding a surface that can talk about the system. A team that adds MCP and Skills creates a system that can truly operate within the platform, grounded in domain context and tool boundaries.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;AI is evolving from a feature to a platform surface. In the same way that the web, mobile, and reporting experiences expose the business to users, AI agents can expose business capabilities and insights to intelligent systems.&lt;/p&gt;

&lt;p&gt;The winning architecture is not a monolith but a layered platform built around a trusted data foundation, well-defined application services, managed integration pipelines, reporting surfaces, and an AI layer that is governed, contextualized, and tool-driven.&lt;/p&gt;

&lt;p&gt;This is the emerging reality of modern software architecture: a system designed for many interfaces, not just one.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>Track Page Views using Application Insights</title>
      <dc:creator>Vimal</dc:creator>
      <pubDate>Mon, 01 Jun 2026 13:39:59 +0000</pubDate>
      <link>https://dev.to/vimaltwit/track-page-views-using-application-insights-49a</link>
      <guid>https://dev.to/vimaltwit/track-page-views-using-application-insights-49a</guid>
      <description>&lt;p&gt;To track page views in an Angular application using Azure Application Insights, you typically integrate the Application Insights JavaScript SDK and hook it into Angular routing events.&lt;br&gt;
Below is a clean, production-friendly approach tailored for Angular apps.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step-by-Step Implementation
&lt;/h2&gt;
&lt;h2&gt;
  
  
  1️⃣ Install Application Insights SDK
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;npm install @microsoft/applicationinsights-web&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  2️⃣Create an App Insights Service
&lt;/h2&gt;

&lt;p&gt;Create a reusable service to initialize telemetry.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// app-insights.service.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Injectable&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ApplicationInsights&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@microsoft/applicationinsights-web&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppInsightsService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;appInsights&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ApplicationInsights&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appInsights&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ApplicationInsights&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;instrumentationKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YOUR_INSTRUMENTATION_KEY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;enableAutoRouteTracking&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="c1"&gt;// we'll manually track&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appInsights&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadAppInsights&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;logPageView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appInsights&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trackPageView&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;uri&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3️⃣Hook into Angular Router Events
&lt;/h2&gt;

&lt;p&gt;Angular SPAs don’t reload pages, so you must manually track navigation changes using the Router.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;TypeScript&lt;/span&gt;&lt;span class="c1"&gt;// app.component.ts&lt;/span&gt;
&lt;span class="c1"&gt;// app.component.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;NavigationEnd&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;filter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rxjs/operators&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AppInsightsService&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app-insights.service&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;router-outlet&amp;gt;&amp;lt;/router-outlet&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;appInsightsService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AppInsightsService&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;monitorRouting&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;monitorRouting&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;events&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nx"&gt;NavigationEnd&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NavigationEnd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appInsightsService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;logPageView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;urlAfterRedirects&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ✅ Result
&lt;/h2&gt;

&lt;p&gt;Each route change (e.g., /home → /dashboard) will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Trigger NavigationEnd&lt;/li&gt;
&lt;li&gt;Send a pageView telemetry event to Application Insights&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🚀 Alternative (Automatic Tracking)
&lt;/h2&gt;

&lt;p&gt;You can enable auto tracking:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
&lt;span class="p"&gt;{&lt;/span&gt;  
 &lt;span class="nl"&gt;instrumentationKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YOUR_KEY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
 &lt;span class="nx"&gt;enableAutoRouteTracking&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ Pros:&lt;/p&gt;

&lt;p&gt;Minimal setup&lt;/p&gt;

&lt;p&gt;⚠️ Cons:&lt;/p&gt;

&lt;p&gt;Less control over naming and metadata&lt;br&gt;
Harder to enrich telemetry&lt;/p&gt;
&lt;h2&gt;
  
  
  🔍 Enhancements (Highly Recommended)
&lt;/h2&gt;

&lt;p&gt;✅ Add Custom Properties&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appInsights&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trackPageView&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;urlAfterRedirects&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;userRole&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;feature&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SearchModule&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ Track Logged-in User&lt;br&gt;
&lt;code&gt;TypeScriptthis.appInsights.setAuthenticatedUserContext('user-id');&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
✅ Track API calls, errors, and events&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appInsights&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trackEvent&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ButtonClicked&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appInsights&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trackException&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;exception&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  👉 Best practice:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Use App Insights Web SDK in Angular&lt;/li&gt;
&lt;li&gt;Use Application Insights SDK in .NET API&lt;/li&gt;
&lt;li&gt;Correlate telemetry via operationId&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🧾 Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Install App Insights SDK&lt;/li&gt;
&lt;li&gt;Create telemetry service&lt;/li&gt;
&lt;li&gt;Subscribe to NavigationEnd&lt;/li&gt;
&lt;li&gt;Call trackPageView()&lt;/li&gt;
&lt;li&gt;(Optional) Add custom telemetry&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ✅ Final Takeaway
&lt;/h2&gt;

&lt;p&gt;Angular does not trigger full page reloads, so you must manually track page views using Router events to get accurate telemetry in Application Insights.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>useranalytics</category>
      <category>azureapplicationinsights</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Build a Streaming UI without over-complicating it</title>
      <dc:creator>Vimal</dc:creator>
      <pubDate>Sat, 23 May 2026 18:53:40 +0000</pubDate>
      <link>https://dev.to/vimaltwit/build-a-streaming-ui-without-overcomplicating-it-1m3f</link>
      <guid>https://dev.to/vimaltwit/build-a-streaming-ui-without-overcomplicating-it-1m3f</guid>
      <description>&lt;p&gt;If you are building a UI that needs to show progress, logs, or live updates, you do not need to jump straight to WebSockets. In many cases, SSE is the simpler and more appropriate choice. It is a browser-friendly way for the server to push events to the client over HTTP. Think of it as a one-way live stream: the server sends updates, and the browser listens.&lt;/p&gt;

&lt;p&gt;SSE is a great option when you need &lt;strong&gt;server → client streaming&lt;/strong&gt; and want to keep the implementation simple.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is SSE?
&lt;/h2&gt;

&lt;p&gt;SSE stands for &lt;strong&gt;Server-Sent Events&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It is a browser-native way for the server to push updates to the client over HTTP.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to use SSE
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Use SSE when&lt;/th&gt;
&lt;th&gt;Avoid SSE when&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;The communication is &lt;strong&gt;one-way&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;You need &lt;strong&gt;bidirectional chat&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You want to &lt;strong&gt;avoid polling&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;You need &lt;strong&gt;low-latency command/control flows&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You want a &lt;strong&gt;lightweight HTTP-based stream&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;You need &lt;strong&gt;binary transport&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You want the &lt;strong&gt;browser to handle the connection natively&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Examples:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;progress updates&lt;/li&gt;
&lt;li&gt;live logs&lt;/li&gt;
&lt;li&gt;status feeds&lt;/li&gt;
&lt;li&gt;task completion notifications&lt;/li&gt;
&lt;li&gt;AI-generated content token by token&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why use SSE instead of polling?
&lt;/h2&gt;

&lt;p&gt;Polling is one of the most common used techniques for implementing such scenarios. Polling means the browser repeatedly asks the server for new data. That creates extra traffic and awkward timing.&lt;/p&gt;

&lt;h2&gt;
  
  
  SSE is better because:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;the browser opens a single connection&lt;/li&gt;
&lt;li&gt;the server sends events as they happen&lt;/li&gt;
&lt;li&gt;the client gets updates immediately&lt;/li&gt;
&lt;li&gt;you avoid repeated polling requests&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a small streaming UI, SSE is often the simplest option.&lt;/p&gt;

&lt;h2&gt;
  
  
  Technical Flow and Architecture
&lt;/h2&gt;

&lt;p&gt;The implementation of an SSE stream relies on a simple front-to-back flow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Backend Endpoint&lt;/strong&gt;: The backend (e.g., ASP.NET) exposes an HTTP endpoint and writes data chunks as SSE events.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Frontend Consumer&lt;/strong&gt;: The client-side framework (e.g., Angular) initializes a native browser &lt;code&gt;EventSource&lt;/code&gt; object to listen to the endpoint.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;UI Rendering&lt;/strong&gt;: The interface listens for incoming chunks and renders the updates in real time as they arrive.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Stream End:&lt;/strong&gt; Once complete, the application treats the closed stream as a normal finish state. &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwtmi5xd547x96sfkwosn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwtmi5xd547x96sfkwosn.png" alt=" " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is especially useful for progress UIs, logs, and status updates.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reference
&lt;/h2&gt;

&lt;p&gt;Full code is available here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/vimalamaldas/Streaming-Sample" rel="noopener noreferrer"&gt;https://github.com/vimalamaldas/Streaming-Sample&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What this sample does
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Backend
&lt;/h3&gt;

&lt;p&gt;An ASP.NET endpoint sends streaming chunks as SSE.&lt;/p&gt;

&lt;h3&gt;
  
  
  Frontend
&lt;/h3&gt;

&lt;p&gt;An Angular service creates an &lt;code&gt;EventSource&lt;/code&gt; and exposes the stream to a component.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>streaming</category>
      <category>sse</category>
      <category>realtime</category>
    </item>
    <item>
      <title>Integrate a Copilot Studio Agent into an Existing .NET App Using Agents SDK</title>
      <dc:creator>Vimal</dc:creator>
      <pubDate>Sun, 19 Apr 2026 17:16:17 +0000</pubDate>
      <link>https://dev.to/vimaltwit/integrate-a-copilot-studio-agent-into-an-existing-net-app-using-agents-sdk-248e</link>
      <guid>https://dev.to/vimaltwit/integrate-a-copilot-studio-agent-into-an-existing-net-app-using-agents-sdk-248e</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;If your application already has an API, the fastest way to add AI is to integrate an agent created using Microsoft Copilot studio.&lt;br&gt;
Microsoft Copilot studio is an agent building platform that offers integration of agents into your applications using Microsoft Agents SDK.&lt;/p&gt;

&lt;p&gt;This walkthrough shows how to wire a Copilot Studio agent into an existing .NET application using the Microsoft Agents SDK approach.&lt;/p&gt;
&lt;h2&gt;
  
  
  Pre-requisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Agent created using Microsoft Copilot studio&lt;/li&gt;
&lt;li&gt;Agent is attached to a knowledge source (SharePoint, Web, Azure Search, 3rd party APIs)&lt;/li&gt;
&lt;li&gt;.NET API with an app registration having API permissions &lt;em&gt;&lt;strong&gt;Copilot Studio.Copilots.Invoke&lt;/strong&gt;&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Add &lt;code&gt;CopilotStudioDocumentRetrievalService&lt;/code&gt; to your existing interface.&lt;/li&gt;
&lt;li&gt;Retrieve Agent settings from Copilot Studio&lt;/li&gt;
&lt;li&gt;Support both user passthrough and OBO token flow.&lt;/li&gt;
&lt;li&gt;Stream agent output through SSE for chat-like UX.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Architecture: Existing App + Copilot Studio Agent
&lt;/h2&gt;

&lt;p&gt;The architecture consists of three main components&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;.NET API with SSE Endpoint&lt;br&gt;
Create an endpoint that provides a response as and when the API receives a response from Copilot agent. This is very important to provide notifications to the client as when response is available.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Retrieval Layer using Agents SDK (This is the Copilot client)&lt;br&gt;
This layer invokes the Copilot agent using the Agents SDK leveraging the configuration settings for the agent.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A Copilot Agent created using Microsoft Copilot Studio attached to a knowledge source that acts as the grounding data.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3d0ejrxhrg263euloxtu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3d0ejrxhrg263euloxtu.png" alt=" " width="800" height="384"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 1: Add the SDK dependencies
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Microsoft.Agents.CopilotStudio.Client&lt;/code&gt; &lt;a href="https://github.com/microsoft/Agents" rel="noopener noreferrer"&gt;Microsoft 365 Agents SDK&lt;/a&gt; for invoking Copilot agent&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Microsoft.Identity.Client&lt;/code&gt; for authentication
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ItemGroup&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"Microsoft.Agents.CopilotStudio.Client"&lt;/span&gt; &lt;span class="na"&gt;Version=&lt;/span&gt;&lt;span class="s"&gt;"1.3.176"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"Microsoft.Identity.Client"&lt;/span&gt; &lt;span class="na"&gt;Version=&lt;/span&gt;&lt;span class="s"&gt;"4.78.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Step 2: Retrieve Agent settings from Copilot studio
&lt;/h2&gt;

&lt;p&gt;Navigate to the Copilot agent, Select Settings &amp;gt; Advanced. Under &lt;strong&gt;Metadata&lt;/strong&gt;, you need the Environment ID, Tenant ID, and Schema name of the agent. Copy these metadata values and add it to app settings.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiqrbvg9ti98pcbagsimn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiqrbvg9ti98pcbagsimn.png" alt=" " width="800" height="326"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Retrieval"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Provider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CopilotStudio"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"CopilotStudio"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"EnvironmentId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;env-id&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"SchemaName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;agent-schema-name&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"AuthMode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"User"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"TenantId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;tenant-id&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"AppClientId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;app-client-id&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"AppClientSecret"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Retrieve and add &lt;code&gt;AppClientId&lt;/code&gt; (client Id) and &lt;code&gt;AppClientSecret&lt;/code&gt; (secret) of the App registration that has API permissions to invoke Copilot agent. App registration requires the following API permissions:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Power Platform API &amp;gt; CopilotStudio.Copilots.Invoke&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Add strongly typed Copilot settings for configuration using Options pattern&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CopilotStudioOptions&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;EnvironmentId&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Empty&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;SchemaName&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Empty&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;AuthMode&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"App"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;TenantId&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Empty&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;AppClientId&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Empty&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;AppClientSecret&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Empty&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Register DI for CopilotStudio
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Configure&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;CopilotStudioOptions&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;
    &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetSection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CopilotStudio"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

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

&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddKeyedScoped&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IDocumentStreamingService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CopilotStudioDocumentRetrievalService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"Copilot"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4: Initialize Copilot client
&lt;/h2&gt;

&lt;p&gt;Initialize the Copilot client using the configuration values that was originally copied from the Copilot agent metadata.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;connectionSettings&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;ConnectionSettings&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;EnvironmentId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EnvironmentId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;SchemaName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AgentIdentifier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Cloud&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PowerPlatformCloud&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Prod&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;CopilotAgentType&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AgentType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Published&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="n"&gt;scope&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CopilotClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ScopeFromSettings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;connectionSettings&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use &lt;code&gt;AskQuestionAsync(...)&lt;/code&gt; to stream activity text and map it into your existing result model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Intialize conversation with Copilot
&lt;/h2&gt;

&lt;p&gt;Initialize a conversation session with Copilot before asking a question:&lt;/p&gt;

&lt;p&gt;This is a setup phase before actually asking a question. Copilot needs to establish a conversation context (session ID, connection state, etc.) before handling queries. The code waits for this initialization to complete, then proceeds to &lt;code&gt;AskQuestionAsync(...)&lt;/code&gt; to get actual results.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;startupActivity&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;copilotClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StartConversationAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;emitStartConversationEvent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;StartConversationAsync(...)&lt;/code&gt; to initialize a new conversation session with Copilot&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;emitStartConversationEvent: true&lt;/code&gt; tells Copilot to emit initialization events (e.g., handshake messages, acknowledgments)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;await foreach&lt;/code&gt; iterates over the stream of activities Copilot sends during startup&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cancellationToken&lt;/code&gt; allows the operation to be cancelled if needed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once the session is initialized use &lt;code&gt;AskQuestionAsync(...)&lt;/code&gt; that takes the user query &lt;code&gt;query&lt;/code&gt; as input parameter to get actual results, use await to asynchronously iterate over activities returned from Copilot as they arrive&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;activity&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;copilotClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AskQuestionAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;conversationId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 6: Expose SSE endpoint for near real-time responses
&lt;/h2&gt;

&lt;p&gt;Add SSE specific code in the controller to process and send real-time data to client &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft6xkgef09wuw2fflrefw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft6xkgef09wuw2fflrefw.png" alt=" " width="800" height="320"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Response.ContentType = "text/event-stream"&lt;br&gt;
&lt;/code&gt;Tells the client this HTTP response is an SSE stream, so data can arrive continuously instead of all at once.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Response.Headers.Append("Cache-Control", "no-cache")&lt;br&gt;
&lt;/code&gt;Prevents caching so the browser/proxy always receives fresh streamed events.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;await foreach (var activity in retrievalService.StreamActivitiesAsync(...))&lt;br&gt;
&lt;/code&gt;Reads activities one-by-one asynchronously from the service as they become available.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;JsonSerializer.Serialize(activity)&lt;br&gt;
&lt;/code&gt;Converts each activity object into JSON text.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;await Response.WriteAsync($"data: {json}\n\n", ...)&lt;br&gt;
&lt;/code&gt;Writes each item in SSE format.&lt;br&gt;
Each SSE message must start with data: and end with a blank line (\n\n), which signals one complete event to the client.&lt;/p&gt;

&lt;p&gt;Overall, this is a streaming endpoint that pushes incremental activity updates to the frontend in real time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ContentType&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"text/event-stream"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Cache-Control"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"no-cache"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;activity&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;retrievalService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StreamActivitiesAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;JsonSerializer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Serialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;activity&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"data: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;\n\n"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Quick test commands
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s2"&gt;"https://localhost:5001/api/query"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &amp;lt;user-token&amp;gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"query":"Summarize the onboarding flow","top":5}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-N&lt;/span&gt; &lt;span class="s2"&gt;"https://localhost:5001/api/query/stream?query=What%20changed%20in%20the%20last%20release%3F&amp;amp;agentType=Copilot"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Final thought
&lt;/h2&gt;

&lt;p&gt;Copilot Studio integration is the easiest to introduce AI capabilities to existing application. Use Copilot studio to create agents and integrate the agent using Microsoft Agents SDK.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>copilotstudio</category>
      <category>ai</category>
      <category>azure</category>
    </item>
    <item>
      <title>Modern Logging and Telemetry in .Net</title>
      <dc:creator>Vimal</dc:creator>
      <pubDate>Fri, 20 Feb 2026 15:29:53 +0000</pubDate>
      <link>https://dev.to/vimaltwit/modern-logging-and-telemetry-in-net-inj</link>
      <guid>https://dev.to/vimaltwit/modern-logging-and-telemetry-in-net-inj</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Logging and telemetry are essential pillars of operational excellence in modern software systems. They provide real-time visibility into application behavior, system performance, and user interactions, enabling DevOps teams to detect and troubleshoot issues quickly before they impact users. Beyond just technical insights, this data informs product management decisions and enhances customer engagement by enabling proactive improvements and a deeper understanding of how users interact with the product.&lt;/p&gt;

&lt;h2&gt;
  
  
  🎯 Article Objective
&lt;/h2&gt;

&lt;p&gt;The objective of this article is to introduce you to the fundamentals of &lt;strong&gt;OpenTelemetry&lt;/strong&gt; and its integration with &lt;strong&gt;Azure Application Insights&lt;/strong&gt; in a .NET application. It aims to highlight the importance of logging and telemetry in achieving &lt;strong&gt;operational excellence&lt;/strong&gt;, particularly in modern cloud-native systems. By the end of this article, readers will understand how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set up OpenTelemetry for distributed tracing and metrics collection in a .NET Web API.&lt;/li&gt;
&lt;li&gt;Enable real-time visibility into application performance using Application Insights.&lt;/li&gt;
&lt;li&gt;Enhance troubleshooting, DevOps workflows, and customer experience through effective telemetry.&lt;/li&gt;
&lt;li&gt;Implement correlation IDs for traceability across services.&lt;/li&gt;
&lt;li&gt;Collect critical performance metrics such as CPU usage, memory availability, and request duration.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This hands-on guide empowers developers to build more reliable, observable, and user-centric applications.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔍 What is OpenTelemetry?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;OpenTelemetry&lt;/strong&gt; is an open-source standard for collecting telemetry data — &lt;strong&gt;logs&lt;/strong&gt;, &lt;strong&gt;metrics&lt;/strong&gt;, and &lt;strong&gt;traces&lt;/strong&gt; — from your application.&lt;/p&gt;

&lt;p&gt;It helps answer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How long does a request take?&lt;/li&gt;
&lt;li&gt;What services were involved in processing it?&lt;/li&gt;
&lt;li&gt;Where are the bottlenecks?&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  📘 Why Not Just Use Logging?
&lt;/h2&gt;

&lt;p&gt;Traditional logging is useful, but lacks &lt;strong&gt;context&lt;/strong&gt;. Here’s how OpenTelemetry compares:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Logging&lt;/th&gt;
&lt;th&gt;OpenTelemetry&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Simple log messages&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tracing across services&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Built-in metrics (CPU, memory)&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Visualization in tools like Application Insights&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Correlation across services&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🎯 Why Use OpenTelemetry with Application Insights?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Application Insights&lt;/strong&gt; is a powerful observability platform in Azure.&lt;/li&gt;
&lt;li&gt;OpenTelemetry allows your app to send &lt;strong&gt;standardized, portable telemetry data&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Gain &lt;strong&gt;end-to-end visibility&lt;/strong&gt; into distributed systems, including APIs, microservices, and external dependencies.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🛠️ Step-by-Step: Use OpenTelemetry in .NET 7
&lt;/h2&gt;

&lt;p&gt;We’ll build a simple Web API that uses OpenTelemetry to trace requests and collect system metrics.&lt;/p&gt;




&lt;h3&gt;
  
  
  📦 Step 1: Add Required Packages
&lt;/h3&gt;

&lt;p&gt;Run this in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet add package Microsoft.ApplicationInsights.AspNetCore
dotnet add package OpenTelemetry.Extensions.Hosting
dotnet add package OpenTelemetry.Instrumentation.AspNetCore
dotnet add package OpenTelemetry.Instrumentation.Http
dotnet add package OpenTelemetry.Exporter.ApplicationInsights
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🧠 Step 2: Configure Program.cs
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.ApplicationInsights.Extensibility&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;OpenTelemetry.Resources&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;OpenTelemetry.Trace&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;OpenTelemetry.Metrics&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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

&lt;span class="c1"&gt;// Enable Application Insights&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddApplicationInsightsTelemetry&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// OpenTelemetry setup&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddOpenTelemetry&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConfigureResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resource&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MyWebApi"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithTracing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tracing&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;tracing&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddAspNetCoreInstrumentation&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddHttpClientInstrumentation&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddSource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MyWebApi"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetSampler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;AlwaysOnSampler&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddApplicationInsightsExporter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ConnectionString&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"APPLICATIONINSIGHTS_CONNECTION_STRING"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="p"&gt;}))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithMetrics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;metrics&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;metrics&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddAspNetCoreInstrumentation&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddRuntimeInstrumentation&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddProcessInstrumentation&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddApplicationInsightsMetricsExporter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ConnectionString&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"APPLICATIONINSIGHTS_CONNECTION_STRING"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="p"&gt;}));&lt;/span&gt;

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

&lt;span class="c1"&gt;// Middleware to add correlation ID to response&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;traceId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Diagnostics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Activity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Current&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;TraceId&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsNullOrEmpty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;traceId&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"X-Correlation-ID"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;traceId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapControllers&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  📂 Step 3: Create a Controller (TraceDemoController.cs)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.AspNetCore.Mvc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Diagnostics&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;MyWebApi.Controllers&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ApiController&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[controller]"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TraceDemoController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ControllerBase&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;ActivitySource&lt;/span&gt; &lt;span class="n"&gt;ActivitySource&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MyWebApi"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;HttpGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hello"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IActionResult&lt;/span&gt; &lt;span class="nf"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;activity&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ActivitySource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StartActivity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SayHello"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;traceId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Activity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Current&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;TraceId&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;Message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Hello, world!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;TraceId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;traceId&lt;/span&gt;
            &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ⚙️ Step 4: Add Configuration (appsettings.json)
&lt;/h3&gt;

&lt;p&gt;Add your Application Insights connection string:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "Logging": {
    "LogLevel": {
      "Default": "Information"
    }
  },
  "APPLICATIONINSIGHTS_CONNECTION_STRING": "InstrumentationKey=YOUR-KEY-HERE"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  📊 Metrics You Get Automatically
&lt;/h3&gt;

&lt;p&gt;OpenTelemetry + Application Insights gives you:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Request duration&lt;/td&gt;
&lt;td&gt;&lt;code&gt;AddAspNetCoreInstrumentation&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CPU usage&lt;/td&gt;
&lt;td&gt;&lt;code&gt;AddRuntimeInstrumentation&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Memory available&lt;/td&gt;
&lt;td&gt;&lt;code&gt;AddProcessInstrumentation&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Request count&lt;/td&gt;
&lt;td&gt;&lt;code&gt;AddAspNetCoreInstrumentation&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;All these show up in Azure Application Insights under Metrics.&lt;/p&gt;

&lt;h3&gt;
  
  
  🧪 Testing the API
&lt;/h3&gt;

&lt;p&gt;Run the app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Call the endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET http://localhost:5000/TraceDemo/hello
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You’ll see the X-Correlation-ID in the response headers — that’s your trace ID!&lt;/p&gt;

&lt;h3&gt;
  
  
  📈 Viewing in Application Insights
&lt;/h3&gt;

&lt;p&gt;Go to Azure Portal &amp;gt; Application Insights.&lt;/p&gt;

&lt;h4&gt;
  
  
  Use:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Application Map&lt;/code&gt; for service relationships.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Metrics&lt;/code&gt; to view CPU, memory, and requests.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Traces&lt;/code&gt; to search with X-Correlation-ID.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Performance&lt;/code&gt; to analyze slow endpoints.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ✅ Summary
&lt;/h3&gt;

&lt;p&gt;With OpenTelemetry + Application Insights, you now have:&lt;/p&gt;

&lt;p&gt;✔ Distributed tracing&lt;/p&gt;

&lt;p&gt;✔ Built-in performance metrics&lt;/p&gt;

&lt;p&gt;✔ Context-rich diagnostics&lt;/p&gt;

&lt;p&gt;✔ Cloud-native observability&lt;/p&gt;

&lt;p&gt;This is a big step up from traditional logging and a must-have for any production-ready .NET app.&lt;/p&gt;

&lt;h3&gt;
  
  
  🧭 What’s Next?
&lt;/h3&gt;

&lt;p&gt;Connect logs (ILogger) to trace context.&lt;/p&gt;

&lt;p&gt;Export telemetry to other tools (Jaeger, Prometheus, etc.).&lt;/p&gt;

&lt;p&gt;Set up alerts based on CPU, memory, or request duration.&lt;/p&gt;

&lt;h3&gt;
  
  
  🧠 Got Questions?
&lt;/h3&gt;

&lt;p&gt;Feel free to drop issues or suggestions!&lt;/p&gt;

</description>
      <category>applicationinsights</category>
      <category>operationalexcellence</category>
      <category>dotnetcore</category>
    </item>
    <item>
      <title>Managing NPM Registries in restricted environments</title>
      <dc:creator>Vimal</dc:creator>
      <pubDate>Wed, 23 Jul 2025 05:26:27 +0000</pubDate>
      <link>https://dev.to/vimaltwit/managing-npm-registries-in-restricted-environments-cgo</link>
      <guid>https://dev.to/vimaltwit/managing-npm-registries-in-restricted-environments-cgo</guid>
      <description>&lt;h2&gt;
  
  
  Problem statement:
&lt;/h2&gt;

&lt;p&gt;Recently we faced a challenge where our organization does not allow us to connect to the public NPM registry to develop locally. However the CI/CD pipelines of the client organization allowed connection to the public registry. As a team, we were pondering on different approaches to handle this unique situation. We could probably use two copies of package.json  one for local having reference link to private registry and then another one for CI/CD pipeline. Is this a good approach or is there a better approach? Let us explore this in the article.&lt;/p&gt;

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

&lt;p&gt;This is a common scenario in some enterprise environments, developers work behind strict firewalls or disconnected networks that &lt;strong&gt;block access to the public NPM registry&lt;/strong&gt;. Yet, the CI/CD pipelines (like Azure DevOps) may be fully open to the internet. This mismatch creates a development headache—how do you keep your dependencies synced and builds working smoothly?&lt;/p&gt;

&lt;p&gt;A common (but bad) idea is to maintain &lt;strong&gt;two separate &lt;code&gt;package.json&lt;/code&gt; files&lt;/strong&gt;—one for local dev and one for CI/CD. But this introduces more problems than it solves.&lt;/p&gt;

&lt;p&gt;The better, cleaner approach? &lt;strong&gt;Use &lt;code&gt;.npmrc&lt;/code&gt; files smartly&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this article let us explore how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use a &lt;strong&gt;private registry&lt;/strong&gt; for local development&lt;/li&gt;
&lt;li&gt;Let &lt;strong&gt;Azure DevOps pipelines use the public registry&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Securely manage credentials&lt;/li&gt;
&lt;li&gt;Avoid sync issues between environments&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ❌ Why Two &lt;code&gt;package.json&lt;/code&gt; Files Is a Bad Idea
&lt;/h2&gt;

&lt;p&gt;Some teams try to maintain one &lt;code&gt;package.json&lt;/code&gt; for local (private registry) and another for CI/CD (public registry).&lt;/p&gt;

&lt;p&gt;Here’s why that’s problematic:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dependency drift&lt;/strong&gt;: Easy to forget syncing both files&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lockfile conflicts&lt;/strong&gt;: &lt;code&gt;package-lock.json&lt;/code&gt; mismatches can cause broken builds&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hard to audit&lt;/strong&gt;: Tools like &lt;code&gt;npm audit&lt;/code&gt;, dependabot, etc. lose context&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Increased complexity&lt;/strong&gt;: More files, more chances of human error&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ✅ The Right Way: Use &lt;code&gt;.npmrc&lt;/code&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Local Development Setup
&lt;/h3&gt;

&lt;p&gt;In your Angular or Node project, create a &lt;code&gt;.npmrc&lt;/code&gt; file &lt;strong&gt;only for local use&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="c"&gt;# .npmrc (DO NOT commit to Git)
&lt;/span&gt;&lt;span class="py"&gt;registry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;https://your-private-registry.company.com/&lt;/span&gt;
&lt;span class="py"&gt;always-auth&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or for scoped packages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="err"&gt;@your-org:&lt;/span&gt;&lt;span class="py"&gt;registry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;https://your-private-registry.company.com/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;.gitignore&lt;/code&gt; It!
&lt;/h3&gt;

&lt;p&gt;To avoid leaking sensitive registry info, add &lt;code&gt;.npmrc&lt;/code&gt; to &lt;code&gt;.gitignore&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.npmrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can safely run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Azure DevOps CI/CD Setup
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ✅ Option 1: Use Public NPM Registry (Recommended for Pipelines)
&lt;/h3&gt;

&lt;p&gt;Azure DevOps build agents can access the public registry by default. So just omit &lt;code&gt;.npmrc&lt;/code&gt; in your repo and let it install dependencies directly from &lt;code&gt;https://registry.npmjs.org&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Install&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Dependencies'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Option 2: Use Private Registry in CI/CD (If Required)
&lt;/h3&gt;

&lt;p&gt;If your pipeline must use a private registry, create a secret token in Azure DevOps (&lt;code&gt;npm_token&lt;/code&gt;) and inject &lt;code&gt;.npmrc&lt;/code&gt; at build time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;NPM_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$(npm_token)&lt;/span&gt;

&lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;echo "registry=https://your-private-registry.company.com/" &amp;gt; .npmrc&lt;/span&gt;
      &lt;span class="s"&gt;echo "//your-private-registry.company.com/:_authToken=$(NPM_TOKEN)" &amp;gt;&amp;gt; .npmrc&lt;/span&gt;
    &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Configure&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Private&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Registry'&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;
    &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Install&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Dependencies'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Full Azure DevOps Pipeline for Angular
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;trigger&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;

&lt;span class="na"&gt;pool&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;vmImage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ubuntu-latest'&lt;/span&gt;

&lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NodeTool@0&lt;/span&gt;
  &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;versionSpec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;18.x'&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Install&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Node.js'&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;echo "registry=https://registry.npmjs.org/" &amp;gt; .npmrc&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Use&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Public&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;NPM&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Registry'&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Install&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Dependencies'&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run build&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Build&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Angular&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;App'&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PublishBuildArtifacts@1&lt;/span&gt;
  &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;pathToPublish&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;dist'&lt;/span&gt;
    &lt;span class="na"&gt;artifactName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;angular-app'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Local vs CI/CD Setup
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6vbcjfw76vhtvdc2k5os.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6vbcjfw76vhtvdc2k5os.png" alt="Local vs CI/CD NPM Registry Setup" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;
 Local vs CI/CD 






&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Don’t manage two &lt;code&gt;package.json&lt;/code&gt; files&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;.npmrc&lt;/code&gt; to cleanly separate dev and CI registry logic&lt;/li&gt;
&lt;li&gt;Keep &lt;code&gt;.npmrc&lt;/code&gt; out of version control&lt;/li&gt;
&lt;li&gt;Use secure tokens in Azure DevOps&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Bonus Tips
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Use &lt;code&gt;npmrc&lt;/code&gt; CLI for Switching
&lt;/h3&gt;

&lt;p&gt;If you switch between multiple registries, use &lt;a href="https://www.npmjs.com/package/npmrc" rel="noopener noreferrer"&gt;&lt;code&gt;npmrc&lt;/code&gt;&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npmrc private
npmrc public
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Scoped Packages
&lt;/h3&gt;

&lt;p&gt;To avoid overriding global registry settings, scope packages and use this pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="err"&gt;@your-org:&lt;/span&gt;&lt;span class="py"&gt;registry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;https://private.registry.com/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;Using &lt;code&gt;.npmrc&lt;/code&gt; properly lets you handle both restricted dev environments and open CI/CD pipelines with ease. It’s clean, secure, and scalable—everything a good DevOps setup should be.&lt;/p&gt;

&lt;p&gt;Let me know in the comments your feedback, if you want a complete deploy-to-Azure setup or if you're facing similar restrictions in your organization!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>angular</category>
      <category>npm</category>
      <category>azuredevops</category>
    </item>
    <item>
      <title>Designing for Dependency Injection — Think Like a Developer, Not a Container</title>
      <dc:creator>Vimal</dc:creator>
      <pubDate>Sun, 20 Jul 2025 16:21:47 +0000</pubDate>
      <link>https://dev.to/vimaltwit/designing-for-dependency-injection-think-like-a-developer-not-a-container-42jo</link>
      <guid>https://dev.to/vimaltwit/designing-for-dependency-injection-think-like-a-developer-not-a-container-42jo</guid>
      <description>&lt;p&gt;Before reaching for &lt;code&gt;.AddScoped&lt;/code&gt; or &lt;code&gt;new&lt;/code&gt;, take a step back and &lt;strong&gt;ask what your class needs to do&lt;/strong&gt; — not what it needs to &lt;em&gt;create&lt;/em&gt;. This should model a functionality from the business domain.&lt;/p&gt;

&lt;h3&gt;
  
  
  Design Thinking First, DI Later
&lt;/h3&gt;

&lt;p&gt;A well-designed class doesn't scream for injection. It simply:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Has a clear purpose.&lt;/li&gt;
&lt;li&gt;Exposes what it needs to perform that purpose.&lt;/li&gt;
&lt;li&gt;Delegates responsibilities it shouldn't own.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s unpack that with a practical approach.&lt;/p&gt;




&lt;h3&gt;
  
  
  Step 1: Identify the Class's Responsibility
&lt;/h3&gt;

&lt;p&gt;Ask: &lt;strong&gt;What behavior is this class responsible for?&lt;/strong&gt; . Let us analyse an order processing functionality. How would you model the behavior and construct the class?&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderProcessor&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ProcessOrder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Validate order&lt;/span&gt;
        &lt;span class="c1"&gt;// Charge payment&lt;/span&gt;
        &lt;span class="c1"&gt;// Send confirmation email&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looking at the above class, you’ve already spotted the problem: This class does &lt;strong&gt;too much&lt;/strong&gt;. This is linked to the &lt;strong&gt;'S'&lt;/strong&gt; in &lt;strong&gt;SOLID&lt;/strong&gt; principles, the class should handle only a single-responsibility. &lt;/p&gt;




&lt;h3&gt;
  
  
  Step 2: Delegate Responsibilities via Abstractions
&lt;/h3&gt;

&lt;p&gt;Break it down. Let other services handle each concern.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IOrderValidator&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;Validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IPaymentService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Charge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;INotificationService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;SendConfirmation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now rewrite &lt;code&gt;OrderProcessor&lt;/code&gt; as a &lt;strong&gt;coordinator&lt;/strong&gt;, not a worker:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderProcessor&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;IOrderValidator&lt;/span&gt; &lt;span class="n"&gt;_validator&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;IPaymentService&lt;/span&gt; &lt;span class="n"&gt;_payment&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;INotificationService&lt;/span&gt; &lt;span class="n"&gt;_notifier&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;OrderProcessor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;IOrderValidator&lt;/span&gt; &lt;span class="n"&gt;validator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;IPaymentService&lt;/span&gt; &lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;INotificationService&lt;/span&gt; &lt;span class="n"&gt;notifier&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_validator&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;validator&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;_payment&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;_notifier&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;notifier&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ProcessOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;_validator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="n"&gt;_payment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Charge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;_notifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SendConfirmation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You’ve just designed for &lt;strong&gt;Dependency Injection&lt;/strong&gt; — without thinking about the container.&lt;/p&gt;




&lt;h3&gt;
  
  
  Step 3: Make It Testable and Flexible
&lt;/h3&gt;

&lt;p&gt;This class can now be tested using mocks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;mockValidator&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Mock&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IOrderValidator&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;span class="n"&gt;mockValidator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;It&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsAny&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;())).&lt;/span&gt;&lt;span class="nf"&gt;Returns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;mockPayment&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Mock&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IPaymentService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;mockNotifier&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Mock&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;INotificationService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;processor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OrderProcessor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mockValidator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mockPayment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mockNotifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;processor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ProcessOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ No real implementations required. ✅ You can test logic in isolation.&lt;/p&gt;




&lt;h3&gt;
  
  
  Step 4: Let the Container Wire It Up
&lt;/h3&gt;

&lt;p&gt;Only now do you register it in &lt;code&gt;.NET Core&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddScoped&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IOrderValidator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OrderValidator&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddScoped&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IPaymentService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StripePaymentService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddScoped&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;INotificationService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;EmailNotifier&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddScoped&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;OrderProcessor&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Summary: The Design-First DI Checklist
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;Ask Yourself…&lt;/th&gt;
&lt;th&gt;Outcome&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;What does this class need to &lt;em&gt;do&lt;/em&gt;?&lt;/td&gt;
&lt;td&gt;Define the class’s responsibility&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;What can be delegated to collaborators?&lt;/td&gt;
&lt;td&gt;Extract abstractions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;How can this class be tested in isolation?&lt;/td&gt;
&lt;td&gt;Refactor for injectability&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Where do I register this in DI container?&lt;/td&gt;
&lt;td&gt;Configure DI at the edges&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  📌 Remember
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;DI isn’t about using a container.&lt;br&gt;
It’s about designing classes that &lt;strong&gt;ask for what they need&lt;/strong&gt;, instead of building it themselves.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Start from behavior. Inject contracts. Let the container worry about construction.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>microsoft</category>
      <category>designpatterns</category>
    </item>
    <item>
      <title>Dependency Injection in .NET Core</title>
      <dc:creator>Vimal</dc:creator>
      <pubDate>Sun, 20 Jul 2025 15:56:40 +0000</pubDate>
      <link>https://dev.to/vimaltwit/dependency-injection-in-net-core-4j51</link>
      <guid>https://dev.to/vimaltwit/dependency-injection-in-net-core-4j51</guid>
      <description>&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Dependency Injection (DI)&lt;/strong&gt; is a software design pattern and technique that deals with how components acquire their dependencies. Rather than creating dependencies internally, a class receives them from the outside — improving &lt;strong&gt;modularity&lt;/strong&gt;, &lt;strong&gt;testability&lt;/strong&gt;, and &lt;strong&gt;flexibility&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In .NET, Dependency Injection is a &lt;strong&gt;first-class citizen&lt;/strong&gt;, built directly into the ASP.NET Core framework.&lt;/p&gt;




&lt;h2&gt;
  
  
  Purpose
&lt;/h2&gt;

&lt;p&gt;Dependency Injection aims to &lt;strong&gt;separate the creation of a component’s dependencies from the component’s behavior&lt;/strong&gt;, promoting &lt;strong&gt;Inversion of Control (IoC)&lt;/strong&gt;. The class should focus only on &lt;em&gt;what it needs to do&lt;/em&gt;, not on &lt;em&gt;how to create the things it needs&lt;/em&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Don't call me, I’ll call you." — This summarizes Inversion of Control, where the framework injects required services into your class.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Some of the common dependencies needed in application are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Services (ILogger, DbContext, etc.)&lt;/li&gt;
&lt;li&gt;Repositories (ICustomerRepository)&lt;/li&gt;
&lt;li&gt;Configurations (IOptions)&lt;/li&gt;
&lt;li&gt;External integrations (IEmailService, IPaymentGateway)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Types of Dependency Injection
&lt;/h2&gt;

&lt;p&gt;There are three common forms of DI:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Constructor Injection&lt;/strong&gt; (most common)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Setter Injection&lt;/strong&gt; (property-based)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interface Injection&lt;/strong&gt; (less common in .NET)&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  1. Constructor Injection
&lt;/h3&gt;

&lt;p&gt;The dependency is provided through the class constructor.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IMessageService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;GetMessage&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EmailMessageService&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IMessageService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;GetMessage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Message via Email"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NotificationManager&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;IMessageService&lt;/span&gt; &lt;span class="n"&gt;_messageService&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;NotificationManager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IMessageService&lt;/span&gt; &lt;span class="n"&gt;messageService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_messageService&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;messageService&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Notify&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_messageService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetMessage&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Registration in .NET Core
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddTransient&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IMessageService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;EmailMessageService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddTransient&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;NotificationManager&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  2. Setter (Property) Injection
&lt;/h3&gt;

&lt;p&gt;Dependencies are set via public properties. Not natively supported by the built-in container, but possible manually.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LoggerService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IMessageService&lt;/span&gt; &lt;span class="n"&gt;MessageService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MessageService&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;GetMessage&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, &lt;code&gt;MessageService&lt;/code&gt; would need to be set manually after object construction.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Interface Injection
&lt;/h3&gt;

&lt;p&gt;The dependency provides an interface to inject itself into the consumer. Rare in .NET:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IInjectable&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IMessageService&lt;/span&gt; &lt;span class="n"&gt;messageService&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Consumers then implement &lt;code&gt;Inject&lt;/code&gt; to receive the dependency.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lifetimes in .NET DI
&lt;/h2&gt;

&lt;p&gt;When registering services, you specify how long a service lives:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Transient&lt;/code&gt; – new instance each time&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Scoped&lt;/code&gt; – one instance per request&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Singleton&lt;/code&gt; – one instance for the app lifetime
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddTransient&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IMyService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MyService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt; &lt;span class="c1"&gt;// new each time&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddScoped&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IMyService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MyService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;    &lt;span class="c1"&gt;// one per web request&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddSingleton&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IMyService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MyService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt; &lt;span class="c1"&gt;// shared instance&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Dependency Graph
&lt;/h2&gt;

&lt;p&gt;.NET Core builds a &lt;strong&gt;dependency graph&lt;/strong&gt; during application startup. Circular dependencies (A → B → A) are automatically detected and cause an error.&lt;/p&gt;




&lt;h2&gt;
  
  
  Benefits of DI
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Decoupling: Easier to replace or extend components&lt;/li&gt;
&lt;li&gt;Testability: Easier to write unit tests using mocks&lt;/li&gt;
&lt;li&gt;Reusability: Services can be reused across classes&lt;/li&gt;
&lt;li&gt;Maintainability: Easier to manage and evolve large applications&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Real-world Example
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IPaymentProcessor&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;decimal&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StripePaymentProcessor&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IPaymentProcessor&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;decimal&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Processed $&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; via Stripe."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CheckoutService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;IPaymentProcessor&lt;/span&gt; &lt;span class="n"&gt;_paymentProcessor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;CheckoutService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IPaymentProcessor&lt;/span&gt; &lt;span class="n"&gt;paymentProcessor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_paymentProcessor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;paymentProcessor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Checkout&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_paymentProcessor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Registration:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddScoped&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IPaymentProcessor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StripePaymentProcessor&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddScoped&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;CheckoutService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Usage:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;checkout&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetRequiredService&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;CheckoutService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;span class="n"&gt;checkout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Checkout&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Outputs: Processed $100 via Stripe.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Anti-Patterns to Avoid
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Service Locator Pattern&lt;/strong&gt;: Using &lt;code&gt;IServiceProvider.GetService()&lt;/code&gt; everywhere breaks DI principles.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Too Many Dependencies&lt;/strong&gt;: If a class has too many injected services, it's likely violating &lt;strong&gt;Single Responsibility Principle&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mixing lifetimes improperly&lt;/strong&gt;: Injecting &lt;code&gt;Scoped&lt;/code&gt; into &lt;code&gt;Singleton&lt;/code&gt; can cause unexpected behavior.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Dependency Injection in .NET Core encourages clean architecture by separating behavior from object creation. It's built-in, powerful, and essential for test-driven and scalable .NET applications.&lt;/p&gt;

&lt;p&gt;By focusing on &lt;strong&gt;what your classes need to do&lt;/strong&gt;, and not how they get their dependencies, your application becomes more maintainable, testable, and adaptable to change.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>dotnet</category>
      <category>dependencyinversion</category>
    </item>
    <item>
      <title>Distribute iOS mobile applications(without App Store)</title>
      <dc:creator>Vimal</dc:creator>
      <pubDate>Wed, 16 Jul 2025 00:59:02 +0000</pubDate>
      <link>https://dev.to/vimaltwit/distribute-ios-mobile-applicationswithout-app-store-1260</link>
      <guid>https://dev.to/vimaltwit/distribute-ios-mobile-applicationswithout-app-store-1260</guid>
      <description>&lt;p&gt;Ever built an app just for &lt;em&gt;yourself&lt;/em&gt; and wondered, &lt;em&gt;"How do I get this running on my iPhone without publishing it to the App Store?"&lt;/em&gt; Whether you're testing a side project, creating a tool for personal productivity, or experimenting with Flutter or SwiftUI, deploying a private app to your own device is totally doable—no paid Apple Developer account required.&lt;/p&gt;

&lt;p&gt;In this post, I’ll walk you through how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build and install a personal iOS app on your device using &lt;strong&gt;Xcode&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Run the app without using TestFlight or the App Store&lt;/li&gt;
&lt;li&gt;Fix that annoying issue where the app stops working once you unplug the USB&lt;/li&gt;
&lt;li&gt;Decide if a &lt;strong&gt;free&lt;/strong&gt; Apple ID is enough for your needs—or if it's time to go &lt;strong&gt;Pro&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s dive into how you can run your own iOS app —no distribution headaches, no gatekeepers, just your code on your phone.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Free (“Personal”) Provisioning via Xcode
&lt;/h2&gt;

&lt;p&gt;Apple lets you install &lt;em&gt;debug&lt;/em&gt; builds on your own device using just a free Apple ID—but with some limitations (e.g. 1 app per bundle‑ID, the provisioning profile expires weekly, and you can’t share to other people).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Install Xcode&lt;/strong&gt;&lt;br&gt;
– On your Mac, download Xcode from the App Store.&lt;br&gt;
– Make sure you have at least macOS Sonoma (14.0) or later.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Open Your Project&lt;/strong&gt;&lt;br&gt;
– If you’re using Flutter, open your project root and execute.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;    flutter build ios

    open ios/Runner.xcworkspace 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;br&gt;
– If you’re native Swift/Obj‑C: open your &lt;code&gt;.xcodeproj&lt;/code&gt; or &lt;code&gt;.xcworkspace&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Add Your Apple ID&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In Xcode, go to &lt;strong&gt;Xcode ▶️ Settings ▶️ Accounts&lt;/strong&gt;, click “+”, and sign in with your Apple ID.&lt;/li&gt;
&lt;li&gt;Select your Apple ID, then “Manage Certificates” → click “+” → “iOS Development”.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Set Bundle Identifier&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In the Project Navigator select your main target (e.g. Runner).&lt;/li&gt;
&lt;li&gt;   Under &lt;em&gt;Signing &amp;amp; Capabilities&lt;/em&gt; → &lt;em&gt;Team&lt;/em&gt;, choose your personal Apple ID.&lt;/li&gt;
&lt;li&gt;   Change the &lt;strong&gt;Bundle Identifier&lt;/strong&gt; to something unique (e.g. &lt;code&gt;com.yourname.myapp&lt;/code&gt;).&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Connect Your iPhone&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;– Plug your iPhone into the Mac via USB (or enable wireless debugging).&lt;br&gt;
 –       In Xcode’s toolbar, select your device from the run‑destination menu.&lt;/p&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Build &amp;amp; Run&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;– Click ▶️ (Run). Xcode will automatically generate a provisioning profile, sign the app, install it on your device, and launch it.&lt;br&gt;
 – If you see a “Untrusted Developer” alert on your phone, go to &lt;strong&gt;Settings ▶️ General ▶️ VPN &amp;amp; Device Management&lt;/strong&gt; and trust your Apple ID profile.&lt;/p&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Re‑sign Weekly&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;

&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Free provisioning profiles last &lt;strong&gt;7 days&lt;/strong&gt;. After that, you need to re‑build &amp;amp; run from Xcode to renew.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;⚡Tip:&lt;/strong&gt;&lt;br&gt;
If you’re expecting to be able to tap the app icon and launch it without ever reconnecting,enable wireless debugging so Xcode can install &amp;amp; re‑sign over Wi‑Fi, without a cable each time:&lt;/p&gt;

&lt;p&gt;With your device plugged in, open &lt;strong&gt;Window&lt;/strong&gt; → &lt;strong&gt;Devices and Simulators&lt;/strong&gt; in Xcode.&lt;/p&gt;

&lt;p&gt;Select your iPhone or device in the left list, then check &lt;code&gt;Connect via network&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now you can unplug the USB cable—and as long as both Mac and iPhone are on the same Wi‑Fi, you can build &amp;amp; Run wirelessly.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Paid Apple Developer Program (₹8,400/year)
&lt;/h2&gt;

&lt;p&gt;If you want more flexibility— &lt;strong&gt;Ad‑Hoc distribution&lt;/strong&gt;, TestFlight, multiple devices, push notifications, or to share with up to 100 testers—you’ll need a paid account.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is Ad-Hoc Distribution?&lt;/strong&gt;&lt;br&gt;
Ad-Hoc distribution lets you install an app on up to 100 physical iOS devices per year using an IPA file (the iOS app package), without going through the App Store or TestFlight.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Features:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;App is signed with a special “Ad-Hoc” provisioning profile&lt;/li&gt;
&lt;li&gt;You manually specify the UDIDs (device IDs) of the devices you want to allow&lt;/li&gt;
&lt;li&gt;You export an IPA from Xcode or CI&lt;/li&gt;
&lt;li&gt;You can install the app using:

&lt;ul&gt;
&lt;li&gt;Apple Configurator (USB)&lt;/li&gt;
&lt;li&gt;OTA (Over-the-Air) tools like Diawi, Firebase App Distribution, etc.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Enroll&lt;/strong&gt;&lt;br&gt;
– Go to &lt;a href="https://developer.apple.com" rel="noopener noreferrer"&gt;https://developer.apple.com&lt;/a&gt; and sign up for the Apple Developer Program.&lt;br&gt;
– Pay the annual fee (₹8,400 in India).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Register Devices&lt;/strong&gt; (for Ad‑Hoc)&lt;br&gt;
 – In App Store Connect → Your App → &lt;em&gt;Devices&lt;/em&gt;, add each device’s UDID.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Create an App ID &amp;amp; Provisioning Profile&lt;/strong&gt;&lt;br&gt;
 – In Certificates, IDs &amp;amp; Profiles, register your App ID (bundle‑ID), and generate an Ad‑Hoc or Development provisioning profile that includes your registered devices.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Build &amp;amp; Distribute&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In Xcode, select your paid “Team” under Signing.&lt;/li&gt;
&lt;li&gt;Archive your build (&lt;strong&gt;Product ▶️ Archive&lt;/strong&gt;), then export an &lt;strong&gt;Ad‑Hoc IPA&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Distribute via:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;TestFlight&lt;/strong&gt; (easiest for multiple testers)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Direct install&lt;/strong&gt; (using tools like Apple Configurator or a simple web‑hosted OTA link)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;App Updates&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;You can push updates through TestFlight or simply rebuild &amp;amp; redistribute the IPA.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Choosing Between the Two
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Free Provisioning&lt;/th&gt;
&lt;th&gt;Paid Developer Program&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cost&lt;/td&gt;
&lt;td&gt;&amp;nbsp;Free&lt;/td&gt;
&lt;td&gt;&amp;nbsp;₹8,400/year&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Device count&lt;/td&gt;
&lt;td&gt;&amp;nbsp;1 (per bundle‑ID)&lt;/td&gt;
&lt;td&gt;&amp;nbsp;Up to 100 (Ad‑Hoc), unlimited TestFlight&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Profile expiration&lt;/td&gt;
&lt;td&gt;&amp;nbsp;7 days&lt;/td&gt;
&lt;td&gt;&amp;nbsp;1&amp;nbsp;year&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;App distribution to others&lt;/td&gt;
&lt;td&gt;&amp;nbsp;No&lt;/td&gt;
&lt;td&gt;&amp;nbsp;Yes (Ad‑Hoc, TestFlight)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Push Notifications, App Store&lt;/td&gt;
&lt;td&gt;&amp;nbsp;No&lt;/td&gt;
&lt;td&gt;&amp;nbsp;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;✅ &lt;strong&gt;When Should You Use Ad-Hoc?&lt;/strong&gt;&lt;br&gt;
Use Ad-Hoc if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You have a private app you want to install on your team’s or family’s devices&lt;/li&gt;
&lt;li&gt;You want to avoid App Store delays&lt;/li&gt;
&lt;li&gt;You want more freedom than TestFlight’s 90-day limit&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If it’s &lt;strong&gt;just for your own testing&lt;/strong&gt; and you don’t mind re‑signing weekly, the &lt;strong&gt;free path&lt;/strong&gt; is simplest. If you want reliable longer provisioning, wider distribution, or App Store/TestFlight support, go with the &lt;strong&gt;paid Developer Program&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Leave me a message if you’d like more detail on any of these steps!&lt;/p&gt;

</description>
      <category>ios</category>
      <category>mobile</category>
      <category>programming</category>
    </item>
    <item>
      <title>Securely Managing Secrets in Configuration in .NET Applications</title>
      <dc:creator>Vimal</dc:creator>
      <pubDate>Fri, 04 Jul 2025 10:18:37 +0000</pubDate>
      <link>https://dev.to/vimaltwit/securely-managing-secrets-in-configuration-in-net-applications-3nkf</link>
      <guid>https://dev.to/vimaltwit/securely-managing-secrets-in-configuration-in-net-applications-3nkf</guid>
      <description>&lt;h3&gt;
  
  
  The Problem
&lt;/h3&gt;

&lt;p&gt;Many developers make the mistake of adding connection strings to appsettings file of .Net application. This makes its way in to the repository and becomes a target of database attacks.Storing connection strings as plain text in configuration files and checking them into a repository can lead to security vulnerabilities, as sensitive information like passwords can be easily accessed by unauthorised users.&lt;/p&gt;

&lt;h3&gt;
  
  
  Possible Solution
&lt;/h3&gt;

&lt;p&gt;.Net provides a number of configuration providers for storing and reading configuration. Storing sensitive configuration items like connection strings in an environment variable is the safest way to avoid connection string or password exposure. Configuration is read from the process that the application is running in.&lt;br&gt;
This code works locally as well on Azure after deployment.&lt;/p&gt;

&lt;p&gt;In the case of Azure App Service, just need to add the configuration item and value under &lt;code&gt;Settings &amp;gt; Environment Variables&lt;/code&gt; on the App Service in Azure portal.&lt;/p&gt;



&lt;p&gt;To add a connection string to environment variables locally, follow these steps:&lt;/p&gt;
&lt;h3&gt;
  
  
  1. &lt;strong&gt;Set Environment Variable in Your Operating System&lt;/strong&gt;
&lt;/h3&gt;
&lt;h4&gt;
  
  
  On Linux or macOS:
&lt;/h4&gt;

&lt;p&gt;You can set the environment variable in your terminal session:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DBConnectionString&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Server=tcp:your-server.database.windows.net,1433;Database=your-database;User ID=your-username;Password=your-password;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To make it persistent across sessions, add the above line to your shell configuration file (e.g., &lt;code&gt;~/.bashrc&lt;/code&gt;, &lt;code&gt;~/.zshrc&lt;/code&gt;, or &lt;code&gt;~/.bash_profile&lt;/code&gt;), and then reload the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;source&lt;/span&gt; ~/.bashrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  On Windows:
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Open the &lt;strong&gt;Start Menu&lt;/strong&gt; and search for "Environment Variables."&lt;/li&gt;
&lt;li&gt;Click on &lt;strong&gt;Edit the system environment variables&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;In the &lt;strong&gt;System Properties&lt;/strong&gt; window, click &lt;strong&gt;Environment Variables&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;User variables&lt;/strong&gt; or &lt;strong&gt;System variables&lt;/strong&gt;, click &lt;strong&gt;New&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Add the following:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Variable name&lt;/strong&gt;: &lt;code&gt;DBConnectionString&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Variable value&lt;/strong&gt;: &lt;code&gt;Server=tcp:your-server.database.windows.net,1433;Database=your-database;User ID=your-username;Password=your-password;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;OK&lt;/strong&gt; to save.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  2. &lt;strong&gt;Verify the Environment Variable&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To ensure the environment variable is set correctly, you can print it in your terminal:&lt;/p&gt;

&lt;h4&gt;
  
  
  On Linux/macOS:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$DBConnectionString&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  On Windows (Command Prompt):
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo %DBConnectionString%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  On Windows (PowerShell):
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;DBConnectionString&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  3. &lt;strong&gt;Access the Environment Variable in Your Application&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;In your application, you can access the environment variable using &lt;code&gt;Environment.GetEnvironmentVariable&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;connectionString&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetEnvironmentVariable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DBConnectionString"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  4. &lt;strong&gt;Test the Configuration&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Run your application and ensure the connection string is being picked up correctly. You can log the connection string for debugging purposes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"SQL Connectionstring: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;connectionString&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Set the environment variable using your operating system's tools.&lt;/li&gt;
&lt;li&gt;Access the variable in your application using &lt;code&gt;Environment.GetEnvironmentVariable&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let me know if you need further assistance!&lt;/p&gt;

</description>
      <category>azure</category>
      <category>dotnet</category>
      <category>security</category>
    </item>
    <item>
      <title>Practical Caching in .NET: Strategies, Eviction, Keys, and Metrics</title>
      <dc:creator>Vimal</dc:creator>
      <pubDate>Sat, 21 Jun 2025 13:42:51 +0000</pubDate>
      <link>https://dev.to/vimaltwit/practical-caching-in-net-strategies-eviction-keys-and-metrics-1d53</link>
      <guid>https://dev.to/vimaltwit/practical-caching-in-net-strategies-eviction-keys-and-metrics-1d53</guid>
      <description>&lt;h2&gt;
  
  
  Key Objectives
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Understand the different caching options available in .NET.&lt;/li&gt;
&lt;li&gt;Learn about cache eviction strategies and when to use them.&lt;/li&gt;
&lt;li&gt;Discover best practices for choosing cache keys.&lt;/li&gt;
&lt;li&gt;Explore how to measure cache efficiency using instrumentation and logging.&lt;/li&gt;
&lt;li&gt;See practical code samples for real-world caching scenarios.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Why Caching Matters
&lt;/h2&gt;

&lt;p&gt;Caching is a fundamental technique for improving application performance and scalability. By storing frequently accessed data in a fast-access layer, you reduce database load, speed up response times, and can even improve reliability during transient back-end failures.&lt;/p&gt;

&lt;p&gt;Fetching data from cache saves networks calls to database, query execution time which speeds up the overall response time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fottghw3z172gja97uf53.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fottghw3z172gja97uf53.png" alt="Cache overview" width="800" height="615"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Caching Options in .NET
&lt;/h2&gt;

&lt;p&gt;.NET provides several built-in caching mechanisms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;In-Memory Cache (&lt;code&gt;IMemoryCache&lt;/code&gt;)&lt;/strong&gt;&lt;br&gt;
Stores data in the memory of the application process. Fast, but data is lost on restart and not shared across servers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Distributed Cache (&lt;code&gt;IDistributedCache&lt;/code&gt;)&lt;/strong&gt;&lt;br&gt;
Supports external cache stores like Redis or SQL Server. Data is shared across multiple app instances and survives restarts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Response Caching&lt;/strong&gt;&lt;br&gt;
Caches HTTP responses at the middleware level for web APIs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Output Caching (ASP.NET Core 7+)&lt;/strong&gt; &lt;br&gt;
Caches the output of controllers or Razor pages.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Cache Eviction Strategies
&lt;/h2&gt;

&lt;p&gt;Eviction determines when items are removed from the cache. Common strategies in .NET:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Absolute Expiration&lt;/strong&gt;
The item is removed after a fixed time, regardless of usage.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;  &lt;span class="n"&gt;_memoryCache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromMinutes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sliding Expiration&lt;/strong&gt;
The item stays in the cache as long as it is accessed within a time window.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;_memoryCache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;MemoryCacheEntryOptions&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;SlidingExpiration&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromMinutes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Manual Eviction&lt;/strong&gt;
Remove items explicitly when data changes.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;_memoryCache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Size-based Eviction&lt;/strong&gt;
Set a size limit for the cache; least recently used items are evicted when the limit is reached.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Choosing Cache Keys
&lt;/h2&gt;

&lt;p&gt;Cache keys should be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Unique: Represent the data being cached (e.g., "user_123" for user with ID 123).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Consistent: Use a predictable pattern for easy invalidation.&lt;br&gt;
Scoped: Include context if needed (e.g., "product_{id}_details").&lt;br&gt;
Example:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;cacheKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;$"employee_&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;employeeId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Measuring Cache Efficiency
&lt;/h2&gt;

&lt;p&gt;To know if your cache is effective, instrument your code to log:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cache Hits&lt;/strong&gt;: Data was found in the cache.&lt;br&gt;
&lt;strong&gt;Cache Misses&lt;/strong&gt;: Data was not found and had to be loaded.&lt;br&gt;
&lt;strong&gt;Evictions&lt;/strong&gt;: When items are removed due to expiration or manual removal.&lt;br&gt;
&lt;strong&gt;Retrieval Times&lt;/strong&gt;: Time taken to fetch from cache vs. database.&lt;br&gt;
Sample Instrumentation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;stopwatch&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Stopwatch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StartNew&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_memoryCache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryGetValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;_logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogInformation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Cache hit for {Key} at {Time}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UtcNow&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;_logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogInformation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Cache miss for {Key} at {Time}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UtcNow&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;LoadFromDatabaseAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;_memoryCache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromMinutes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;stopwatch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Stop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;_logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogInformation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Retrieval for {Key} took {Elapsed} ms"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stopwatch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ElapsedMilliseconds&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Advanced:
&lt;/h2&gt;

&lt;p&gt;For distributed caches like Redis, you can use Redis server metrics or middleware like App Metrics for more detailed analysis.&lt;/p&gt;

&lt;p&gt;Example: In-Memory Cache with Eviction and Instrumentation&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EmployeeCacheService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;IMemoryCache&lt;/span&gt; &lt;span class="n"&gt;_memoryCache&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;ILogger&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;EmployeeCacheService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_logger&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;EmployeeCacheService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IMemoryCache&lt;/span&gt; &lt;span class="n"&gt;memoryCache&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ILogger&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;EmployeeCacheService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_memoryCache&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;memoryCache&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;_logger&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Employee&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetEmployeeAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;employeeId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;$"employee_&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;employeeId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;stopwatch&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Stopwatch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StartNew&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_memoryCache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryGetValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="n"&gt;Employee&lt;/span&gt; &lt;span class="n"&gt;employee&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;_logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogInformation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Cache hit for {Key} at {Time}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UtcNow&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;_logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogInformation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Cache miss for {Key} at {Time}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UtcNow&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;employee&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;LoadEmployeeFromDb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;employeeId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;_memoryCache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;employee&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;MemoryCacheEntryOptions&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;AbsoluteExpirationRelativeToNow&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromMinutes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;});&lt;/span&gt;
            &lt;span class="n"&gt;_logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogInformation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Cache set for {Key} at {Time}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UtcNow&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;stopwatch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Stop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;_logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogInformation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Retrieval for {Key} took {Elapsed} ms"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stopwatch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ElapsedMilliseconds&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;employee&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;EvictEmployee&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;employeeId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;$"employee_&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;employeeId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;_memoryCache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;_logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogInformation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Cache evicted for {Key} at {Time}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UtcNow&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;.NET offers several caching options: in-memory, distributed (Redis, SQL), and response/output caching.&lt;/li&gt;
&lt;li&gt;Choose the right eviction strategy for your scenario: absolute, sliding, manual, or size-based.&lt;/li&gt;
&lt;li&gt;Use clear, unique cache keys for easy management and invalidation.&lt;/li&gt;
&lt;li&gt;Instrument your cache usage to measure hits, misses, evictions, and performance.&lt;/li&gt;
&lt;li&gt;Caching is a powerful tool—use it wisely to boost your app’s speed and scalability!&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;What caching strategies have worked best for your .NET projects? Share your experience in the comments!&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
