<?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>Forem: Nolan Miller</title>
    <description>The latest articles on Forem by Nolan Miller (@nmiller15).</description>
    <link>https://forem.com/nmiller15</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1504140%2F54da552b-d9e7-4eb0-8b1c-4bc9afeee9e0.jpeg</url>
      <title>Forem: Nolan Miller</title>
      <link>https://forem.com/nmiller15</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/nmiller15"/>
    <language>en</language>
    <item>
      <title>March 2026</title>
      <dc:creator>Nolan Miller</dc:creator>
      <pubDate>Wed, 01 Apr 2026 16:51:47 +0000</pubDate>
      <link>https://forem.com/nmiller15/march-2026-1kf8</link>
      <guid>https://forem.com/nmiller15/march-2026-1kf8</guid>
      <description>&lt;p&gt;Theme of the month: Endings. My wife and I sold our house in order to move and I wrapped up a big project at work so that I can tackle some accounting integrations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where My Time Went
&lt;/h2&gt;

&lt;p&gt;I finished a big lift and shift project of over 20 years of sales data between database servers. It was one of the smoother projects that I've done so far. Not &lt;em&gt;no&lt;/em&gt; bugs, but fewer! The difference was becoming obsessed with proving what I'm shipping which revealed a lot of incorrect assumptions that saved me in this project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Small Wins
&lt;/h2&gt;

&lt;p&gt;With fzf and tmux, I dramatically improved my ability to navigate my system on the command line and store windows associated with projects that I'm working on. Heavily inspired by &lt;a href="https://github.com/theprimeagen/tmux-sessionizer" rel="noopener noreferrer"&gt;tmux-sessionizer&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before some stakeholders were about to show off a feature I had worked on to the whole staff, it started hard failing. Under pressure, I was able to locate and fix the bug in about 5 minutes!&lt;/p&gt;

&lt;h2&gt;
  
  
  Worth A Read
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://simonwillison.net/2025/Dec/18/code-proven-to-work/" rel="noopener noreferrer"&gt;Your job is to deliver code you have proven to work&lt;/a&gt; — reign it in, cowboy&lt;br&gt;
&lt;a href="https://www.marginalia.nu/log/a_132_ai_bores/" rel="noopener noreferrer"&gt;AI makes you boring&lt;/a&gt; — creative ideas are born out of painful problem solving&lt;br&gt;
&lt;a href="https://www.desiringgod.org/articles/what-god-thinks-about-you" rel="noopener noreferrer"&gt;What God Thinks About You&lt;/a&gt; — a 10 year old article that I am going to return to&lt;/p&gt;

&lt;h2&gt;
  
  
  Half-Baked
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Vertical Slice Architecture is the best strategy for agentic workflows.&lt;/li&gt;
&lt;li&gt;TestContainers for integration testing gives me way more peace of mind than the three unit tests that I added in 20 minutes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Other Things
&lt;/h2&gt;

&lt;p&gt;I shot a 116 on 18 and then a 50 on 9 in back to back days. If I can keep this level of improvement up, I'll be on the tour by July.&lt;/p&gt;

&lt;p&gt;Started playing Fallout 4 finally. It turns out, I am not very good at role playing games. After about 7 hours of gameplay I found myself high-tailing it out of the castle with a .38 rifle with no armor and no ammo. I have not started farming food yet.&lt;/p&gt;

</description>
      <category>log</category>
    </item>
    <item>
      <title>Thoughts After a Year of Software Development</title>
      <dc:creator>Nolan Miller</dc:creator>
      <pubDate>Tue, 13 Jan 2026 12:41:32 +0000</pubDate>
      <link>https://forem.com/nmiller15/thoughts-after-a-year-of-software-development-ie1</link>
      <guid>https://forem.com/nmiller15/thoughts-after-a-year-of-software-development-ie1</guid>
      <description>&lt;p&gt;After teaching myself to code, I landed a job a year ago in December. In no particular order, here is an assorted collection of thoughts, opinions, and tidbits that I've accumulated over the past year. &lt;/p&gt;

&lt;h3&gt;
  
  
  Typing speed and accuracy are important
&lt;/h3&gt;

&lt;p&gt;As a junior, I do not spend "most of my time thinking." Many of the problems that I need to solve aren't very mentally taxing, they just need implemented. When I started training my typing speed and accuracy by bouncing between &lt;a href="https://keybr.com/" rel="noopener noreferrer"&gt;keybr&lt;/a&gt; and &lt;a href="https://monkeytype.com/" rel="noopener noreferrer"&gt;monkeytype&lt;/a&gt;, even repetitive "hammer-it-out" coding sessions became much more enjoyable (and shorter too). My backspace key appreciates the rest.&lt;/p&gt;

&lt;h3&gt;
  
  
  AI hype is mostly just that
&lt;/h3&gt;

&lt;p&gt;When an application is even remotely complex, or the context needed to solve an issue is of any reasonable size, AI is practically useless. No, I'm not going to type up my organization's application and server architecture so that I can argue with AI to get it to stop hallucinating. AI can make "nice" looking websites and decent interactivity. I really use it to search for Microsoft documentation... which is abysmal. AI is pretty good at that.&lt;/p&gt;

&lt;h3&gt;
  
  
  I hate Microsoft
&lt;/h3&gt;

&lt;p&gt;Windows sucks. VS sucks. (Except for the debugger, that's pretty good.)&lt;/p&gt;

&lt;h3&gt;
  
  
  Knowing how to host an app is a differentiator
&lt;/h3&gt;

&lt;p&gt;Surprisingly, there's a large portion of developers who have never stood up a production server on a bare VPS. I'm no expert, but it's really not too difficult. Maybe I just enjoy working on servers, but knowing how to host your apps outside of Netlify or Vercel is a good skill to have.&lt;/p&gt;

&lt;h3&gt;
  
  
  I'm really good at making really bad code
&lt;/h3&gt;

&lt;p&gt;Did you want to filter that list using 3 helper methods across two classes with injected services? I got you. &lt;/p&gt;

&lt;p&gt;The next day, I usually realize that this could have been done in 3 lines and everyone can magically understand what it does.&lt;/p&gt;

&lt;h3&gt;
  
  
  I'm not rich
&lt;/h3&gt;

&lt;p&gt;I make more money than I used to. But, it seems like most development jobs aren't the "f*** you" money that YouTube would have you believe. Lucky for me, I really like coding. &lt;/p&gt;

&lt;h3&gt;
  
  
  I really like developing
&lt;/h3&gt;

&lt;p&gt;I don't know if its the sound of the keyboard, the hacker aesthetic that you get from using a shell for everything, or the feeling catpuccin gives, but being a developer is really fun. &lt;/p&gt;

&lt;h3&gt;
  
  
  Shortcuts will make you feel like a god
&lt;/h3&gt;

&lt;p&gt;I have not measured whether or not it speeds me up a significant degree, but it feels very good to not have to reach for my mouse to perform really common actions. It is well worth taking the time and the initial slowdown to get system shortcuts into your fingers. Did you know that on Windows, you can open and focus applications in your taskbar by using Win + the number corresponding to it's order? Getting used to navigating your computer this way will immediately make everything feel more smooth.&lt;/p&gt;

&lt;h3&gt;
  
  
  JavaScript is the worst
&lt;/h3&gt;

&lt;p&gt;But, it's not going away. The event loop is the death of me everytime I mess with WASM in highly-interactive apps. It's evil... but, you need to know it.&lt;/p&gt;

&lt;h3&gt;
  
  
  OOP is OOK
&lt;/h3&gt;

&lt;p&gt;I work in C#, and everything is an object no matter what. For most data-heavy problems, I can usually create a pretty solid mental model with this paradigm, but sometimes it feels like I'm just trying to fit into the paradigm when all i need is a couple util functions. I don't know the number of abstractions that I've taken the time to write and then immediately deleted because it no longer makes sense.&lt;/p&gt;

&lt;h3&gt;
  
  
  Quality of life features live on the back burner
&lt;/h3&gt;

&lt;p&gt;It's really hard to convince anyone that your "it would be really nice if" idea is worth the time when there are new features and projects that other teams are depending on. At best, I've had a bit of time when I can shove it into the mix when I finish a project early unexpectedly. Instead of creating the "quality of life" ticket for later, just lump it in with the feature that you're working on. &lt;/p&gt;

&lt;h3&gt;
  
  
  Nobody knows what you do, or how long it will take
&lt;/h3&gt;

&lt;p&gt;My manager is great, has lots of industry experience, knows me and my work pretty well, and he still cannot figure out how much time it will take for me to complete something. Being a developer uniquely gives you a lot of trust and autonomy over your schedule. This is a privilege and a responsibility. Some of the best engineering work time can produce no quantifiable output. Don't take advantage of this.&lt;/p&gt;

&lt;h3&gt;
  
  
  Assume any data you don't own is toxic
&lt;/h3&gt;

&lt;p&gt;When you don't have crystal clear visibility into a data source for your application, you need to treat it like it can and will be wrong or missing every time. Use fallback values, conditional rendering, and generally assume the worst. It's probably a good idea to do this when you have the visibility too.&lt;/p&gt;

&lt;h3&gt;
  
  
  The code I actually use is short and isn't elegant
&lt;/h3&gt;

&lt;p&gt;The code I use the most are tiny scripts that I've written for myself. If they get used a lot, they can't break. If they can't break, they need to be easy to maintain. If they need to be easy to maintain, then they need to be short, and so clear a beginner could understand them. Automation doesn't save time if it's buggy and hard to understand. That said, I don't rela&lt;/p&gt;

&lt;h3&gt;
  
  
  Small problems need solved too
&lt;/h3&gt;

&lt;p&gt;When I'm trying to find the biggest and most exciting and most impactful problem to solve, I can't think of anything. But, when I open my eyes to small annoyances, I start to see them everywhere.&lt;/p&gt;

&lt;h3&gt;
  
  
  Backend is way more interesting than front end
&lt;/h3&gt;

&lt;p&gt;I wasn't counting on this to be true. A year ago, I thought that my bent towards things that are artistic would have drawn me to the front end more. But, in all the projects I've worked on, it's been far more exhilarating to solve the pivotal logical issue than it was to figure out how to show it to someone. &lt;/p&gt;

&lt;h3&gt;
  
  
  A fast/slow dev server makes a huge difference
&lt;/h3&gt;

&lt;p&gt;Have you ever worked with the Blazor dev server? Maybe I'm doing it wrong, but getting that thing to load up a large project takes &lt;em&gt;forever&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Don't repeat yourself... but don't not repeat yourself
&lt;/h3&gt;

&lt;p&gt;I've rewritten logic in a few places that has bitten me. You will always miss at least one update if you have to go to more than one place. But, in my zealousness I've created some abstractions that make absolutely no sense to work with. DRY is for information, not code. Each piece of information, or logic, should have one authoritative implementation. Don't push things together just because.&lt;/p&gt;

&lt;h3&gt;
  
  
  There's almost always a better way
&lt;/h3&gt;

&lt;p&gt;... and someone else thought of it first. You don't need to be a hero and try to come up with the most clever solution to prove you know what you're doing. Ask questions to people at your disposal. Collaboration leads to better ideas and a better team.&lt;/p&gt;

&lt;h3&gt;
  
  
  Version control everything
&lt;/h3&gt;

&lt;p&gt;Use git repos and feature branches religiously and neurotically. I can't count the number of times that I've started on a bug fix while I was in the middle of working on a small feature only to realize that I never created a new branch. Not only do I have to start over the bugfix, but often, I also broke my feature branch and have to walk backwards for a while to get it fixed.&lt;/p&gt;

&lt;h3&gt;
  
  
  That it....
&lt;/h3&gt;

&lt;p&gt;I learned a lot in year one, and I know I still have so much further to go. I've never stepped into a career that it feels like no matter how much you learn, you've only just scratched the surface. It's overwhelming. But, it's also exciting! &lt;/p&gt;

&lt;p&gt;Hopefully some of this advice is helpful to you! Hopefully you agree with some of it. Hopefully you disagree with some of it. For what it's worth, these are my thoughts. &lt;/p&gt;

&lt;p&gt;For now.&lt;/p&gt;

</description>
      <category>career</category>
      <category>discuss</category>
    </item>
    <item>
      <title>How to Build an API with Controllers</title>
      <dc:creator>Nolan Miller</dc:creator>
      <pubDate>Wed, 26 Nov 2025 20:26:31 +0000</pubDate>
      <link>https://forem.com/nmiller15/how-to-build-an-api-with-controllers-5a80</link>
      <guid>https://forem.com/nmiller15/how-to-build-an-api-with-controllers-5a80</guid>
      <description>&lt;p&gt;I starting working in ASP.NET after minimal APIs had already been released and reached popularity. My first professional project involved moving endpoints from a .NET controller-based API to the new minimal syntex. Unfortunately for me, that meant I was not going to be able to avoid the controller-based API even though I wasn't particularly comfortable with the paradigm... or C# for that matter.&lt;/p&gt;

&lt;p&gt;To save you the headache, I will walk through the very basics of creating a controller-based API and explain what I spent hours staring at code to figure out (after all, 20 hours of reading code can save you 20 minutes of reading documentation). We will create endpoints, accept parameters and document the routes all in the controller-based syntax. &lt;/p&gt;

&lt;h2&gt;
  
  
  What is a controller-based API?
&lt;/h2&gt;

&lt;p&gt;The controller-based API, is... well, an API whose endpoints are is organized with controllers, as opposed to the &lt;a href="https://nolanmiller.me/posts/intro-to-.net-apis-for-a-javascript-developer/" rel="noopener noreferrer"&gt;minimal API&lt;/a&gt;, whose endpoints are registered directly on the &lt;code&gt;WebApplication&lt;/code&gt; using extension like &lt;code&gt;MapGet&lt;/code&gt; and &lt;code&gt;MapPost&lt;/code&gt;. The pattern is actually just the MVC (model-view-controller) architecture, but with the "V" left out. Since an API doesn't typically return formatted views, it doesn't need to worry about that. But, the routing and model construction all work the same way as it would in an MVC application. Instead of a view, our controllers will return data wrapped in HTTP responses that can be used by any other application that can make HTTP requests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring an API for controllers
&lt;/h2&gt;

&lt;p&gt;That's enough background, let's get started by bootstrapping an application using the &lt;a href="https://nolanmiller.me/posts/supercharge-your-productivity-with-the-.net-cli/" rel="noopener noreferrer"&gt;&lt;code&gt;dotnet&lt;/code&gt; cli&lt;/a&gt;. In a new terminal window, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet new webapi &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"TodoApi"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once this runs, we'll have a working API, but if you'll open up &lt;code&gt;Program.cs&lt;/code&gt;, you'll notice that we already have a minimal API endpoint registered here. With a little extra work, we'll have this converted into a controller-based API.&lt;/p&gt;

&lt;p&gt;First, &lt;strong&gt;DELETE&lt;/strong&gt; the following lines of code from &lt;code&gt;Program.cs&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;summaries&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;"Freezing"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Bracing"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Chilly"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Cool"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Mild"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Warm"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Balmy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Hot"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Sweltering"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Scorching"&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;MapGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/weatherforecast"&lt;/span&gt;&lt;span class="p"&gt;,&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;forecast&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;  &lt;span class="n"&gt;Enumerable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;WeatherForecast&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;DateOnly&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromDateTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddDays&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
            &lt;span class="n"&gt;Random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Shared&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;(-&lt;/span&gt;&lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;55&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;summaries&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Shared&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;summaries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&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;ToArray&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;forecast&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;WithName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GetWeatherForecast"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// leave in app.Run();&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;summaries&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;"Freezing"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Bracing"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Chilly"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Cool"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Mild"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Warm"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Balmy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Hot"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Sweltering"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Scorching"&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;MapGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/weatherforecast"&lt;/span&gt;&lt;span class="p"&gt;,&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;forecast&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;  &lt;span class="n"&gt;Enumerable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;WeatherForecast&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;DateOnly&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromDateTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddDays&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
            &lt;span class="n"&gt;Random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Shared&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;(-&lt;/span&gt;&lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;55&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;summaries&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Shared&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;summaries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&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;ToArray&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;forecast&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;WithName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GetWeatherForecast"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;///////////////////////////&lt;/span&gt;
&lt;span class="c1"&gt;// do not delete app.Run();&lt;/span&gt;
&lt;span class="c1"&gt;///////////////////////////&lt;/span&gt;

&lt;span class="k"&gt;record&lt;/span&gt; &lt;span class="nc"&gt;WeatherForecast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DateOnly&lt;/span&gt; &lt;span class="n"&gt;Date&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;TemperatureC&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;Summary&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;TemperatureF&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;32&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;TemperatureC&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;0.5556&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, replace &lt;code&gt;var app = builder.Build()&lt;/code&gt;, with the following:&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="nf"&gt;AddControllers&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="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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This small bit of code here enables the use of controllers in our web app. With the &lt;code&gt;AddControllers()&lt;/code&gt; extension method, we're registering &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection.mvcservicecollectionextensions.addcontrollers?view=aspnetcore-9.0" rel="noopener noreferrer"&gt;all the services&lt;/a&gt; that we might need for API development in ASP.NET. Once the services are registered and the app is built, instead of manually configuring all of our endpoints, &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.builder.controllerendpointroutebuilderextensions.mapcontrollers?view=aspnetcore-9.0" rel="noopener noreferrer"&gt;&lt;code&gt;.MapControllers()&lt;/code&gt;&lt;/a&gt; goes to look at all of our Controllers and turn the action methods into route endpoints!&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating routes from actions
&lt;/h2&gt;

&lt;p&gt;Now that our &lt;code&gt;Program.cs&lt;/code&gt; file expects to search our app for controllers, we should go and make one. To support the quintessential "todo" app with our API, in the root of the project, create a folder called &lt;code&gt;Controllers&lt;/code&gt;. Inside that folder, make a new file called &lt;code&gt;TodoController.cs&lt;/code&gt; and add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.AspNetCore.Http&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.AspNetCore.Mvc&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;TodoApi.Controllers&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;"api/[controller]"&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="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TodoController&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="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;This is the controller that we will use to create endpoints for our API. This controller is just a C# class that inherits from the &lt;code&gt;ControllerBase&lt;/code&gt; class that is provided by the &lt;code&gt;Microsoft.AspNetCore.Mvc&lt;/code&gt; package. That base class gives us access to some helper methods that we will use later. We also have to include the &lt;code&gt;[ApiController]&lt;/code&gt; attribute to tell the framework that we are creating a controller.&lt;/p&gt;

&lt;p&gt;If we started our application now, the controller would be registered, but no routes would be added because we haven't added any action methods. So, let's do that right now. In order to add the endpoint, create a method on the controller that returns an &lt;code&gt;ActionResult&lt;/code&gt;. Add the following method to the &lt;code&gt;TodoController&lt;/code&gt; class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// in TodoController&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;ActionResult&lt;/span&gt; &lt;span class="nf"&gt;Health&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Healthy"&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;This is called an &lt;em&gt;action method&lt;/em&gt;. It returns a controller action using the &lt;code&gt;Ok()&lt;/code&gt; helper method provided by &lt;code&gt;ControllerBase&lt;/code&gt; which returns an &lt;code&gt;ActionResult&lt;/code&gt; that has a &lt;code&gt;200&lt;/code&gt; status code and contains the string passed to it. If we build and run our application now, we have a new endpoint! Now let's talk about where we can find it when we're trying to call the API. &lt;/p&gt;

&lt;h2&gt;
  
  
  URL Routing in Controllers
&lt;/h2&gt;

&lt;p&gt;ASP.NET does most of the routing for us when we are using controller-based syntax. If you're familiar with the MVC pattern, then you already know how this will work. Each endpoint is created using the name of the controller class, the name of the action method and optional input parameters.&lt;/p&gt;

&lt;p&gt;The action method that we just created was inside of the &lt;code&gt;TodoController&lt;/code&gt; and it's method name is &lt;code&gt;Health&lt;/code&gt;. By default, to hit this endpoint, we have to send a &lt;code&gt;GET&lt;/code&gt; request to &lt;code&gt;/Todo/Health&lt;/code&gt;. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;TodoController&lt;/code&gt; → &lt;code&gt;Todo&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ActionResult Health()&lt;/code&gt; → &lt;code&gt;Health&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Seems simple enough, but if you try this on your API now, you'll notice that you get back a &lt;code&gt;404&lt;/code&gt;. Sorry! I tricked you. &lt;/p&gt;

&lt;p&gt;This controller &lt;em&gt;isn't&lt;/em&gt; using the default routing scheme. If you've been following along with the code I've told you to put in, then you might have noticed, that we added:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;[Route("/api/[controller]")]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;... to the top of the controller.&lt;/p&gt;

&lt;p&gt;This is an attribute that we can assign to a class or action method to tell the framework what pattern we want it to use when assigning an endpoint. The pattern syntax is dead simple, it will:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;match any string that you pass literally, &lt;/li&gt;
&lt;li&gt;statically replace wildcards passed between &lt;code&gt;[]&lt;/code&gt;, and &lt;/li&gt;
&lt;li&gt;pass named parameters to action methods between &lt;code&gt;{}&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The default pattern for a controller in ASP.NET is &lt;code&gt;"/[controller]"&lt;/code&gt;, where the wildcard &lt;code&gt;controller&lt;/code&gt; is replaced by the name of the controller class with the word "Controller" stripped out.&lt;/p&gt;

&lt;p&gt;With our custom &lt;code&gt;Route&lt;/code&gt; attribute, we're using &lt;code&gt;"/api/[controller]"&lt;/code&gt;. So, to hit our controller endpoints, we would just have to use the base &lt;code&gt;/api/Todo&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We didn't add a custom &lt;code&gt;Route&lt;/code&gt; parameter to our Action method, so it will route using the default pattern &lt;code&gt;"/[action]"&lt;/code&gt;, where the wildcard &lt;code&gt;action&lt;/code&gt; will be replaced with the name of the action method. If you're following from above, that makes the full pattern for our endpoint &lt;code&gt;"/api/[controller]/[action]"&lt;/code&gt;. So, to check the health of our API, get a &lt;code&gt;GET&lt;/code&gt; request to &lt;code&gt;/api/Todo/Health&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;With the &lt;code&gt;Route&lt;/code&gt; parameter, we can change the routes to whatever we would like. Let's illustrate this by adding another endpoint to this API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api/[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;TodoController&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;public&lt;/span&gt; &lt;span class="n"&gt;ActionResult&lt;/span&gt; &lt;span class="nf"&gt;GetTodo&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;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&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;Since we didn't add a &lt;code&gt;Route&lt;/code&gt; parameter to this action method, we have inherited the default. So, to hit this endpoint in it's current state we would send a &lt;code&gt;GET&lt;/code&gt; request to &lt;code&gt;/api/Todo/GetTodo/23&lt;/code&gt;. This would return an action result that would presumably return a Todo that had the ID of 23. So, how is this 23 passed into the &lt;code&gt;id&lt;/code&gt; parameter of the action method? &lt;/p&gt;

&lt;p&gt;There is one more section of the default route pattern for ASP.NET.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/[controller]/[action]/[id]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;That means that without adding a custom attribute, we have access to an &lt;code&gt;id&lt;/code&gt; input parameter that can be submitted as a URL parameter by a user. In order to accept it all we have to do is add the parameter to the action method with the name &lt;code&gt;id&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This method seems like a good candidate for customization though. Sending a &lt;code&gt;GET&lt;/code&gt; request to an endpoint containing &lt;code&gt;GetTodo&lt;/code&gt; seems redundant and sloppy. So, let's use the &lt;code&gt;Route&lt;/code&gt; attribute to create our own pattern. While we're at it, our users likely know that they're hitting an API, and we don't have anything else hosted at this address, so we can adjust that too.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"todos"&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;TodosController&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="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;"{id}"&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;ActionResult&lt;/span&gt; &lt;span class="nf"&gt;GetTodo&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;id&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;By combining these two &lt;code&gt;Route&lt;/code&gt; attributes, we've created a new pattern: &lt;code&gt;/todos/{id}&lt;/code&gt;. To make the same request as earlier, we would send a &lt;code&gt;GET&lt;/code&gt; request to &lt;code&gt;/todos/23&lt;/code&gt;. Using &lt;code&gt;Route&lt;/code&gt;, we kept the user from having to type out the name of our implementation method, while still leaving it intact for our developer to use. I'll also note that we switched the pattern to the curly brace syntax to better identify that &lt;code&gt;id&lt;/code&gt; is a route parameter that will be passed in the action method parameter named &lt;code&gt;id&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now that we've got the request side of things figured out, let's take a look at how to handle getting information back to the user.&lt;/p&gt;

&lt;h3&gt;
  
  
  Constructing responses
&lt;/h3&gt;

&lt;p&gt;So far, all we've returned is &lt;code&gt;Ok()&lt;/code&gt;. ASP.NET also provides us  methods like &lt;code&gt;NotFound()&lt;/code&gt; and &lt;code&gt;StatusCode()&lt;/code&gt; that return different status codes. Along with these three, we have access to &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.controllerbase?view=aspnetcore-2.2#methods" rel="noopener noreferrer"&gt;a long list of helper methods&lt;/a&gt; through the &lt;code&gt;ControllerBase&lt;/code&gt; class to send responses to the user. Feel free to peruse them in your own time, but today, I'll just look at four.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Ok()&lt;/code&gt; - Returns a 200 status code. Pass any model into it as a parameter to send this back as serialized JSON.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Created()&lt;/code&gt; - Returns a 201 status code, indicating a successful model creation or update.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;NotFound()&lt;/code&gt; - Returns a 404 status code. This is useful if you have a "get one" route that is passed a failed id.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;StatusCode()&lt;/code&gt; - If you don't have time to look up the built-in method, or you find they don't have a method that satisfies your needs, you can just pass the status code as a parameter to this method to return a response with that code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's use a couple of them. Here's a &lt;code&gt;SaveTodo&lt;/code&gt; method that uses &lt;code&gt;Created&lt;/code&gt; and &lt;code&gt;NotFound&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="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;"{id}/Save"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;HttpPost&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;ProducesResponseType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;201&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;ProducesResponseType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;404&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;ActionResult&lt;/span&gt; &lt;span class="nf"&gt;SaveTodo&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;FromBody&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Todo&lt;/span&gt; &lt;span class="n"&gt;todo&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;success&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_todoService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveTodo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;todo&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;success&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Created&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;NotFound&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 example, notice the decorations. We have an &lt;code&gt;[HttpPost]&lt;/code&gt; and  two &lt;code&gt;[ProducesResponseType]&lt;/code&gt; attributes. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;SaveTodo&lt;/code&gt; method takes in a &lt;code&gt;Todo&lt;/code&gt; class instance. With what we've seen so far this wouldn't be possible without creating a horribly-long URL that took in all string parameters. Not a great interface selection. So why couldn't we pass objects with our request before? By default, action methods will represent &lt;code&gt;GET&lt;/code&gt; request endpoints. In order to pass a body to our method, we'd send a &lt;code&gt;POST&lt;/code&gt; request and our endpoint wouldn't match anymore.&lt;/p&gt;

&lt;p&gt;Luckily, making this change is as simple as including the attribute &lt;code&gt;[HttpPost]&lt;/code&gt; before the method as shown in the example.&lt;/p&gt;

&lt;p&gt;What about the &lt;code&gt;[ProducesResponseType]&lt;/code&gt; attribute, though? While not vital, it serves two purposes. If you use OpenAPI to generate your documentation, then these attributes can be used to add helpful details about your route. And even if you don't use OpenAPI, they're a way to provide some in-code documentation for future developers. In a simple method like this, that may seem silly, but as controller methods and their logic grow, it can certainly be nice to know at a glance what the success/failure results for your endpoint are.&lt;/p&gt;

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

&lt;p&gt;If you've only had exposure to the newer minimal API syntax, then I hope that this makes the controller-based API pattern a bit more approachable. As with many things in "approaching-legacy-status" .NET, it is fairly verbose to get to a working API, but in my next few posts, I'll be exploring some features that you'll need a controller-based API to take advantage of and &lt;em&gt;hopefully&lt;/em&gt; give you a reason to actually use them! &lt;/p&gt;

&lt;p&gt;Until then!&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
    </item>
    <item>
      <title>Build a Database Connection Framework In 133 Lines Of Code</title>
      <dc:creator>Nolan Miller</dc:creator>
      <pubDate>Fri, 24 Oct 2025 12:13:31 +0000</pubDate>
      <link>https://forem.com/nmiller15/build-a-database-connection-framework-in-133-lines-of-code-49cg</link>
      <guid>https://forem.com/nmiller15/build-a-database-connection-framework-in-133-lines-of-code-49cg</guid>
      <description>&lt;p&gt;Entity Framework is a popular database connection choice for .NET developers. It's fairly simple to use but, what if I told you that we could create a connection framework on top of ASP.NET that would allow us to get total control of the SQL that we write? The cherry on top is that it will take about as much code as it takes to configure Entity Framework.&lt;/p&gt;

&lt;p&gt;In this article, I'll show you how to connect an ASP.NET minimal API to a local SQLite database Entity Framework. We will still map tables into classes allowing us to interact with our data in C#. I'll include every line of code you need, so let's get started.&lt;/p&gt;

&lt;h2&gt;
  
  
  The data
&lt;/h2&gt;

&lt;p&gt;First, we have to do is set up a database. I decided to use SQLite since I've never had an excuse to before. Make sure that you have SQLite installed and that you've connected to a database. (You could also connect to a MySQL, SQL Server or Postgres database using the following method too, but this article will focus on SQLite.)&lt;/p&gt;

&lt;p&gt;With our database, we'll track student information and grades. First, connect to SQLite and create a database, we'll call it &lt;code&gt;Students.db&lt;/code&gt;, then create a &lt;code&gt;students&lt;/code&gt; table and a &lt;code&gt;grades&lt;/code&gt; table.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sqlite3 Students.db
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;sqlite&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;students&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;        &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;INTEGER&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;        &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;        &lt;span class="n"&gt;school&lt;/span&gt; &lt;span class="nb"&gt;TEXT&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="n"&gt;sqlite&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;grades&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;        &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;INTEGER&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;        &lt;span class="n"&gt;scored&lt;/span&gt; &lt;span class="nb"&gt;INTEGER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;        &lt;span class="n"&gt;out_of&lt;/span&gt; &lt;span class="nb"&gt;INTEGER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;        &lt;span class="n"&gt;student_id&lt;/span&gt; &lt;span class="nb"&gt;INTEGER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;        &lt;span class="k"&gt;FOREIGN&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;student_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;REFERENCES&lt;/span&gt; &lt;span class="n"&gt;students&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Drop these two table definitions into ChatGPT and have it script you out some sample data for both of the tables. This isn't necessary, but it will make your API more interesting to work with once we're done. Once you've done that, we're ready to get started.&lt;/p&gt;

&lt;h2&gt;
  
  
  The connection
&lt;/h2&gt;

&lt;p&gt;Instead of using Entity Framework, we'll remove that layer of abstraction to use ADO.NET. These are the libraries that EF uses in its implementation. Microsoft was kind enough to wrap them up in a NuGet package for us. In the root of your project, run the following command:&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.Data.Sqlite
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that installed, we can work on getting our application connected to the database. First, grab your connection string. Each database provider has their own format for these, but I'll trust that you can find that and configure it on your own. Sqlite's format is below:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;"Data Source=path/to/database_file.db"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The best way to give your application access to this is through a configuration object that you supply through dependency injection. I wrote &lt;a href="https://nolanmiller.me/posts/learn-application-configuration-in-asp.net/" rel="noopener noreferrer"&gt;an article&lt;/a&gt; about how to get that set up if you need help. Or you can decide to be a lawless cowboy and hard-code it... I'm not your mother.&lt;/p&gt;

&lt;p&gt;It's finally time to write some code. In order to interact with our database, we need a class and a matching interface that will provide the connection to the rest of our application. We will call it, somewhat unimaginatively, &lt;code&gt;DatabaseConnectionProvider&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="c1"&gt;// DatabaseConnectionProvider.cs&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Data.Sqlite&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;Students.Repository.SQL&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;DatabaseConnectionProvider&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IDatabaseConnectionProvider&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="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;_connectionString&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;DatabaseConnectionProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IConfiguration&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Don't you hard code it, cowboy...&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;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"ConnectionString"&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;_connectionString&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;InvalidOperationException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Connection string not found."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since we'll be injecting this provider into other classes later, we'll create an interface and include a preview of the first method that we will create!&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="c1"&gt;// IDatabaseConnectionProvider.cs&lt;/span&gt;
&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Students.Abstractions&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;IDatabaseConnectionProvider&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;GetRecords&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;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 back in our provider class, create the database connection inside this &lt;code&gt;GetRecords&lt;/code&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// DatabaseConnectionProvider.cs &lt;/span&gt;
&lt;span class="c1"&gt;// after DatabaseConnectionProvider(IConfigration)&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetRecords&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="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;connection&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;SqliteConnection&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="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Open&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;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateCommand&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CommandText&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"SELECT * FROM students;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ExecuteReader&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Read&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;reader&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;SqliteConnection&lt;/code&gt; class is provided to us by that NuGet package that we installed earlier. This gives us the building blocks of database interaction: connection, issuing commands, and reading the results.&lt;/p&gt;

&lt;p&gt;This isn't our final &lt;code&gt;GetRecords&lt;/code&gt; implementation, but it &lt;em&gt;will&lt;/em&gt; work and you can test that (if you seeded some sample values into your database). When you run it, the method creates Sqlite database connection and issues a &lt;code&gt;SELECT *&lt;/code&gt; command to return all the students. We get back a &lt;code&gt;DataReader&lt;/code&gt;, also provided by the NuGet package from earlier, that we can use to read the &lt;code&gt;"name"&lt;/code&gt; column of each row before disposing the connection. &lt;/p&gt;

&lt;p&gt;We're connected! Take a moment to &lt;a href="https://giphy.com/gifs/animation-portal-the-cake-is-a-lie-3oEduOEWGS68758rXq" rel="noopener noreferrer"&gt;celebrate&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The models
&lt;/h2&gt;

&lt;p&gt;Now that we can get the data out of the database, we have a bit of grunt work to do in order to be able to work with it. For each of our database tables that creates a record we want to use in our code, we need to create a model in C# using a class.&lt;/p&gt;

&lt;p&gt;In this small sample project, we just need two.&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="c1"&gt;// Student.cs&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;Student&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Id&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="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="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;School&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;span class="c1"&gt;// Grade.cs&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;Grade&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Id&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="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Scored&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="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;OutOf&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="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;StudentId&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One of these models represents a single row in a table. Right now, they are sad and empty. Okay, maybe not sad, but definitely empty. But, now we have a problem. How do we get a &lt;code&gt;DataReader&lt;/code&gt; to spit out these models that we just created?&lt;/p&gt;

&lt;p&gt;Once we get into our read loop, we could access all of the columns by name and manually assign them to the model properties. That would work, but we would have to rename our method to &lt;code&gt;GetStudentRecords&lt;/code&gt;, since attempting to query for grades would throw an exception when looking for the &lt;code&gt;"name"&lt;/code&gt; or the &lt;code&gt;"school"&lt;/code&gt; columns.&lt;/p&gt;

&lt;p&gt;Well, then we could create a new &lt;code&gt;GetGradeRecords&lt;/code&gt;, but then, of course, we would be rewriting all of the logic inside our original method except for where we construct and return a model.&lt;/p&gt;

&lt;p&gt;Instead, we need to offload the parsing responsibility from our &lt;code&gt;DatabaseConnectionProvider&lt;/code&gt;. Instead of making our provider responsible for reading data, we can make each model responsible for knowing how to construct itself by giving each one &lt;code&gt;Parse&lt;/code&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// In Student.cs &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;School&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="n"&gt;Student&lt;/span&gt; &lt;span class="nf"&gt;Parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IDataReader&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ParseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ParseString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;School&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ParseString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"school"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&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="c1"&gt;// In Grade.cs&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;StudentId&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="n"&gt;Grade&lt;/span&gt; &lt;span class="nf"&gt;Parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IDataReader&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ParseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;Scored&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ParseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"scored"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;OutOf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ParseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"out_of"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;StudentId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ParseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"student_id"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&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;If you're typing along, you probably noticed that &lt;code&gt;ParseInt&lt;/code&gt; and &lt;code&gt;ParseString&lt;/code&gt; are red. In order to clean up the syntax a bit, I added a couple static extensions methods on the &lt;code&gt;DataReader&lt;/code&gt; class. You can add those in a new file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Data&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;Students.Repository.SQL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ReaderExtensions&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;ParseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;IDataReader&lt;/span&gt; &lt;span class="n"&gt;reader&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;columnName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetInt32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetOrdinal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;columnName&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;ParseString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;IDataReader&lt;/span&gt; &lt;span class="n"&gt;reader&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;columnName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetOrdinal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;columnName&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;Now all we have to do is let the &lt;code&gt;DatabaseConnectionProvider&lt;/code&gt; know that our models have this parse method. We will do this with generics, but we are also going to need to define an interface to expose this method generically...&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="c1"&gt;// ISqlDataParser.cs&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Data&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;Students.Abstractions&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;ISqlDataParser&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&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;T&lt;/span&gt; &lt;span class="nf"&gt;Parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IDataReader&lt;/span&gt; &lt;span class="n"&gt;reader&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;... and make sure that our models are inheriting it.&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="c1"&gt;// Student.cs&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;Student&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ISqlDataParser&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Student&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="c1"&gt;// Grade.cs&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;Grade&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ISqlDataParser&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Grade&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's update our &lt;code&gt;GetRecords&lt;/code&gt; declaration to finish making our &lt;code&gt;Parse&lt;/code&gt; methods available.&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="c1"&gt;// In DatabaseConnectionProvider&lt;/span&gt;
&lt;span class="c1"&gt;// Replace public List&amp;lt;T&amp;gt; GetRecords()&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetRecords&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ISqlDataParser&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What this says, is that we can only call &lt;code&gt;GetRecords&amp;lt;T&amp;gt;&lt;/code&gt; if the type that we insert for &lt;code&gt;T&lt;/code&gt; implements the &lt;code&gt;ISqlDataParser&lt;/code&gt; interface and has a parameter-less constructor.&lt;/p&gt;

&lt;p&gt;Now that we can safely access &lt;code&gt;Parse&lt;/code&gt; we can use it in &lt;code&gt;GetRecords&amp;lt;T&amp;gt;&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="c1"&gt;// In DatabaseConnectionProvider.cs&lt;/span&gt;
&lt;span class="c1"&gt;// In GetRecords&amp;lt;T&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;// Replace everything after:  var reader = command.ExecuteReader();&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;returnList&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
        &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ExecuteReader&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Read&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;returnList&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="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;T&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;Parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Close&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;returnList&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;
  
  
  The query
&lt;/h2&gt;

&lt;p&gt;Right now, we're in an interesting state. The &lt;code&gt;GetRecords&lt;/code&gt; method is &lt;em&gt;able&lt;/em&gt; to parse theoretically infinite data types, but it never will. Why? Because we've hard-coded a query into the command object that we're sending to the database.&lt;/p&gt;

&lt;p&gt;Similar to what we did with the &lt;code&gt;Parse&lt;/code&gt; method, we need to take away the &lt;code&gt;DatabaseConnectionProvider&lt;/code&gt;'s responsibility to choose the query it should run. That means that we're going to have to move the query up into a parameter, but, we run into a problem there.&lt;/p&gt;

&lt;p&gt;If only add a &lt;code&gt;string&lt;/code&gt; parameter to the method, but then we don't have access to the &lt;code&gt;Command&lt;/code&gt; object. &lt;/p&gt;

&lt;p&gt;So what?&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Command&lt;/code&gt; object is where we add &lt;code&gt;SqlParameters&lt;/code&gt;. The only option that we would have at this point would be to use string interpolation to add the values in manually. Forcing users of our provider to build queries this way is not only poor etiquette, it is also a potential security vulnerability. Microsoft has already (hopefully), done a lot of work to secure this &lt;code&gt;Command&lt;/code&gt; object against SQL injection attacks. No matter the sanitation that we do, adding the parameters to the correct property on the &lt;code&gt;Command&lt;/code&gt; object is the smartest way forward. &lt;/p&gt;

&lt;p&gt;In order to keep our provider's methods modular, we need to abstract this into a class that could be used in conjunction with any model that we create. It will wrap up our intended query with placeholders for parameter values, and a dictionary of our parameters. We'll call it &lt;code&gt;DataCallSettings&lt;/code&gt; (naming is hard).&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="c1"&gt;// DataCallSettings.cs&lt;/span&gt;
&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Students.Models&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;DataCallSettings&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;SqlCommand&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="n"&gt;Dictionary&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;object&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Parameters&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="k"&gt;new&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;DataCallSettings&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;command&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;SqlCommand&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;command&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;AddParameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;object&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;Parameters&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This class is now the only parameter to &lt;code&gt;GetRecords&amp;lt;T&amp;gt;&lt;/code&gt;. This is a significantly better developer experience than passing in positional parameters. This is a simple implementation, but if we ever decided to extend it to include support for stored procedures, retry logic, transactions or caching, we can do that without breaking our existing codebase.&lt;/p&gt;

&lt;p&gt;Take a look at the finished method with all of the changes that we made.&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="c1"&gt;// In DatabaseConnectionProvider.cs&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;GetRecords&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;DataCallSettings&lt;/span&gt; &lt;span class="n"&gt;dcs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ISqlDataParser&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="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="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;connection&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;SqliteConnection&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="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Open&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;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateCommand&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CommandText&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dcs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SqlCommand&lt;/span&gt;&lt;span class="p"&gt;;&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;key&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;dcs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Parameters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Keys&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Parameters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddWithValue&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;dcs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Parameters&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="p"&gt;}&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;returnList&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
        &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ExecuteReader&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Read&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;returnList&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="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;T&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;Parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Close&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;returnList&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;As a bonus, I'll also give you two lines of code that will let us get single records using all the hard work we did earlier.&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="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;GetRecord&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;DataCallSettings&lt;/span&gt; &lt;span class="n"&gt;dcs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ISqlDataParser&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;GetRecords&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;dcs&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;FirstOrDefault&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The command
&lt;/h2&gt;

&lt;p&gt;Sometimes you will want to issue a query to the database that won't return anything. So, our database interface isn't quite complete. We need to build a method that allows us to send database queries without creating an empty model at the end. It will look very similar to our &lt;code&gt;GetRecords&lt;/code&gt; method, but we will use the &lt;code&gt;.ExecuteNonQuery()&lt;/code&gt; method instead, and we'll call it &lt;code&gt;Execute&lt;/code&gt;. &lt;em&gt;Creative... I know.&lt;/em&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="c1"&gt;// In DatabaseConnectionProvider.cs&lt;/span&gt;
&lt;span class="c1"&gt;// After GetRecord&amp;lt;T&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;Execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DataCallSettings&lt;/span&gt; &lt;span class="n"&gt;dcs&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="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;connection&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;SqliteConnection&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="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Open&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;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateCommand&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CommandText&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dcs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SqlCommand&lt;/span&gt;&lt;span class="p"&gt;;&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;key&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;dcs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Parameters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Keys&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Parameters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddWithValue&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;dcs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Parameters&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="p"&gt;}&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ExecuteNonQuery&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Close&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;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is fine, but we're duplicating some logic between &lt;code&gt;GetRecords&lt;/code&gt; and &lt;code&gt;Execute&lt;/code&gt;. Let's lift it into a fancy new &lt;code&gt;BuildCommand&lt;/code&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// In DatabaseConnectionProvider.cs&lt;/span&gt;
&lt;span class="c1"&gt;// After Execute()&lt;/span&gt;

&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;SqliteCommand&lt;/span&gt; &lt;span class="nf"&gt;BuildCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DataCallSettings&lt;/span&gt; &lt;span class="n"&gt;dcs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SqliteConnection&lt;/span&gt; &lt;span class="n"&gt;connection&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;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateCommand&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CommandText&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dcs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SqlCommand&lt;/span&gt;&lt;span class="p"&gt;;&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;key&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;dcs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Parameters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Keys&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Parameters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddWithValue&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;dcs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Parameters&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="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;command&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;And refactor both methods to use it.&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="c1"&gt;// In DatabaseConnectionProvider.cs&lt;/span&gt;

&lt;span class="c1"&gt;// In GetRecords&amp;lt;T&amp;gt;&lt;/span&gt;
    &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Open&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;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;BuildCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dcs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;connection&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;returnList&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// In Execute()&lt;/span&gt;
    &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Open&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;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;BuildCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dcs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ExecuteNonQuery&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ah, much better. But, we're not done yet. Let's add one more method that we will wind up using a lot in practice. When we perform an INSERT, the database will set the identity column, so let's make sure that we get that back out.&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="c1"&gt;// In DatabaseConnectionProvider.cs&lt;/span&gt;
&lt;span class="c1"&gt;// Below Execute()&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;ExecuteWithIdentity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DataCallSettings&lt;/span&gt; &lt;span class="n"&gt;dcs&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;dcs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SqlCommand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StartsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"INSERT"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;InvalidOperationException&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="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;connection&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;SqliteConnection&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="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;dcs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SqlCommand&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;dcs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SqlCommand&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; SELECT last_insert_rowid();"&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;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;BuildCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dcs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;connection&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;identity&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Convert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToInt32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ExecuteScalar&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Close&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;identity&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;And with that... drumroll please.&lt;/p&gt;

&lt;p&gt;We've done it! We've created, by hand, an way to interact with a database that is extensible and easy to use.&lt;/p&gt;

&lt;h2&gt;
  
  
  The repository
&lt;/h2&gt;

&lt;p&gt;Now that we're done creating this database interface, I want to quickly walk through how you can use it. One design pattern that I use daily is the repository design pattern. This is a fancy (and admittedly somewhat confusing) name that we can give to a file that wraps up our data transfer logic, keeping our modules less coupled.&lt;/p&gt;

&lt;p&gt;Adding a separate layer allows us to ignore the database's implementation details when we finally want to send this data to a front end somewhere. So, let's create a &lt;code&gt;StudentsRepository&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="c1"&gt;// StudentsRepository.cs&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Students.Abstractions&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;Students.Models&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;Students.Repository.SQL&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;StudentsRepository&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IStudentsRepository&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;And here's the interface, complete with the methods that we're going to create.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Students.Models&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;Students.Abstractions&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;IStudentsRepository&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Student&lt;/span&gt; &lt;span class="nf"&gt;GetStudent&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;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Student&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetStudents&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;SaveStudent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Student&lt;/span&gt; &lt;span class="n"&gt;student&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;DeleteStudent&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;id&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;Then, back in our repository, we will inject our &lt;code&gt;DatabaseConnectionProvider&lt;/code&gt;. Make sure that it's registered in your &lt;code&gt;Program.cs&lt;/code&gt; file first though. Here's &lt;a href="https://nolanmiller.me/posts/what-is-dependency-injection/" rel="noopener noreferrer"&gt;an article&lt;/a&gt; that walks through DI in ASP.NET if you need some help with that. &lt;/p&gt;

&lt;p&gt;Finishing the implementation now is as simple as calling the appropriate provider method with a &lt;code&gt;DataCallSettings&lt;/code&gt; instance with a SQL query. Instead of walking through step by step, I'll just include the whole file below, so that you can see how it will look.&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="c1"&gt;// in StudentsRepository.cs&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;StudentsRepository&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IStudentsRepository&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;IDatabaseConnectionProvider&lt;/span&gt; &lt;span class="n"&gt;_provider&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nf"&gt;StudentsRepository&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IDatabaseConnectionProvider&lt;/span&gt; &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_provider&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;provider&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="n"&gt;Student&lt;/span&gt; &lt;span class="nf"&gt;GetStudent&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;id&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;dcs&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;DataCallSettings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SELECT * FROM students WHERE Id = @Id;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;dcs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddParameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&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;_provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetRecord&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Student&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;dcs&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="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Student&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetStudents&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;dcs&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;DataCallSettings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SELECT * FROM students;"&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;_provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetRecords&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Student&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;dcs&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;SaveStudent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Student&lt;/span&gt; &lt;span class="n"&gt;student&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;student&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="c1"&gt;// new student&lt;/span&gt;
            &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nf"&gt;InsertStudent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;student&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;UpdateStudent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;student&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;InsertStudent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Student&lt;/span&gt; &lt;span class="n"&gt;student&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;dcs&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;DataCallSettings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"INSERT INTO students (name, school) VALUES (@Name, @School);"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;AddStudentParameters&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dcs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;student&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;_provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ExecuteWithIdentity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dcs&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;UpdateStudent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Student&lt;/span&gt; &lt;span class="n"&gt;student&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;dcs&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;DataCallSettings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"UPDATE students SET name = @Name, school = @School WHERE id = @Id;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;dcs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddParameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;student&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;AddStudentParameters&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dcs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;student&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;_provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dcs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
            &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;student&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;
            &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;DeleteStudent&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;id&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;dcs&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;DataCallSettings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DELETE FROM students WHERE id = @Id"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;dcs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddParameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&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;_provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dcs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&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;void&lt;/span&gt; &lt;span class="nf"&gt;AddStudentParameters&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DataCallSettings&lt;/span&gt; &lt;span class="n"&gt;dcs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Student&lt;/span&gt; &lt;span class="n"&gt;student&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;student&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsNew&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;dcs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddParameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;student&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;dcs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddParameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;student&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;dcs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddParameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"School"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;student&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;School&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;
  
  
  The conclusion
&lt;/h2&gt;

&lt;p&gt;Okay, I'll admit that this more code than you probably need if you were using Entity Framework. But... it's not &lt;em&gt;that&lt;/em&gt; much more. I find myself far more comfortable working in an application that has this level of transparency and flexibility than one that does mapping magic. To me, this is an easy trade-off. &lt;/p&gt;

&lt;p&gt;This implementation isn't clever, it's not complicated, and it's easy to work with, even if it takes a little bit of getting used to. Over the past two years I've been programming, a significant percentage of bugs I deal with are caused by data being malformed. Maybe this is skill issues, but it has made me slightly paranoid about data handling in apps that I work on. &lt;/p&gt;

&lt;p&gt;Using this pattern, it's being handled completely by me. If there's a problem, I know that it was something I wrote (read: something I can fix). I created the database, I wrote the SQL queries. Since I am responsible for this system, I want to know how it's handling my data.&lt;/p&gt;

&lt;p&gt;This isn't to say that ORMs are bad. I might not be very good at working with them (see my reference to skill issues above). But, if you've never tried to use ADO.NET, I hope you feel that you have the tools to get started.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>database</category>
      <category>webdev</category>
      <category>learning</category>
    </item>
    <item>
      <title>The Perfect Programming Environment</title>
      <dc:creator>Nolan Miller</dc:creator>
      <pubDate>Fri, 15 Aug 2025 13:43:24 +0000</pubDate>
      <link>https://forem.com/nmiller15/the-perfect-programming-environment-17co</link>
      <guid>https://forem.com/nmiller15/the-perfect-programming-environment-17co</guid>
      <description>&lt;p&gt;I often encounter programming terms and lingo that goes way over my head when I'm browsing software engineering content on the internet. I wish that I could say that I drop everything and search these terms as soon as I see them, but this is rarely the case. But, this article is about a time that I took my medicine and not only looked up something I didn't understand, but implemented it into my daily workflow. &lt;/p&gt;

&lt;p&gt;The term? —&lt;em&gt;dotfiles&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Centralized and Modular Configurations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What are dotfiles?
&lt;/h3&gt;

&lt;p&gt;Maybe you're more hip than I was, but if you're not, let me fill you in. &lt;em&gt;Dotfile&lt;/em&gt; is technical shorthand for a hidden file on your system that provides configuration settings to your operating system, shell, or applications. Most systems' preferred method of hiding files s to add a &lt;code&gt;.&lt;/code&gt; at the beginning of the file—hence, &lt;em&gt;dotfile&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;Many developers choose to alter these files to exert a level of god-like control over their own computers (i.e. to change the color of their terminal prompt... ). Having these files spread across the computer can make them difficult to update and maintain, so it's convenient to package them together into a personal &lt;em&gt;dotfiles&lt;/em&gt; git repository.&lt;/p&gt;

&lt;p&gt;Alright, you're filled in, and I'll admit that on the face of it, dotfiles sound pretty boring. I expected this project to fulfill my neurotic need to organize, but in the end, I found that it presented interesting challenges to solve, and that this project represents the only project that I've built that I use &lt;em&gt;daily&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why I created my own dotfiles
&lt;/h3&gt;

&lt;p&gt;I hesitate to write this, but Pewdiepie (yes, the Fortnite streamer) was actually the first inspiration for this project. After &lt;a href="https://www.youtube.com/watch?v=pVI_smLgTY0" rel="noopener noreferrer"&gt;watching him install Arch&lt;/a&gt;, I went down a rabbit hole of customization possibilities for my own devices. &lt;/p&gt;

&lt;p&gt;The discovery of this video coincided pretty closely with the beginning of my transition to Neovim (by the way). Neovim's configurations are all stored in text files, text files that are notoriously easy to break and hard to recover if you've made too many changes at once. It's a good idea to keep these tracked in a git repository, and to change them intentionally so that you can run &lt;code&gt;git reset HEAD --hard&lt;/code&gt; when the worst happens.&lt;/p&gt;

&lt;p&gt;I am not an Arch Linux user quite yet, but my current OS's were another motivation. I work on Windows and do personal development on Mac. If I want to make a change to my dev environment, I'm adjusting it in two places. Not all of the applications that I use are cross platform, but I still like to keep as much of the workflow the same as I can. This means that I wind up translating keyboard shortcuts and other configurations from one DSL to another. This is much easier, when everything is centralized. &lt;/p&gt;

&lt;p&gt;Writing my own version-controlled and modular dotfiles repository solves all of these problems. But, I'd be lying if I said that the primary reason wasn't just that I like to tinker, and this may be one of the most fun ways to explore your operating system.&lt;/p&gt;

&lt;h3&gt;
  
  
  Making it your own
&lt;/h3&gt;

&lt;p&gt;In 2010, developer and startup advisor, Zach Holman, wrote a piece called &lt;a href="https://zachholman.com/2010/08/dotfiles-are-meant-to-be-forked/" rel="noopener noreferrer"&gt;Dotfiles Are Meant To Be Forked&lt;/a&gt;, where he argues that some of the best developers have horribly disorganized configurations, and that a dotfiles repo should be well designed, personalized and extensible. He ends the article with an encouragement to get started:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;So, &lt;a href="https://github.com/holman/dotfiles" rel="noopener noreferrer"&gt;fork it&lt;/a&gt;. Or, if not mine, then fork some of the awesome other projects I mentioned. Or come up with your own way of organizing your stuff and share it. Everyone’s got their own way of streamlining their system, and sharing dotfiles helps everyone.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I would only alter this advice slightly. If you haven't created your own dotfiles repository before, start from scratch. Before going to see what other people have done, find out what problems &lt;em&gt;you&lt;/em&gt; are trying to solve for &lt;em&gt;your&lt;/em&gt; workflow. Once you've done this, digging into someone else's configurations can give you inspiration for things to change. But, I've found that adding configurations from others has led to creating features that I never use, and a more difficult to maintain repository that is cluttered with unnecessary configurations.&lt;/p&gt;

&lt;p&gt;This might sound strange coming from a blogger who is about to tell you about his own dotfiles. My goal with this article is not to show you every inch of my configuration. In fact, I won't discuss most of the configurations at all. Rather, I want to give you a skeleton that will get your own repository &lt;em&gt;working&lt;/em&gt;. The questions that I will answer today are: "How do I centralize my config files?" and "How can I make them modular?"&lt;/p&gt;

&lt;p&gt;I'm hoping that removing this barrier makes it easier for you to joyfully discover your preferences, your operating system, and new tools and applications shared by the community.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building Dotfiles
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Centralizing configurations
&lt;/h3&gt;

&lt;p&gt;The first problem to solve when creating a dotfiles repo is getting all of your configurations into one directory without breaking all of the software and firmware that read from them. These files are typically located in a few different locations on your computer. That means the configurations aren't portable or easily maintainable. To solve this we need a way to tell our computer where to look for our configuration files.&lt;/p&gt;

&lt;p&gt;Luckily, the solution for this is built into your operating system. It's called symbolic linking or symlinking. &lt;/p&gt;

&lt;p&gt;When we boot up, say, Neovim (by the way), the application tries to set its configuration by looking for files. By default, it goes to my user directory for this path &lt;code&gt;~/.config/nvim&lt;/code&gt;. We could just put the configuration files there, &lt;em&gt;or&lt;/em&gt; we could put a symlink there that basically says, "This file that you're looking for is over there." The computer will redirect to the linked file or files and read them as if they are in the location of the symlink. &lt;/p&gt;

&lt;p&gt;Let's take another example, a &lt;code&gt;.zshrc&lt;/code&gt; file that contains some customizations on my terminal prompt. For my terminal to read this file, it has to be in my user directory. If I want to keep this file in my dotfiles repo I'll create a symlink at &lt;code&gt;~/.zshrc&lt;/code&gt; that points to &lt;code&gt;/Projects/dotfiles/.zshrc&lt;/code&gt;. Now when the computer goes to &lt;code&gt;~/.zshrc&lt;/code&gt; it's invisibly redirected to the file at &lt;code&gt;/Projects/dotfiles/.zshrc&lt;/code&gt;. My terminal can read its configurations and I get to keep them in a tidy folder with all my other configurations.&lt;/p&gt;

&lt;p&gt;Implementing a link in a unix-based environment is as simple as running the command:&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;ln&lt;/span&gt; &lt;span class="nt"&gt;-sf&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;source&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;link&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;... where source is the file in your dotfiles and link is the location that you want to put the link.&lt;/p&gt;

&lt;p&gt;The following script will allow you to quickly add source/link pairs.&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="c"&gt;# Create an associative array for source/target pairs&lt;/span&gt;
&lt;span class="nb"&gt;typeset&lt;/span&gt; &lt;span class="nt"&gt;-A&lt;/span&gt; links
&lt;span class="nv"&gt;links&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$DOTFILES&lt;/span&gt;&lt;span class="s2"&gt;/mac/.zshrc"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.zshrc"&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$DOTFILES&lt;/span&gt;&lt;span class="s2"&gt;/mac/.zprofile"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.zprofile"&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$DOTFILES&lt;/span&gt;&lt;span class="s2"&gt;/mac/.zshenv"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.zshenv"&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$DOTFILES&lt;/span&gt;&lt;span class="s2"&gt;/shared/nvim"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.config"&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Loop through each key in the associative array&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="nb"&gt;source &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;(@k)links&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;&lt;span class="nb"&gt;link&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;links&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$source&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nv"&gt;backup&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$link&lt;/span&gt;&lt;span class="s2"&gt;.backup"&lt;/span&gt;

  &lt;span class="c"&gt;# Check if the link target or [target].backup exists&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$link&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$backup&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
      if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$link&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
        &lt;span class="c"&gt;# Backup any existing configuration files (just in case)&lt;/span&gt;
        &lt;span class="nb"&gt;mv&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$link&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$backup&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Backed up: &lt;/span&gt;&lt;span class="nv"&gt;$backup&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
      &lt;span class="k"&gt;fi
  fi&lt;/span&gt;

  &lt;span class="c"&gt;# This section handles making sure that parent directories exist&lt;/span&gt;
  &lt;span class="c"&gt;#&lt;/span&gt;
  &lt;span class="c"&gt;# Checking if the source is a directory and the&lt;/span&gt;
  &lt;span class="c"&gt;# target doesn't exist&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$source&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$link&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
      &lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$link&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="c"&gt;# We need to split the file name off of the path to &lt;/span&gt;
      &lt;span class="c"&gt;# create all the parent directories.&lt;/span&gt;
      &lt;span class="nv"&gt;parent_dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;link&lt;/span&gt;:h&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
      &lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$parent_dir&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;fi&lt;/span&gt; 

  &lt;span class="c"&gt;# Create the link&lt;/span&gt;
  &lt;span class="nb"&gt;ln&lt;/span&gt; &lt;span class="nt"&gt;-sf&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$source&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$link&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$source&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
      &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Linked &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;source&lt;/span&gt;:t&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; directory to &lt;/span&gt;&lt;span class="nv"&gt;$link&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;else
      &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Linked &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;source&lt;/span&gt;:t&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; to &lt;/span&gt;&lt;span class="nv"&gt;$link&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;fi
done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you need to centralize more files, and create more links, they can quickly be added to the &lt;code&gt;links&lt;/code&gt; array at the top, and the links will automatically be created. As I encounter more configurations across my system that I'd like to change, it's very simple to add them here, link them, and run the script. The friction to making changes now is pretty much gone. &lt;/p&gt;

&lt;h3&gt;
  
  
  Making them modular
&lt;/h3&gt;

&lt;p&gt;While having everything in one place makes things easier to maintain, if the files get unmanageably long, then that friction comes back. So, combining related configurations into well-named files is a must. I'll focus here on two methods to modularize your configuration files, one for language-based configurations and one for plaintext configurations.&lt;/p&gt;

&lt;p&gt;If you're interested in the structure that I use to modularize the configurations of my different operating systems, check out the &lt;a href="https://github.com/nmiller15/dotfiles" rel="noopener noreferrer"&gt;repository&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Scripting-Language Configurations
&lt;/h4&gt;

&lt;p&gt;When splitting up configurations into multiple files, it's important to know the configuration language of the application. Sometimes, this is a Turing-complete language like Bash or Lua, but other times its a domain specific language (DSL) that can only be used with that piece of software.&lt;/p&gt;

&lt;p&gt;When we scripting languages, the way that we make things modular is a bit more straightforward. Let's look at my &lt;code&gt;.zshrc&lt;/code&gt; for example. I want to customize my prompt, add some functions and keep aliases as shortcuts to different locations on my drive. Since, the &lt;code&gt;.zshrc&lt;/code&gt; is written in Zsh (very similar to Bash), I can organize my configurations into separate files like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotfiles/
├── shell/
|   ├── aliases.sh
|   ├── functions.sh
|   └── prompt.sh
├── .zshrc
└── bootstrap.zsh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My shell is still going to look for a &lt;code&gt;.zshrc&lt;/code&gt; file, not our modules. Instead of jamming all of our configurations in the file, we will tell it to look for our dotfiles repository and loop through the &lt;code&gt;shell&lt;/code&gt; subdirector and source every readable file that ends in &lt;code&gt;.sh&lt;/code&gt;.&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="nv"&gt;DOTFILES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/Path/To/dotfiles"&lt;/span&gt;

&lt;span class="k"&gt;for &lt;/span&gt;FILE &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;$DOTFILES&lt;/span&gt;/shell/&lt;span class="k"&gt;*&lt;/span&gt;.sh&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="nv"&gt;$FILE&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;source&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  DSL / Plaintext Configuration
&lt;/h4&gt;

&lt;p&gt;While DSLs can still be Turing-complete, many configuration languages aren't, which means that we don't have access to helpful things like conditionals or loops. To make modular configurations, we are going to have to construct the source files from our modules using a scripting language.&lt;/p&gt;

&lt;p&gt;For my tmux configuration I have a similar directory structure to my shell configurations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotfiles/
├── tmux/
|   ├── theme.conf
|   ├── bindings.conf
|   └── general.conf
├── .tmux.conf
└── bootstrap.zsh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that we still have a modular structure. But, our &lt;code&gt;.tmux.conf&lt;/code&gt; file is written in plaintext, it's not executable, so we can't loop through the &lt;code&gt;tmux/&lt;/code&gt; directory there. Instead, we have to write a function that can write our &lt;code&gt;.tmux.conf&lt;/code&gt; to use in &lt;code&gt;bootstrap.zsh&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;write_conf &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;local dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;
    &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;out&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;

    &lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="nv"&gt;$dir&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$out&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"# Conf written on &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;gdate&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$out&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

write_conf &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$DOTFILES&lt;/span&gt;&lt;span class="s2"&gt;/tmux"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$DOTFILES&lt;/span&gt;&lt;span class="s2"&gt;/.tmux.conf"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now for every plaintext configuration, we can write every file in a given directory to a single file. I also added a timestamp to the end of the file to make sure the bootstrap script ran properly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I don't like forking
&lt;/h2&gt;

&lt;p&gt;You can get a lot of ideas for your own configurations by perusing &lt;a href="https://github.com/nmiller15/dotfiles" rel="noopener noreferrer"&gt;my dotfiles&lt;/a&gt;, or any of the dotfiles that many people share on &lt;a href="https://www.reddit.com/r/dotfiles/" rel="noopener noreferrer"&gt;reddit&lt;/a&gt;, or &lt;a href="https://github.com/search?type=repositories&amp;amp;q=dotfiles" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; or other sites. However, I think that &lt;em&gt;if you're just starting,&lt;/em&gt; forking someone else's configurations can side-step the the self-discovery and growth than comes from starting from scratch. &lt;/p&gt;

&lt;p&gt;By all means, take inspiration from others, but the goal is to solve the problems that &lt;em&gt;you&lt;/em&gt; have on &lt;em&gt;your&lt;/em&gt; system. If you start with a fork dotfiles, you're getting someone else's solutions to someone else's problems. Often, these solutions have &lt;em&gt;way more&lt;/em&gt; configurations that you want or need, because you're jumping into a repository that may have been built on for years. For me, that kind of starting point is overwhelming and adds friction when there are changes that I want to make.&lt;/p&gt;

&lt;h2&gt;
  
  
  But, they're &lt;em&gt;your&lt;/em&gt; dotfiles.
&lt;/h2&gt;

&lt;p&gt;So, do what you want. If you want to fork, fork. If you want to start from scratch, start from scratch. Nobody's opinion on your dotfiles matters because they are uniquely yours, for your computer, your workflow, and your enjoyment.&lt;/p&gt;

&lt;p&gt;Happy scripting!&lt;/p&gt;

</description>
      <category>automation</category>
      <category>tooling</category>
      <category>bash</category>
      <category>learning</category>
    </item>
    <item>
      <title>Quidditch - Powered By PostgreSQL and ASP.NET</title>
      <dc:creator>Nolan Miller</dc:creator>
      <pubDate>Thu, 24 Jul 2025 19:24:06 +0000</pubDate>
      <link>https://forem.com/nmiller15/quidditch-powered-by-postgresql-and-aspnet-3mp5</link>
      <guid>https://forem.com/nmiller15/quidditch-powered-by-postgresql-and-aspnet-3mp5</guid>
      <description>&lt;p&gt;As a software developer, it's important to work on your craft. That's why I've been studying ASP.NET for the past few months. &lt;a href="https://nolanmiller.me/posts/intro-to-.net-apis-for-a-javascript-developer/" rel="noopener noreferrer"&gt;In my last article&lt;/a&gt; I walk through how to set up an ASP.NET Minimal Web API. Today, I'll be building on that foundation, by adding a persistent data store, a la PostgreSQL. In order to configure a .NET API to communicate with a PostgreSQL database, I'm going to use Entity Framework.&lt;/p&gt;

&lt;p&gt;Though I could have worked with my animal sounds API, I decided to implement the database for an app that scores a road trip game that my wife and I took this summer.&lt;br&gt;
I recently saw a video about a new road trip game that's inspired by Harry Potter (my favorite book series). I knew that my wife and I had to try it. If you're interested, the rules of the game are &lt;a href="https://www.instagram.com/reel/DEs-Stox4d2/?hl=en" rel="noopener noreferrer"&gt;described in this video,&lt;/a&gt; and you can play using my score tracker at &lt;a href="https://quidditchtrip.nolanmiller.me" rel="noopener noreferrer"&gt;https://quidditchtrip.nolanmiller.me&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;In this article, I'll go over making sure that you have PostgreSQL installed and running, and then how to install and configure Entity Framework to read to and write from the database. &lt;/p&gt;
&lt;h2&gt;
  
  
  What you'll need to start:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A .NET Web API (that you've created &lt;a href="https://nolanmiller.me/posts/supercharge-your-productivity-with-the-.net-cli/" rel="noopener noreferrer"&gt;using the dotnet CLI&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Access to an internet connection&lt;/li&gt;
&lt;li&gt;A little bit of patience&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Install Postgres
&lt;/h2&gt;

&lt;p&gt;There are a few different methods to installing and starting a Postgres server on your machine, but the easiest route is downloading Postgres.app, a MacOS postgres server interface that comes bundled with the &lt;code&gt;psql&lt;/code&gt; CLI. If you're not on Mac, or if you're interested in other installation methods the &lt;a href="https://www.postgresql.org/download/" rel="noopener noreferrer"&gt;official Postgres website&lt;/a&gt; has installation instructions for every operating system and includes instructions for other installation methods.&lt;/p&gt;

&lt;p&gt;Once you're done you should be able to start your Postgres server and also connect to it using the &lt;code&gt;psql&lt;/code&gt; command line interface. &lt;/p&gt;
&lt;h2&gt;
  
  
  Create a database
&lt;/h2&gt;

&lt;p&gt;Before we can start creating our models and writing data, we need to make sure that we have a database for our application. To do this, connect to &lt;code&gt;psql&lt;/code&gt; using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will connect us to the Postgres server with the default user &lt;code&gt;postgres&lt;/code&gt;. If it prompts  you for a password, it should be the default password, &lt;code&gt;postgres&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Once you're connected you should see a prompt that ends with &lt;code&gt;#&lt;/code&gt; and we can issue the following SQL command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;postgres&lt;/span&gt;&lt;span class="o"&gt;=#&lt;/span&gt; &lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;DATABASE&lt;/span&gt; &lt;span class="n"&gt;Quidditch&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since this database is for my Quidditch app, I'll name it &lt;code&gt;Quidditch&lt;/code&gt;, just replace this with whatever name makes sense for your application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connect to your database
&lt;/h2&gt;

&lt;p&gt;With a database set up, it can be connected to our .NET application using Entity Framework, an object-relational mapper for the .NET ecosystem. EF will automate reading and writing data on our database, and handle table creation and modifications through the development process.&lt;/p&gt;

&lt;p&gt;To get started with EF for Postgres, install two NuGet packages by running the following commands from a terminal in your .NET project:&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.EntityFrameworkCore.PostgreSQL
dotnet add package Microsoft.EntityFrameworkCore.Design
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To interact with a database we have to create a database context to allow us to interface with the database, configure the context object to use the proper connection string, set up models and create a migration using EF that will scaffold our database. &lt;/p&gt;

&lt;h2&gt;
  
  
  1. Database Context
&lt;/h2&gt;

&lt;p&gt;To create a database context, create a class that inherits from EF's DbContext class, like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.EntityFrameworkCore&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;QuidditchContext&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;DbContext&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;QuidditchContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DbConextOptions&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;QuidditchContext&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;base&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="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;Then wire it into your &lt;code&gt;Program.cs&lt;/code&gt; file.&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="c1"&gt;// in Program.cs&lt;/span&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="s"&gt;"[Your connection string]"&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="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;AddDbContext&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;QuidditchContext&lt;/span&gt;&lt;span class="p"&gt;&amp;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="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseNpgsql&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way of setting a connection string isn't secure, and should only be used for testing. Make sure that you load these in via a config file!&lt;/p&gt;

&lt;p&gt;And with these two small additions, Entity Framework can access your database server.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Set up models
&lt;/h2&gt;

&lt;p&gt;The next step in configuration is defining the models that we want to persist. For my Quidditch game, since it's a simple score tracker, I really only need to capture two data models: games and teams. Instead of creating two database tables for these and setting up their columns, I can just create the model in my C# code and EF will reason out the structure of the database!&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;Team&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;TeamKey&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="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="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="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Score&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="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;IsActive&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="n"&gt;DateTime&lt;/span&gt; &lt;span class="n"&gt;CreatedDateTime&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="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;GameKey&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="n"&gt;JsonIgnore&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;Game&lt;/span&gt; &lt;span class="n"&gt;Game&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="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Game&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;GameKey&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="n"&gt;DateTime&lt;/span&gt; &lt;span class="n"&gt;GameStartDateTime&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="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;GameEndDateTime&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="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;IsActive&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="k"&gt;true&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;bool&lt;/span&gt; &lt;span class="n"&gt;IsFinished&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;GameEndDateTime&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="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Team&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Teams&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="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Team&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A couple of things to point out here. First, I'm using the terminology &lt;code&gt;[Entity]Key&lt;/code&gt; to define my primary keys. This is &lt;em&gt;not&lt;/em&gt; automatically picked up by EF. They would prefer that you use &lt;code&gt;[Entity]Id&lt;/code&gt; instead. Unfortunately, I am stubborn and would have been mistyping "Key" instead of "Id" of for the whole project, so I took the extra couple of steps to define my keys and relationships. &lt;/p&gt;

&lt;p&gt;When I add these models to my database context in the next step, EF will use these models to set up tables and columns based on them. Not everything will be one for one though. There are two special properties here. The &lt;code&gt;Team.Game&lt;/code&gt; property and the &lt;code&gt;Game.Teams&lt;/code&gt; properties are called &lt;em&gt;Navigations&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;A Navigation property models a relationship between two tables. They work by associating related models using primary and foreign keys on the models and are kept in sync by EF. &lt;/p&gt;

&lt;p&gt;Before these will behave as expected, we need to register these models in our &lt;code&gt;DbContext&lt;/code&gt; with &lt;code&gt;DbSet&lt;/code&gt; properties. This can be done as easily as adding properties to any other class, but set the type to &lt;code&gt;DbSet&amp;lt;[Entity]&amp;gt;&lt;/code&gt; where &lt;code&gt;[Entity]&lt;/code&gt; is the model that you want to register.&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="c1"&gt;// QuidditchContext&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;QuidditchContext&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;DbContext&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;QuidditchContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DbConextOptions&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;QuidditchContext&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;base&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="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="n"&gt;DbSet&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Team&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Teams&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="n"&gt;DbSet&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Game&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Games&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;DbSet&amp;lt;&amp;gt;&lt;/code&gt; class comes from Entity Framework and inherits from &lt;code&gt;IEnumerable&amp;lt;T&amp;gt;&lt;/code&gt;, which allows us to use LINQ (and some Entity Framework specific versions of LINQ) to access our models.&lt;/p&gt;

&lt;p&gt;Since I decided to use a different convention for my primary and foreign keys, I have another configuring step to define the relationships between my tables. To manually define table and column relationships, override the &lt;code&gt;OnModelCreating&lt;/code&gt; method in &lt;code&gt;DbContext&lt;/code&gt;. The relationships that I used are below.&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;QuidditchContext&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;DbContext&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnModelCreating&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ModelBuilder&lt;/span&gt; &lt;span class="n"&gt;modelBuilder&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// .HasKey tell EF what the name of the primary key should be&lt;/span&gt;
        &lt;span class="n"&gt;modelBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Team&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HasKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TeamKey&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;modelBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Game&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HasKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GameKey&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// These methods define the one-to-many relationship in&lt;/span&gt;
        &lt;span class="c1"&gt;// what looks like plain language. &lt;/span&gt;
        &lt;span class="n"&gt;modelBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Team&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HasOne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Game&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithMany&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Teams&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HasForeignKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GameKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;OnDelete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DeleteBehavior&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetNull&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// .OnDelete can set what happens to related tables&lt;/span&gt;
        &lt;span class="c1"&gt;// when the record they reference is deleted.&lt;/span&gt;

        &lt;span class="c1"&gt;// I don't want a table to be created for this model.&lt;/span&gt;
        &lt;span class="n"&gt;modelBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Ignore&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;LeaderboardEntry&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;   
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even if you're not using custom naming for your properties, it is probably a good idea to override this method so that your complex relationships are explicitly set by you. This will help mitigate unexpected behavior and has the added benefit of providing some in-code documentation.&lt;/p&gt;

&lt;p&gt;Now that configuration is done, it's time to create a database through a process called migration.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Create a migration
&lt;/h2&gt;

&lt;p&gt;As you work on a project, inevitably the shape of your data will change here and there. Instead of manually updating your database tables, Entity Framework handles this through &lt;em&gt;migrations.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Since the models are already defined in the code, Entity Framework can scaffold and re-scaffold database, throughout the lifecycle of the application. A migration can be created using the &lt;code&gt;dotnet&lt;/code&gt; CLI with the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet ef migrations add InitialCreate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With &lt;code&gt;dotnet ef&lt;/code&gt; the Entity Framework-specific tools are specified, and then using the &lt;code&gt;migrations add&lt;/code&gt; command a migration is created called &lt;code&gt;InitialCreate&lt;/code&gt;. A migration can have any name, but it's a good idea to give it a descriptive title for when you need to roll your changes back.&lt;/p&gt;

&lt;p&gt;To finalize the changes on our database (or "creation of" in this instance) we still have to run one more command. EF separates this process of updating the database into two steps. In the first step, a few things happen:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a &lt;code&gt;Migrations&lt;/code&gt; directory is created in the root of your project if not already there&lt;/li&gt;
&lt;li&gt;a &lt;code&gt;[TIMESTAMP]_InitialCreate.cs&lt;/code&gt; file is generated, containing the steps to implement the changes to your context, and steps to walk it back if needed.&lt;/li&gt;
&lt;li&gt;a &lt;code&gt;[TIMESTAMP]_InitialCreate.Designer.cs&lt;/code&gt; file is generated with metadata for EF to use.&lt;/li&gt;
&lt;li&gt;a &lt;code&gt;MyContextModelSnapshot.cs&lt;/code&gt; file containing a current snapshot of your context model is created.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The syntax in these files is fairly easy to interpret, so it's a good idea to do a once-over of the &lt;code&gt;Up&lt;/code&gt; method in the &lt;code&gt;[TIMESTAMP]_InitialCreate.cs&lt;/code&gt; method so that you aren't surprised by any changes!&lt;/p&gt;

&lt;p&gt;Now to finalize those changes and apply them to the database run the following command.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;This will updates the database to the most recent migration. Be careful as you do this, there is potential for data loss when running this command! Now, the database and it's tables are set up and ready for you to start querying!&lt;/p&gt;

&lt;h2&gt;
  
  
  Using LINQ to access your data
&lt;/h2&gt;

&lt;p&gt;To illustrate how to query a database using Entity Framework, take a look at one of the service methods that I created for my application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;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;ServiceResponse&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Game&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetGameByKey&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;gameKey&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;game&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;_context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Games&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Teams&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SingleAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GameKey&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;gameKey&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;game&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="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ServiceResponse&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Game&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="nf"&gt;Failure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ServiceResponse&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Game&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="nf"&gt;Success&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;game&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're familiar with LINQ syntax, then this should be familiar.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ServiceResponse&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Game&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetGameByKey&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;gameKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, I'm declaring a method called &lt;code&gt;GetGameByKey&lt;/code&gt;, that returns a custom response object with the generic type &lt;code&gt;Game&lt;/code&gt;. I just created a response class with a generic &lt;code&gt;Payload&lt;/code&gt; property so that I can send back metadata along with the requested models if needed.&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;game&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;_context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Games&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Teams&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SingleAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GameKey&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;gameKey&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This line queries the database, translating the database record into a usable model and assigning it to a variable that we can return from the method! By default, navigation properties are not included, but using &lt;code&gt;.Include()&lt;/code&gt; and specifying the navigation property includes the related navigation in the query. &lt;/p&gt;

&lt;p&gt;Query execution is signaled by the &lt;code&gt;.SingleAsync()&lt;/code&gt; method, which works the same way as &lt;code&gt;.Single()&lt;/code&gt; in LINQ. So this query, will return a only a single record where the &lt;code&gt;GameKey&lt;/code&gt; column's value is equal to the &lt;code&gt;gameKey&lt;/code&gt; argument passed in when this method is called.&lt;/p&gt;

&lt;p&gt;Here's another method 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;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;ServiceResponse&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Game&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;SetGameInactive&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;gameKey&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;gameResponse&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;GetGameByKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gameKey&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;gameResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WasSuccessful&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;gameResponse&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;game&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gameResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Payload&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;game&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsActive&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;_context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Games&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;game&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;changedRows&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;_context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveChangesAsync&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;changedRows&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ServiceResponse&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Game&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="nf"&gt;Failure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ServiceResponse&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Game&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="nf"&gt;Success&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;game&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;There's a little more logic going on in this method. The goal is to find the &lt;code&gt;Game&lt;/code&gt; with the matching &lt;code&gt;GameKey&lt;/code&gt; and then set its &lt;code&gt;IsActive&lt;/code&gt; property to &lt;code&gt;false&lt;/code&gt;. The &lt;code&gt;Game&lt;/code&gt; is retrieved in the same way as the first method we looked at. Once it's been accessed, then it's properties can be updated like any other class instance in C#. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;_context.Games.Update()&lt;/code&gt; method prepares EF to send the command to the database. Unlike the first query, the execution is started by &lt;code&gt;SaveChangesAsync()&lt;/code&gt;, which returns the number of affected rows. This is the EF pattern for modifying existing data. The changes are made in the code, and &lt;code&gt;SaveChanges()&lt;/code&gt; or &lt;code&gt;SaveChangesAsync()&lt;/code&gt; must be called. &lt;/p&gt;

&lt;p&gt;I hope that this shows just how simple it can be to access the data from a database using familiar C# list patterns. For a full list of methods available to Entity Framework, &lt;a href="https://learn.microsoft.com/en-us/ef/core/querying/" rel="noopener noreferrer"&gt;check out their documentation&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;If you made it this far, thank you for reading! I hope that you found it helpful and I wish you the best of luck in implementing EF Core into your own C# applications. &lt;/p&gt;

&lt;p&gt;This was a unique challenge for me. I primarily write in C# for my job, but we use a custom data access library that requires mapping our models manually. While Entity Framework has some nice quality-of-life features, I found that lose some of the flexibility gained by writing your own SQL. &lt;/p&gt;

&lt;p&gt;This was a very simple project, but even still, it felt like I didn't save much time by using an ORM. Rather than save time on having to write SQL, I traded that time for configuring my database and tables in C#. &lt;/p&gt;

&lt;p&gt;In my day job, I rely on libraries that have been provided for me, so I'm looking forward to learning how to implement database connections on my own. I don't know that I would choose to use Entity Framework again. I liked how easy it was to set up my models and navigations made implementing business logic very nice, but the configuration of relationships just wasn't as straightforward as it is in SQL. &lt;/p&gt;

&lt;p&gt;Regardless, it is always good to take some time to learn new technologies.&lt;/p&gt;

&lt;p&gt;Thanks again for reading!&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>asp</category>
      <category>dotnet</category>
      <category>learning</category>
    </item>
    <item>
      <title>Intro to .NET APIs for a JavaScript Developer</title>
      <dc:creator>Nolan Miller</dc:creator>
      <pubDate>Tue, 27 May 2025 12:34:27 +0000</pubDate>
      <link>https://forem.com/nmiller15/intro-to-net-apis-for-a-javascript-developer-2bf9</link>
      <guid>https://forem.com/nmiller15/intro-to-net-apis-for-a-javascript-developer-2bf9</guid>
      <description>&lt;p&gt;When I was applying like crazy to developer jobs, I'd scroll past so many .NET focused ones, thinking, "I'm only a JavaScript developer." &lt;/p&gt;

&lt;p&gt;I felt lied to. &lt;/p&gt;

&lt;p&gt;The internet told me "JavaScript can do it all," but, I felt like the skills that I'd learned would never land me a job. When I &lt;em&gt;did&lt;/em&gt; find a primarily JavaScript job, it always had so many applicants that I felt like I didn't have a chance.&lt;/p&gt;

&lt;p&gt;As of October 2024, JavaScript was still the second most used language on GitHub (though it was just over taken by Python). Check out this &lt;a href="https://github.blog/news-insights/octoverse/octoverse-2024/" rel="noopener noreferrer"&gt;blog post from GitHub&lt;/a&gt;. But even though there's so much JavaScript code, that doesn't mean that the job market for it is thriving. &lt;/p&gt;

&lt;p&gt;In my experience, the jobs with a .NET focus on job boards were:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;... looking for more experience, but appeared to be more flexible.&lt;/li&gt;
&lt;li&gt;... were paying higher starting salaries, and&lt;/li&gt;
&lt;li&gt;... not attracting very many applicants AT ALL.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;JavaScript's reputation for being easy to learn, means that WAY MORE people know it, paradoxically requiring you to be even more experienced to compete in the job market.&lt;/p&gt;

&lt;h2&gt;
  
  
  I just started programming, I can't code in C#!
&lt;/h2&gt;

&lt;p&gt;The first time I looked at C#, it was intimidating. Sure, it uses curly braces, but the boilerplate code is deeply nested, I don't know any of the libraries available, and EVERYTHING IS IN PASCAL CASE. &lt;/p&gt;

&lt;p&gt;The .NET ecosystem is a mature, reliable framework used to develop stable applications in many environments, but it can feel pretty unapproachable to newbies. &lt;/p&gt;

&lt;p&gt;But, C# has a template that will feel very familiar to an intermediate JavaScript developer. A starting place, where you can begin to create useful apps and also begin to wrap your mind around the syntax and features of C# in ASP.NET.&lt;/p&gt;

&lt;h2&gt;
  
  
  An unconventional starting point
&lt;/h2&gt;

&lt;p&gt;Start with a simple API. To be more specific, use the Minimal API template. The MVC model, especially when you're starting out, can be overwhelming. So, why start with an API? Because it's a simple way to integrate .NET into something that you're already working on. Have a React application? Well then let it consume your ASP.NET Minimal API as the backend.&lt;/p&gt;

&lt;p&gt;You'll probably be surprised that the things you learned as a JavaScript developer (especially if you're using Express.js to build your APIs), will have strong carry over into the .NET ecosystem.&lt;/p&gt;

&lt;p&gt;So, let's get up to speed on what a Minimal API even is, and then I'll walk you through how to get your own Minimal API up and running by the end of this post!&lt;/p&gt;

&lt;h3&gt;
  
  
  What Are Minimal APIs?
&lt;/h3&gt;

&lt;p&gt;With .NET 6, Microsoft released Minimal APIs. This is opposed to the Controller-based API pattern that is common in .NET. Minimal APIs is that remove a lot of unnecessary boilerplate code that you need to create endpoint routes in a controller-based APIs. &lt;/p&gt;

&lt;p&gt;Here's why this is good news for Javascript developers looking to get into .NET. The removal of this boilerplate code makes the syntax look &lt;em&gt;very similar&lt;/em&gt; to the syntax used to build an API on Node with Express.js.&lt;/p&gt;

&lt;h3&gt;
  
  
  Side-by-Side Comparison: Express.js vs. Minimal APIs
&lt;/h3&gt;

&lt;p&gt;To show you how approachable this can be, I'm going to create a GET and POST route and point out the similarities between the C# Minimal API version and the Express.js version&lt;/p&gt;

&lt;p&gt;So let's set up the .NET Minimal API first.&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="c1"&gt;// set up api&lt;/span&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;namespace&lt;/span&gt; &lt;span class="nn"&gt;MinimalAPI&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;Program&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;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="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;// ... add endpoints and middleware here&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;"Server is running on port 3000."&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;span class="s"&gt;"http://localhost:3000"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If this syntax is new to you, let me walk you through it. We're first referencing the &lt;code&gt;Microsoft.AspNetCore.Mvc&lt;/code&gt; which contains the Builder class that we will use to construct our application. We call the &lt;code&gt;build()&lt;/code&gt; method on the builder and then &lt;code&gt;run&lt;/code&gt; our application while specifying the port.&lt;/p&gt;

&lt;p&gt;Now, to set up the same application on Node in Express.js we would write the following.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// set up express app&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// ... add endpoints and middleware here&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Server is running on port 3000&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;Notice how similar. We &lt;code&gt;require&lt;/code&gt; Express, which abstracts our builder logic. Then we run the application, specifying the port!&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating Endpoints
&lt;/h3&gt;

&lt;p&gt;The syntax is even more similar between these two frameworks for endpoint creation.  Using the &lt;code&gt;app&lt;/code&gt; that our builder created we the correct endpoint verb creation method to create the endpoint listener. In ASP.NET, this will look like this.&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;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HttpRequest&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;HttpResponse&lt;/span&gt; &lt;span class="n"&gt;response&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="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Hello World"&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;This pattern is nearly identical to what we would write in Express.js.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&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="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello World&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;In both the Minimal API and the Express API, we pass the endpoint route as the first parameters, and the callback function as the second. &lt;/p&gt;

&lt;h3&gt;
  
  
  Get started with ASP.NET
&lt;/h3&gt;

&lt;p&gt;If you're tired of seeing job postings you feel that you can't apply for, then start learning C#! It doesn't have to be scary, or overly complex. And, I hope that I've shown that with the knowledge that you have already, you can get started in creating a useful application that has the potential to solve real world problems. &lt;/p&gt;

&lt;p&gt;There are numerous free resources to get started with the basics of C#, and if it's your first strongly typed language, there will probably be some hurdles. But, once you get through the initial learning phase, so many of the skills you've already developed will transfer over.&lt;/p&gt;

&lt;p&gt;Over the past several months, I've been diving deeper into ASP.NET. Check out some of my posts that detail my journey!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nolanmiller.me/posts/supercharge-your-productivity-with-the-.net-cli/" rel="noopener noreferrer"&gt;Learn ASP.NET Core from Scratch &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nolanmiller.me/posts/supercharge-your-productivity-with-the-.net-cli/" rel="noopener noreferrer"&gt;Supercharge Your Productivity with the .NET CLI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nolanmiller.me/posts/anatomy-of-an-asp.net-mvc-template/" rel="noopener noreferrer"&gt;Anatomy of an ASP.NET MVC Template&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nolanmiller.me/posts/what-is-dependency-injection/" rel="noopener noreferrer"&gt;Interviewers will Ask You About This: Dependency Injection Made Simple&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nolanmiller.me/posts/learn-application-configuration-in-asp.net/" rel="noopener noreferrer"&gt;Learn Application Configuration in ASP.NET&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>dotnet</category>
      <category>api</category>
      <category>learning</category>
    </item>
    <item>
      <title>Learn Application Configuration in ASP.NET</title>
      <dc:creator>Nolan Miller</dc:creator>
      <pubDate>Mon, 24 Mar 2025 12:20:52 +0000</pubDate>
      <link>https://forem.com/nmiller15/learn-application-configuration-in-aspnet-2adp</link>
      <guid>https://forem.com/nmiller15/learn-application-configuration-in-aspnet-2adp</guid>
      <description>&lt;p&gt;As a self-taught developer, a part of software development that I didn't know much about when I started my first development job was configuration.&lt;/p&gt;

&lt;p&gt;When I was building solo projects, it was hard to see the value in loading configurations rather than just hard coding. &lt;em&gt;Why would I introduce complexity?&lt;/em&gt; &lt;em&gt;It would take time learn how to load them in.&lt;/em&gt; &lt;em&gt;Maybe I'll learn how to do it later, but that's just a waste of time.&lt;/em&gt;  &lt;/p&gt;

&lt;p&gt;I knew that these thoughts weren't true, but the excuses kept me from learning. As I got some experience with larger codebases, however, I started seeing the clear need for configuration objects. We have to able to change specific behaviors of our application without releasing. This is what enables us to connect one release of an application to different databases or APIs, to change features for development or production, and make many other important changes. &lt;/p&gt;

&lt;p&gt;If you follow along with this article, we will create a basic console application that shuffles through the titles of songs to demonstrate how to load values into a configuration object and access them to change functionality in .NET.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's create a music player!
&lt;/h2&gt;

&lt;p&gt;Okay... only sort of. Unfortunately, we won't be sending anything to your speakers. For the purpose of learning how to load and use configurations within ASP.NET, I created a console application called SongShuffle! &lt;/p&gt;

&lt;p&gt;To follow along with the sections in this article, go ahead and clone the GitHub repo by running the &lt;code&gt;git clone&lt;/code&gt; command below in your console.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/nmiller15/SongShuffle/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I've created branches to guide you through the codebase in this article, at any point you can checkout the branches and arrive at a working application at a different step! I encourage you to experiment and load some of your own configurations and functionality here though!&lt;/p&gt;

&lt;p&gt;To make sure you're on the correct branch, run the following in your console.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout 1-start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  A tour of our music player
&lt;/h3&gt;

&lt;p&gt;If you launch the SongShuffle console application by clicking Run/Debug, or using &lt;code&gt;dotnet run&lt;/code&gt; in the project directory, you will see a modest user command line interface that asks you to press any key to start listening. &lt;/p&gt;

&lt;p&gt;The song screen shows the title, artist and year of the current song's release at the top of the screen and will allow you to select a new song by pressing enter. If you type in &lt;code&gt;q&lt;/code&gt; before pressing enter, the program will exit. &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%2Flkzsxvudlgn6budo31ha.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%2Flkzsxvudlgn6budo31ha.png" alt="SongShuffle Interface" width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the basic function of the music player that we will configure. Go ahead and play around with it!&lt;/p&gt;

&lt;p&gt;Take some time to familiarize yourself with the classes that we have here that create the behavior for this application: &lt;code&gt;Song.cs&lt;/code&gt; and &lt;code&gt;SongProvider&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;If you're digging around in the song bank in the &lt;code&gt;SongProvider&lt;/code&gt;, you might notice that we only have 80s music loaded into the application. While this might be all that I play, others might want their music player to be a bit more versatile, so this is going to be the first configurable feature that we are going to add to the music player.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring for the 90s groove
&lt;/h2&gt;

&lt;p&gt;To add this feature, we have to add another song bank and a way to select those banks. To see my implementation, run the following command in your console.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout 2-pick-a-decade
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Most of our changes are in the &lt;code&gt;SongProvider&lt;/code&gt; class. I've added three more song banks, containing music from different decades. I've created an Enum &lt;code&gt;Decades&lt;/code&gt; that will select the song set for the &lt;code&gt;SongBank&lt;/code&gt;. And I've added a switch statement in the &lt;code&gt;SongPovider&lt;/code&gt; constructor, that sets the &lt;code&gt;SongBank&lt;/code&gt; property.&lt;/p&gt;

&lt;p&gt;With these changes the &lt;code&gt;SongProvider&lt;/code&gt; is able to change its selection of songs without having to alter it's implementation details. We've now moved control of the song bank selection outside of the provider. That means that we'll have to define our Enum to pass in before we can instantiate our &lt;code&gt;SongProvider&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="c1"&gt;// SongProvider.cs&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;SongProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Decades&lt;/span&gt; &lt;span class="n"&gt;decade&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;decade&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;Decades&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Eighties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;SongBank&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;EightiesSongs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;Decades&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Nineties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;SongBank&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;NinetiesSongs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;Decades&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TwoThousands&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;SongBank&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TwoThousandsSongs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;Decades&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TwentyTens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;SongBank&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TwoThousandTensSongs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ArgumentException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Must include a valid decade."&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="c1"&gt;// Program.cs&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;DisplaySong&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;userResponse&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;decade&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SongProvider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Decades&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Nineties&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;provider&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;SongProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;decade&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// ... &lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now we can rock out to some Madonna!&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%2Fufgdix4te6yuj6b3mttj.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%2Fufgdix4te6yuj6b3mttj.png" alt="SongShuffle Hard Coded Nineties Music" width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If we wanted to change the decade we can do that a bit more easily now, but its still a developer task. Someone without any code experience would have issues working with this. We'd have to go in, change the value of the &lt;code&gt;Decades&lt;/code&gt; Enum. Then, we'd also have to create a release and push it. &lt;/p&gt;

&lt;p&gt;Man... That's a lot of work for a small feature.&lt;/p&gt;

&lt;p&gt;So, we've moved the song bank selection out of the &lt;code&gt;SongProvider&lt;/code&gt; but, what if we pull it out of the application itself. This would keep us from having to deal with this release issue.&lt;/p&gt;

&lt;h2&gt;
  
  
  Loading our first configuration
&lt;/h2&gt;

&lt;p&gt;Checkout the next branch to see how we can load values into our .NET program from external files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout 3-config-from-json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first thing I'd like to point out is the &lt;code&gt;LoadConfig()&lt;/code&gt; method that I've created which has a fairly straightforward goal.... to load the configuration. But, how is this handled 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;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;LoadConfig&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;Welcome&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nf"&gt;DisplaySong&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&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;
  
  
  The configuration interface
&lt;/h3&gt;

&lt;p&gt;Microsoft has an &lt;code&gt;IConfiguration&lt;/code&gt; interface built into the framework. The interface allows us to attach key-value pairs from multiple sources and then access them later. These values are what we will use to configure parts of our application.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;LoadConfig()&lt;/code&gt; method that I created, just returns an instance of &lt;code&gt;IConfiguration&lt;/code&gt; loaded with our configuration values. The configuration object that is returned by this method will be passed around our application with values being accessed and determining app behavior.&lt;/p&gt;

&lt;h3&gt;
  
  
  Accessing values from a config object
&lt;/h3&gt;

&lt;p&gt;There are a few ways that we can use to access these values. First, is using the Indexer syntax, borrowed from the dictionary.&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="k"&gt;value&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;"KeyName"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the way that we will access them throughout this article, but also know that .NET provides other ways to access complex configuration objects using methods like &lt;code&gt;.GetSection()&lt;/code&gt; and &lt;code&gt;.Bind()&lt;/code&gt;. If you'd like more information on those, &lt;a href="https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-9.0#bind-hierarchical-configuration-data-using-the-options-pattern" rel="noopener noreferrer"&gt;check out this article from Microsoft's documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Registering key-value pairs to a config object
&lt;/h3&gt;

&lt;p&gt;The most common way to register key-value pairs is through an &lt;code&gt;appsettings.json&lt;/code&gt; file. This is a file that contains a valid JSON object that sits at the root level of your project. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; It is common for &lt;code&gt;appsettings.json&lt;/code&gt; to be checked into source control, so do &lt;em&gt;not&lt;/em&gt; store sensitive data like API keys or connection strings here.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In our example &lt;code&gt;appsettings.json&lt;/code&gt;, we have a simple JSON object that defines a "Decade" key.&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;"Decade"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"TwoThousands"&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;Now, to add this file to our configuration object, we need to use the built-in &lt;code&gt;ConfigurationBuilder&lt;/code&gt; and use the &lt;code&gt;AddJsonFile&lt;/code&gt; method. Pass the relative path of the JSON file that you want to add to register the key-value pairs inside it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;IConfiguration&lt;/span&gt; &lt;span class="nf"&gt;LoadConfig&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;builder&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;ConfigurationBuilder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddJsonFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"appsettings.json"&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;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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When we run &lt;code&gt;LoadConfig()&lt;/code&gt; any values that we have in our &lt;code&gt;appsettings.json&lt;/code&gt; file will be accessible within our application in our &lt;code&gt;IConfiguration&lt;/code&gt; object!&lt;/p&gt;

&lt;h3&gt;
  
  
  Using our configuration object in the application
&lt;/h3&gt;

&lt;p&gt;To actually make use of this &lt;code&gt;IConfiguration&lt;/code&gt; object, we have to pass it into our &lt;code&gt;DisplaySong&lt;/code&gt; method. You can take a look at the necessary changes below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;DisplaySong&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IConfiguration&lt;/span&gt; &lt;span class="n"&gt;config&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;userResponse&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;decade&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Decade"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;switch&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;"Nineties"&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;SongProvider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Decades&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Nineties&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"TwoThousands"&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;SongProvider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Decades&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TwoThousands&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"TwentyTens"&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;SongProvider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Decades&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TwentyTens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;SongProvider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Decades&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Eighties&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;provider&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;SongProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;decade&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;With this method, the selection of the decade is decoupled from the logic that displays the song. The selection of the decade is being set outside of our application.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;If this isn't working for you...&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Try the following steps if the configuration isn't loading for you.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Right click on &lt;code&gt;appsettings.json&lt;/code&gt; in Visual Studio. &lt;/li&gt;
&lt;li&gt;Properties &amp;gt; Copy To Output Directory. Make sure it is set to "Copy Always".&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What did I just do?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Your application runs from the &lt;code&gt;/bin/Debug/netX.X&lt;/code&gt; directory when you run your application in Debug mode. When Visual Studio tries to compile and run your project, it's looking for the &lt;code&gt;appsettings.json&lt;/code&gt; file relative to the file that it complied (in the &lt;code&gt;bin&lt;/code&gt;). &lt;/p&gt;

&lt;p&gt;By setting the "Copy Always", whenever we click "Debug" our &lt;code&gt;appsettings.json&lt;/code&gt; will be copied into &lt;code&gt;/bin/Debug/netX.X&lt;/code&gt; so that we can access it in our program.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;While we don't have to release another version of the application to change this behavior, it's still a little bit involved. We still have to find the right text file and change the correct value to get this to happen. Now let's explore how we can change the behavior of our application without having to edit any additional files!&lt;/p&gt;

&lt;h2&gt;
  
  
  Passing command-line arguments
&lt;/h2&gt;

&lt;p&gt;With only a few changes to our application, we can take in strings from outside the application by allowing command line arguments. Run the following command to see the changes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout 4-config-from-commandline
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You may not notice the change at first because it's so small, but there is one. We've added one line which calls the &lt;code&gt;.AddCommandLine(args)&lt;/code&gt; to the &lt;code&gt;ConfigurationBuilder&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;IConfiguration&lt;/span&gt; &lt;span class="nf"&gt;LoadConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;builder&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;ConfigurationBuilder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddJsonFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"appsettings.json"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddCommandLine&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="k"&gt;return&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By chaining this to the &lt;code&gt;.AddJsonFile()&lt;/code&gt; method, we're adding all the values from both to our configuration object.&lt;/p&gt;

&lt;p&gt;Command line arguments are key-value pairs declared after the execution command. To attach a key-value pair you would run the program like this:&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;span class="nt"&gt;--Decade&lt;/span&gt; &lt;span class="s2"&gt;"TwentyTens"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key &lt;code&gt;"Decade"&lt;/code&gt; would then be passed into the program with the value &lt;code&gt;"TwentyTens"&lt;/code&gt;. Luckily, we don't have to type these arguments into the program every time we want to Debug our program.&lt;/p&gt;

&lt;p&gt;In order to add a command line argument to your Debug profile, first, right-click your project and click &lt;em&gt;Properties&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;In that window, select &lt;em&gt;Debug&lt;/em&gt; from the sidebar, and click &lt;em&gt;Launch Profiles UI&lt;/em&gt;. After you click this, you will see the following UI window. Under &lt;em&gt;Command line arguments&lt;/em&gt; you can type in anything you like.&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%2Fio66jqdysfazps4pgtd7.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%2Fio66jqdysfazps4pgtd7.png" alt="Visual Studio Command Line Arguments For Debug" width="786" height="513"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Command line arguments can be passed in four different syntaxes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;[command] --key value&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[command] --key=value&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[command] /key value&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[command] /key=value&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm not sure what the advantage of having these different syntaxes is, but I prefer the first, since it is the most common way that I've seen arguments passed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Didn't we just pass &lt;code&gt;"Decade"&lt;/code&gt; twice?
&lt;/h3&gt;

&lt;p&gt;If never removed our &lt;code&gt;appsettings.json&lt;/code&gt; file, it's still being loaded into the configuration with a &lt;code&gt;Decade&lt;/code&gt; key, meaning that the &lt;code&gt;"Decade"&lt;/code&gt; key was loaded twice. &lt;/p&gt;

&lt;p&gt;Our &lt;code&gt;ConfigurationBuilder&lt;/code&gt; doesn't handle key collisions. It doesn't check to see if a key has already been assigned before binding a value to it. &lt;/p&gt;

&lt;p&gt;What does this mean? &lt;/p&gt;

&lt;p&gt;If you have two configuration files or methods that assign the same key, the key that was loaded earlier will be overwritten by the one loaded later. &lt;/p&gt;

&lt;p&gt;If you go back to the &lt;code&gt;appsettings.json&lt;/code&gt; file, you'll see that we still have a &lt;code&gt;"TwoThousands"&lt;/code&gt; value there. That value was successfully loaded, but immediately after that, our command line argument with the same key overwrote it with its value &lt;code&gt;"TwentyTens"&lt;/code&gt;. In our final configuration object, the key &lt;code&gt;"Decade"&lt;/code&gt; will have the value of the command line argument.&lt;/p&gt;

&lt;p&gt;This behavior allows us to keep configuration files that are subsets of other configuration files. Take for example an application that uses a different API in production and development. We can create a config file that only have the values that we need to overwrite, like a API key and endpoint that is only loaded in development.&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;builder&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;ConfigurationBuilder&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;AddJsonFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"appsettings.json"&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;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsDevelopment&lt;/span&gt;&lt;span class="p"&gt;())&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;AddJsonFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"appsettings.development.json"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're going to use this approach, make sure to be mindful of the order that you add your files and configuration sources in. There are no priority rules, so keys will &lt;em&gt;always&lt;/em&gt; be overwritten load methods later in the chain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Environmental influence
&lt;/h2&gt;

&lt;p&gt;There may by instances in which multiple applications will all share the same configuration values if they're running in the same environment. In that case, we can also load these into our program. Run the following command to see the changes that we make:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout 5-environment-variables
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just like the above methods, environment variables will be added as key-value pairs . It goes beyond the scope of this article to talk about how to set these on various systems, but I'll show you how you can set them in Visual Studio for development. &lt;/p&gt;

&lt;p&gt;If you open up the &lt;em&gt;Launch Profiles UI&lt;/em&gt; that we accessed to set our command line variables (&lt;em&gt;Properties&lt;/em&gt; &amp;gt; &lt;em&gt;Debug&lt;/em&gt; &amp;gt; &lt;em&gt;Launch Profiles&lt;/em&gt;), you can also set environment variables!&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%2Fgo3qiqr0fr6eb5vn99my.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%2Fgo3qiqr0fr6eb5vn99my.png" alt="Visual Studio Launch Profiles Environment Variables" width="786" height="513"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since we already have sources defining our decade, let's use a new variable &lt;code&gt;ShowImage&lt;/code&gt; that we will use to decide whether or not you see my beautiful ASCII rendering of an iPod. &lt;/p&gt;

&lt;p&gt;In the &lt;em&gt;Environment Variables&lt;/em&gt; section, under "Name", write "ShowImage", and for it's value, type "false". &lt;/p&gt;

&lt;p&gt;Now to access these when we run our code, all we need to do is add the &lt;code&gt;.AddEnvironmentVariables()&lt;/code&gt; method to our &lt;code&gt;ConfigurationBuilder&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;IConfiguration&lt;/span&gt; &lt;span class="nf"&gt;LoadConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;builder&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;ConfigurationBuilder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddJsonFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"appsettings.json"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddCommandLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddEnvironmentVariables&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;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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All we have to do to get this configuration up and running is to use our Boolean conversion in an &lt;code&gt;if&lt;/code&gt; statement and put our image inside it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;DisplaySong&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IConfiguration&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Additional setup ommitted for space&lt;/span&gt;

    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userResponse&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="s"&gt;"q"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;song&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ShuffleSelect&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;Clear&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;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;$"Now playing &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;song&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="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"ShowImage"&lt;/span&gt;&lt;span class="p"&gt;]?.&lt;/span&gt;&lt;span class="nf"&gt;ToLower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;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;@"
                ╔═══╗
                ║███║
                ║(O)║♫ ♪ ♫ ♪
                ╚═══╝
            ▄ █ ▄ █ ▄ ▄ █ ▄ █ ▄ █
            "&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&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;Now, our iPod will only be displayed if the configuration is set to "true". &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%2Fnlp2hu4d5vkq77e5dxyq.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%2Fnlp2hu4d5vkq77e5dxyq.png" alt="SongShuffle ShowImage false" width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But, I like to see my ASCII masterpiece while I'm "listening" to music, so I'm going to change this configuration back!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It's worth noting here that this is a fairly atypical usage of environment variables. Since both environment variables and command line arguments come in as strings, it isn't wise to use them as Booleans or integers or any other type unless you're parsing or validating them into another object.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's add one more configuration to this application, I'd like to make the songs play automatically, but again, I don't want to have to change any code. I could add another configuration in a JSON file or any of the other methods that we've discussed, but I want to show you how to do this with a .NET-specific solution, User Secrets.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up User Secrets in .NET
&lt;/h2&gt;

&lt;p&gt;See the code changes to accept user secrets by running the following command, but keep it open, we'll have a few more to run to make sure that we're all set up.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout 6-user-secrets
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;User Secrets is a Microsoft-created, development-only solution for storing sensitive strings outside of source control. It's built right into the .NET SDK and makes loading sensitive information into your application very simple for development.&lt;/p&gt;

&lt;p&gt;You do &lt;strong&gt;not&lt;/strong&gt; want to use this in production because this offers no encryption for your sensitive information, you would be better off using some sort of secrets manager. &lt;/p&gt;

&lt;h3&gt;
  
  
  How does User Secrets work?
&lt;/h3&gt;

&lt;p&gt;User Secrets is very similar to adding a JSON file to your application. We will create a file with key-value pairs and tell the framework where to look for the file. &lt;/p&gt;

&lt;p&gt;We identify the file using the &lt;code&gt;&amp;lt;UserSecretsId&amp;gt;&lt;/code&gt; tag with a Guid value in our .csproj file. Then in our &lt;code&gt;%AppData%\Microsoft\UserSecrets\{project-guid}&lt;/code&gt; we can store our secrets in a file called &lt;code&gt;secrets.json&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Don't worry though, you don't have to set this up manually.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up User Secrets
&lt;/h3&gt;

&lt;p&gt;Using the .NET CLI, all we have to do is run one command to get set up.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;When you run this command a few things happen: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;an ID is created&lt;/li&gt;
&lt;li&gt;the ID is saved to your .csproj file in a &lt;code&gt;&amp;lt;UserSecretsId&amp;gt;&lt;/code&gt; tag&lt;/li&gt;
&lt;li&gt;a directory named for the ID is created&lt;/li&gt;
&lt;li&gt;a &lt;code&gt;secrets.json&lt;/code&gt; file is created&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The CLI also provides us a method of adding values to our &lt;code&gt;secrets.json&lt;/code&gt; file without having to dig through our user directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet user-secrets &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;key&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;value&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Using User Secrets to auto-play our songs
&lt;/h3&gt;

&lt;p&gt;In our &lt;code&gt;LoadConfig&lt;/code&gt; method, we only have to add one line to bind our user secrets.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;IConfiguration&lt;/span&gt; &lt;span class="nf"&gt;LoadConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;builder&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;ConfigurationBuilder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddJsonFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"appsettings.json"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddCommandLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddEnvironmentVariables&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddUserSecrets&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Program&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also have to add a little logic to our &lt;code&gt;DisplaySong&lt;/code&gt; method to create our auto-play behavior.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;DisplaySong&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IConfiguration&lt;/span&gt; &lt;span class="n"&gt;config&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;userResponse&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;decade&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Decade"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;switch&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;"Nineties"&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;SongProvider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Decades&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Nineties&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"TwoThousands"&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;SongProvider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Decades&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TwoThousands&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"TwentyTens"&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;SongProvider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Decades&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TwentyTens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;SongProvider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Decades&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Eighties&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userResponse&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="s"&gt;"q"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ... existing logic remains unchanged ... after &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;counter&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"You've listened to 5 songs! Want to keep going?"&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;"(Type q to quit.)"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;userResponse&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadLine&lt;/span&gt;&lt;span class="p"&gt;()?.&lt;/span&gt;&lt;span class="nf"&gt;ToLower&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="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;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Autoplay"&lt;/span&gt;&lt;span class="p"&gt;]?.&lt;/span&gt;&lt;span class="nf"&gt;ToLower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;counter&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;userResponse&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadLine&lt;/span&gt;&lt;span class="p"&gt;()?.&lt;/span&gt;&lt;span class="nf"&gt;ToLower&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;blockquote&gt;
&lt;p&gt;These variables also come in as strings, so they carry the same warning as environment variables did above.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Adding the &lt;code&gt;"Autoplay"&lt;/code&gt; key
&lt;/h3&gt;

&lt;p&gt;Run the following command to write the &lt;code&gt;"Autoplay"&lt;/code&gt; key to our &lt;code&gt;secrets.json&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet user-secrets &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="s2"&gt;"Autoplay"&lt;/span&gt; &lt;span class="s2"&gt;"true"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can quickly check what keys are accessible in our &lt;code&gt;secrets.json&lt;/code&gt; by running the following command:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Oh no! Did you verify and see that you misspelled something? That's okay, we can remove the key using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet user-secrets remove &lt;span class="o"&gt;{&lt;/span&gt;key&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;... or, we can clear out all the keys by using:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;... and you can add the key again to correct any misspellings.&lt;/p&gt;

&lt;p&gt;And we're done! If we start up our application, now, a new song will appear on the screen every two seconds until 5 consecutive songs have played!&lt;/p&gt;

&lt;h2&gt;
  
  
  Misusing configurations
&lt;/h2&gt;

&lt;p&gt;As I previously stated in some asides, this is a wild misuse of the &lt;code&gt;ConfigurationBuilder&lt;/code&gt;, but I believe it demonstrates the ways in which you can pass data from different sources into your application.&lt;/p&gt;

&lt;p&gt;So, if this is wrong, what is the right way to use a configuration object? &lt;/p&gt;

&lt;p&gt;The most common use-cases for configurations are storing connection strings for databases, external API keys for authentication, setting logging behaviors, to turn on and off features, and configuring environment-specific variables. &lt;/p&gt;

&lt;p&gt;While we may not be using it to select the specific decade of music that you're listening to, you no longer have to look at your &lt;code&gt;Program.cs&lt;/code&gt; file and wonder how these values are making their way into the projects that you work on. &lt;/p&gt;

&lt;h2&gt;
  
  
  Using configurations on your own
&lt;/h2&gt;

&lt;p&gt;In your next project, give the &lt;code&gt;ConfigurationBuilder&lt;/code&gt; a try! A good time to think about this is in the deployment phase of your next personal project. &lt;/p&gt;

&lt;p&gt;What are the lines of code that you're changing because you're about to load the application on another machine? These are great candidates to load into an &lt;code&gt;IConfiguraiton&lt;/code&gt; object!&lt;/p&gt;




&lt;p&gt;If you're getting value out of these posts, consider subscribing using the link below to receive these posts straight to your inbox! &lt;/p&gt;

&lt;p&gt;&lt;a href="https://d782b8fa.sibforms.com/serve/MUIFAK2keDpq4jw-krst9Ki0T2Asllq4pHVH7YEaci2JN2o3H1rLOXm-4H3G3lc31swK7WFMNYjoSJqaBleHxcV0vc8EEBLLxb3HK0U59_fRRDFUaj96lZyvOSE2NiYQSi1jC_0L0Tq8wj2_OcG8PFuNsL5SH65CQh_GpSOXqV3FqTJosq6tSRV2e2mw9MSXcAx7-2c_3fY-abRi" rel="noopener noreferrer"&gt;Click here to subscribe!&lt;/a&gt;&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>learning</category>
      <category>asp</category>
      <category>configuration</category>
    </item>
    <item>
      <title>Interviewers Will Ask You About This: .NET Dependency Injection Made Simple</title>
      <dc:creator>Nolan Miller</dc:creator>
      <pubDate>Mon, 24 Feb 2025 16:21:34 +0000</pubDate>
      <link>https://forem.com/nmiller15/interviewers-will-ask-you-about-this-dependency-injection-made-simple-1ped</link>
      <guid>https://forem.com/nmiller15/interviewers-will-ask-you-about-this-dependency-injection-made-simple-1ped</guid>
      <description>&lt;p&gt;My heart rate was elevated and my hands were clenching the plush armrests of a very comfortable chair in a board room. &lt;em&gt;He knew.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;After thinking about it way too long, I'd just called a singleton a factory method in a code example that was broadcast onto one of the two flat screens on the far wall. &lt;/p&gt;

&lt;p&gt;"So, what do you know about dependency injection?"&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Strike 2.&lt;/em&gt; I remembered reading something about this when I was panic studying for this interview, but I didn't really understand it. "I've... um... never used it before, but I think I understand the concept..." &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Sigh. This is over isn't it.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Since I started teaching myself to code, one of the things that's frustrated me the most about this space, is how big all the freaking words are. Dependency Injection? What is that? What does it mean to have a dependency? What the heck is injecting it? &lt;/p&gt;

&lt;p&gt;I struggled through figuring this out so that you don't have to. The concept is not as hard as it might seem, and it can dramatically increase your code quality. If you're self-taught, this is a concept that &lt;em&gt;will&lt;/em&gt; come up in job interviews, because in any project of a reasonable size, it is probably being used. &lt;/p&gt;

&lt;p&gt;Let's dive in, so that your interview doesn't go how mine did.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a dependency?
&lt;/h2&gt;

&lt;p&gt;In short, a dependency is a piece of code that is &lt;em&gt;depended upon&lt;/em&gt; for functionality.&lt;/p&gt;

&lt;p&gt;When we talk about dependencies, we will talk about &lt;em&gt;clients&lt;/em&gt; and &lt;em&gt;services&lt;/em&gt;. The client is the class that &lt;em&gt;depends&lt;/em&gt; on something else, the class that takes the injection. The service is what is injected, it is the &lt;em&gt;dependency&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;It's not always this clean though. Often services will also have a long list of dependencies, creating a chain of interrelated classes. But, to keep things simple for now, we'll just focus on the relationship between one client and one service.&lt;/p&gt;

&lt;h3&gt;
  
  
  Real World Dependencies
&lt;/h3&gt;

&lt;p&gt;Dependencies don't only exist in your IDE. This pattern is modeled after the real world, as many concepts in object oriented programming are. &lt;/p&gt;

&lt;p&gt;If you live some distance from your workplace, it is likely that you are dependent upon a car. You are the client, and the service is your car! A dependency relationship. &lt;/p&gt;

&lt;p&gt;Let's quickly create a program that reflects this relationship. First let's create a person and give it some properties.&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;Person&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Descriptors that are related to a person&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="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="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Workplace&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="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Age&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="c1"&gt;// A constructor for our class.&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;Me&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;Age&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;age&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;Program&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// An instance of Person with my information&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;nolan&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;Person&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Nolan"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;27&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;nolan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Workplace&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Certified Angus Beef"&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, lets create a car, and use it to get to work!&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;Car&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ... Properties&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;Drive&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;destination&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;$"Arrived at &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="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;Person&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ... Properties and things&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;GoToWork&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Becuase this class needs instantiated&lt;/span&gt;
        &lt;span class="c1"&gt;// for this behavior to work, it is a &lt;/span&gt;
        &lt;span class="c1"&gt;// service that Person depends on.&lt;/span&gt;
        &lt;span class="n"&gt;Car&lt;/span&gt; &lt;span class="n"&gt;car&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;Car&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;hasArrived&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;car&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Drive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Workplace&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;hasArrived&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;"Made it to work!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is all a dependency is. Try looking at some of your own real world relationships and identifying the dependencies that you have. What people do you rely on? What possessions? etc.&lt;/p&gt;

&lt;p&gt;There's nothing wrong with relying on other people or things to accomplish goals and tasks, but it &lt;em&gt;does&lt;/em&gt; become a problem when these things we rely on are the &lt;em&gt;only&lt;/em&gt; way we know how to accomplish those goals. &lt;/p&gt;

&lt;p&gt;In this example, the only way that the &lt;code&gt;Person&lt;/code&gt; class knows how to &lt;code&gt;GoToWork&lt;/code&gt; is by using a &lt;code&gt;Car&lt;/code&gt;. We have to use this implementation of &lt;code&gt;Car&lt;/code&gt; no matter what. What if &lt;code&gt;Car&lt;/code&gt; breaks? We can't borrow a car, or get a rental? We need to introduce more flexibility into this class.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create flexibility with interfaces
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;I thought this was an article on dependency injection.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Yes. It is. But, the concept of interfaces is tightly coupled with dependency injection... 😉&lt;/p&gt;

&lt;p&gt;To solve our problem of rigidity in &lt;code&gt;GoToWork&lt;/code&gt;, let's say that at minimum we need a vehicle to get to work. I don't care what kind it is, how many wheels it has or what kind of gas it takes, I just need it to be able to drive. &lt;/p&gt;

&lt;p&gt;We can create an interface for that:&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;IVehicle&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;Drive&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;destination&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, with one tweak to our &lt;code&gt;GoToWork&lt;/code&gt; method, we begin to decrease our reliance on &lt;code&gt;Car&lt;/code&gt; specifically. &lt;/p&gt;

&lt;p&gt;For the sake of illustration, let's say that my &lt;code&gt;Car&lt;/code&gt; has broken down, I still need to get to work. So, instead I'll use my wife's SUV to get there!&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;SUV&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IVehicle&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;bool&lt;/span&gt; &lt;span class="nf"&gt;Drive&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;destination&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;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;Person&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ... Properties and things&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;GoToWork&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Using the interface we created,&lt;/span&gt;
        &lt;span class="c1"&gt;// we can add any implementation &lt;/span&gt;
        &lt;span class="c1"&gt;// of a vehicle here now.&lt;/span&gt;
        &lt;span class="n"&gt;IVehicle&lt;/span&gt; &lt;span class="n"&gt;vehicle&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;SUV&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;hasArrived&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vehicle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Drive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Workplace&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;hasArrived&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;"Made it to work!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we've achieved some flexibility, we need to address another issue. If we were to translate this &lt;code&gt;GoToWork&lt;/code&gt; method back to real life, we'd notice something strange.&lt;/p&gt;

&lt;p&gt;Every time this person tries to go to work, they're building a vehicle (and taking it back apart once they get there). &lt;/p&gt;

&lt;p&gt;Not very smart is it? &lt;/p&gt;

&lt;p&gt;&lt;em&gt;But, who cares, this isn't real life.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Well, no, but there are two programming-related reasons that we don't want to build our dependency inside our method. Single-responsibility, and efficiency.&lt;/p&gt;

&lt;p&gt;The way our code is built right now violates the single-responsibility principle. This feature of object-oriented design states that the components of our application should have &lt;em&gt;one&lt;/em&gt; responsibility. &lt;code&gt;GoToWork&lt;/code&gt;, despite the name, doesn't just &lt;code&gt;GoToWork&lt;/code&gt;. It creates an outside class instance &lt;em&gt;and&lt;/em&gt; goes to work. &lt;/p&gt;

&lt;p&gt;What if I want to create a &lt;code&gt;GoToSchool&lt;/code&gt; method? Or a &lt;code&gt;GoToTheStore&lt;/code&gt; method? I'd have to duplicate my code in every one of the methods (violating the DRY principle). Now imagine that my &lt;code&gt;Car&lt;/code&gt; breaks again, and I need to use the &lt;code&gt;SUV&lt;/code&gt; class! I need to change it in every place I create that class. &lt;/p&gt;

&lt;p&gt;It's also less efficient. Every time I need to use the &lt;code&gt;Drive&lt;/code&gt; method, I need to create a new class instance. With a small class like this, there may not be much performance overhead, but as classes get bigger and code gets more complex, this becomes an issue. What if I wanted to track the mileage on the car? Or know how many trips it took? This becomes far more complex if every time I'm using the &lt;code&gt;Car&lt;/code&gt; I create a new one.&lt;/p&gt;

&lt;p&gt;We can solve this though. You might think that we can just move the implementation into a property and instantiate it there, but we can take this one step further, by removing the creation of the instance outside of the class entirely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Injecting your first dependency
&lt;/h2&gt;

&lt;p&gt;Let's start by adjusting our &lt;code&gt;Person&lt;/code&gt; class to make sure that we have somewhere to store the dependency. We don't want our class methods to be able to adjust it, and we don't want it to be accessible outside of our class either, so we'll use a &lt;code&gt;private readonly&lt;/code&gt; field.&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;Person&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;IVehicle&lt;/span&gt; &lt;span class="n"&gt;_vehicle&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Other properties and things&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now... we inject. &lt;/p&gt;

&lt;p&gt;We're going to create a constructor that has &lt;code&gt;IVehicle&lt;/code&gt; as a parameter, then we assign this parameter to our new field.&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;Person&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;IVehicle&lt;/span&gt; &lt;span class="n"&gt;_vehicle&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Other properties and things&lt;/span&gt;

    &lt;span class="c1"&gt;// Inject the IVehicle through this&lt;/span&gt;
    &lt;span class="c1"&gt;// constructor&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IVehicle&lt;/span&gt; &lt;span class="n"&gt;vehicle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_vehicle&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vehicle&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;Now take a look at how this simplifies our &lt;code&gt;GoToWork&lt;/code&gt; method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Person&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;IVehicle&lt;/span&gt; &lt;span class="n"&gt;_vehicle&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Other properties and things&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IVehicle&lt;/span&gt; &lt;span class="n"&gt;vehicle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_vehicle&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vehicle&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;GoToWork&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// This will now work with any implementation&lt;/span&gt;
        &lt;span class="c1"&gt;// of IVehicle!&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;hasArrived&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_vehicle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Drive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Workplace&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;hasArrived&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;"Made it to work!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The reason the &lt;code&gt;GoToWork&lt;/code&gt; method is simplified is because it is no longer responsible for &lt;em&gt;choosing an implementation&lt;/em&gt; or &lt;em&gt;creating an instance&lt;/em&gt; of &lt;code&gt;IVehicle&lt;/code&gt;. That now takes place outside of the &lt;code&gt;Person&lt;/code&gt; class entirely!&lt;/p&gt;

&lt;p&gt;Take a look at how we might call the &lt;code&gt;GoToWork&lt;/code&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Program&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Pick and instantiate an IVehicle&lt;/span&gt;
        &lt;span class="n"&gt;IVehicle&lt;/span&gt; &lt;span class="n"&gt;car&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;Car&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;nolan&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;Person&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;car&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;nolan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Workplace&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Certified Angus Beef"&lt;/span&gt;

        &lt;span class="n"&gt;nolan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GoToWork&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;This is the basic concept of dependency injection. Notice that our &lt;code&gt;Main&lt;/code&gt; method actually got a bit more complex. While the design pattern has its advantages, like testability, separation of concerns and single-responsibility, one of the tradeoffs is that we have made our code a bit more complex to work with.&lt;/p&gt;

&lt;p&gt;Luckily for us, we can take advantage of all the benefits of this pattern and sidestep some of this complexity by letting a DI framework do the work of injecting the instances for us. &lt;/p&gt;

&lt;h2&gt;
  
  
  Inversion of control with DI containers
&lt;/h2&gt;

&lt;p&gt;There are many DI frameworks, but the one we'll go over today is the DI container that's built into ASP.NET. No matter the framework that you're using, the goal is the same: automatically provide services to clients that are generated by your framework. Put simply, to inject your dependencies.&lt;/p&gt;

&lt;p&gt;The concept is called &lt;em&gt;Inversion of Control&lt;/em&gt;. Instead of the client controlling the dependencies that it has, the control structure is flipped. The framework is given control over the dependencies and the client is allowed to use it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;All these "i" terms...&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;It is important to make a distinction between the terms **interface&lt;/em&gt;&lt;em&gt;, **implementation&lt;/em&gt;&lt;em&gt;, and **instance&lt;/em&gt;*. Naturally... they all had to start with "i".&lt;/p&gt;

&lt;p&gt;An &lt;strong&gt;interface&lt;/strong&gt; is a set of specifications for class definitions. A contract.&lt;br&gt;
An &lt;strong&gt;implementation&lt;/strong&gt; is a definition of a class that adheres to that interface or contract.&lt;br&gt;
An &lt;strong&gt;instance&lt;/strong&gt;, is the usable object with property values and behavior that represents a real-world object. The class definition in actual use somewhere.*&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Just remember: Create **instances&lt;/em&gt;* from &lt;strong&gt;implementations&lt;/strong&gt; of &lt;strong&gt;interfaces&lt;/strong&gt;.*&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When we're using a DI container, we have to bind (either manually or automatically) our interface requests to an instance that implements it. When you define a relationship between an interface and an implementation to the DI container, it will fulfill any request for the interface with the bound implementation. &lt;/p&gt;

&lt;p&gt;You can also explicitly attach implementations without an interface. When this is done, the framework will respond directly to requests for that implementation with the implementation.&lt;/p&gt;

&lt;p&gt;In the following example, we will look at how to bind interfaces and implementations as this is the most common pattern that you will see.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bind services to your DI container
&lt;/h2&gt;

&lt;p&gt;To illustrate how to bind services to your DI container, we will start in the context of an ASP.NET MVC application. The main method of this creates a web app builder. Taking advantage of boilerplate middleware, the controllers and views are collected and instantiated by the framework. &lt;/p&gt;

&lt;p&gt;Let's take simple web application that displays facts. It has a &lt;code&gt;FactsController&lt;/code&gt; with a few routes and related Views. Let's create this controller now.&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;FactsController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&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="nf"&gt;FactsController&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="n"&gt;IActionResult&lt;/span&gt; &lt;span class="nf"&gt;Index&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;View&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will take for granted that we have a view for &lt;code&gt;Index&lt;/code&gt; and that we have a &lt;code&gt;FactsViewModel&lt;/code&gt; that will hold a &lt;code&gt;Fact&lt;/code&gt; string that we can display. &lt;/p&gt;

&lt;p&gt;Now, we want to generate random facts. We could put all of that logic here in a private method, or in one of our action methods, but that would violate the single responsibility principle and make our project much harder to maintain.&lt;/p&gt;

&lt;p&gt;So, let's inject a service to do that for us!&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;FactsController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Controller&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;IFactGenerator&lt;/span&gt; &lt;span class="n"&gt;_factGenerator&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;FactsController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IFactGenerator&lt;/span&gt; &lt;span class="n"&gt;factGenerator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;_factGenerator&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;factGenerator&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="n"&gt;IActionResult&lt;/span&gt; &lt;span class="nf"&gt;Index&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;viewModel&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;FactsViewModel&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// The Generate method takes an enum value that lets&lt;/span&gt;
    &lt;span class="c1"&gt;//   us choose the category of fact that is generated.&lt;/span&gt;
    &lt;span class="c1"&gt;// The Fact property of our FactsViewModel is then displayed&lt;/span&gt;
    &lt;span class="c1"&gt;//   in the Fact.cshtml view.&lt;/span&gt;
    &lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fact&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_factGenerator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FactTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Animal&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;View&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;viewModel&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;This looks very similar to what we did above with our manual dependency injection. We defined a field &lt;code&gt;_factGenerator&lt;/code&gt;, injected the interface through the constructor, and then we accessed the method of our service from within our client: the &lt;code&gt;.Generate(FactTypes)&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;However, this &lt;em&gt;won't&lt;/em&gt; work yet. &lt;/p&gt;

&lt;p&gt;We still need to bind our service within our DI container. We do this by adding a service to the service collection on our &lt;code&gt;WebApplicationBuilder&lt;/code&gt;. So head over to &lt;code&gt;Program.cs&lt;/code&gt; and add the following line.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;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;// AddSingleton&amp;lt;TInterface, TImplmentation&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;// This line creates a singleton instance of a service.&lt;/span&gt;
    &lt;span class="c1"&gt;// Whenever this interface is called, the instance created by&lt;/span&gt;
    &lt;span class="c1"&gt;// the builder will be delivered.&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;IFactGenerator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FactGenerator&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// This is added by the template&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;AddControllersWithViews&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;Now, if we boot up our application and navigate to &lt;code&gt;/Facts&lt;/code&gt; we should see the output of the &lt;code&gt;FactGenerator&lt;/code&gt;. Using the &lt;code&gt;.AddSingleton&lt;/code&gt; method, we have told the DI container that wraps our application, "Whenever a class that you build requests an &lt;code&gt;IFactGenerator&lt;/code&gt;, give them the instance of &lt;code&gt;FactGenerator&lt;/code&gt; that you've created."&lt;/p&gt;

&lt;h2&gt;
  
  
  Deciding what instance to be delivered using binding
&lt;/h2&gt;

&lt;p&gt;In addition to the &lt;code&gt;.AddSingleton()&lt;/code&gt; method, we can also make decisions about which &lt;em&gt;instance&lt;/em&gt; of our implementation is injected by our DI container. &lt;/p&gt;

&lt;p&gt;We can use singletons, transients, or we can scope our instances. Here's how each of these behave:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;.AddSingleton()&lt;/code&gt; - Only one instance of this type will be created. Every request for an implementation will be fulfilled with the same instance.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.AddTransient()&lt;/code&gt; - For every request for a service, a new instance will be created to fulfil it. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.AddScoped()&lt;/code&gt; - For every request made of the application (not the DI container) a new instance will be created. The same instance will be used for the duration of the request.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To illustrate how this works, I've adjusted the &lt;code&gt;FactGenerator&lt;/code&gt; and the &lt;code&gt;FactController&lt;/code&gt; to show off the differences between the binding types.&lt;/p&gt;

&lt;p&gt;In my &lt;code&gt;FactGenerator&lt;/code&gt;, I've made it so that each instance can only generate one unique fact. After the &lt;code&gt;.GetFact&lt;/code&gt; method has been used, it will return the initially generated fact. This will give us a very clear look at the instance lifetimes.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;FactController&lt;/code&gt;, I've created Action Methods for &lt;code&gt;Singleton&lt;/code&gt;, &lt;code&gt;Transient&lt;/code&gt; and &lt;code&gt;Scoped&lt;/code&gt;. These correspond to more or less identical views that all use the &lt;code&gt;FactsViewModel&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To get the facts for these views, I've bound and injected 6 different fact generators, two of each binding type. With two of each, we can explore the differences in lifetime between transients, singletons, and scoped.&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;FactsController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Controller&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;TransientRandomFactGenerator&lt;/span&gt; &lt;span class="n"&gt;_transientRandomFactGenerator1&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;TransientRandomFactGenerator&lt;/span&gt; &lt;span class="n"&gt;_transientRandomFactGenerator2&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;SingletonRandomFactGenerator&lt;/span&gt; &lt;span class="n"&gt;_singletonRandomFactGenerator1&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;SingletonRandomFactGenerator&lt;/span&gt; &lt;span class="n"&gt;_singletonRandomFactGenerator2&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;ScopedRandomFactGenerator&lt;/span&gt; &lt;span class="n"&gt;_scopedRandomFactGenerator1&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;ScopedRandomFactGenerator&lt;/span&gt; &lt;span class="n"&gt;_scopedRandomFactGenerator2&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;FactsController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;TransientRandomFactGenerator&lt;/span&gt; &lt;span class="n"&gt;transientRandomFactGenerator1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;TransientRandomFactGenerator&lt;/span&gt; &lt;span class="n"&gt;transientRandomFactGenerator2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;SingletonRandomFactGenerator&lt;/span&gt; &lt;span class="n"&gt;singletonRandomFactGenerator1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;SingletonRandomFactGenerator&lt;/span&gt; &lt;span class="n"&gt;singletonRandomFactGenerator2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;ScopedRandomFactGenerator&lt;/span&gt; &lt;span class="n"&gt;scopedRandomFactGenerator1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;ScopedRandomFactGenerator&lt;/span&gt; &lt;span class="n"&gt;scopedRandomFactGenerator2&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_transientRandomFactGenerator1&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;transientRandomFactGenerator1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;_transientRandomFactGenerator2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;transientRandomFactGenerator2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;_singletonRandomFactGenerator1&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;singletonRandomFactGenerator1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;_singletonRandomFactGenerator2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;singletonRandomFactGenerator2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;_scopedRandomFactGenerator1&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scopedRandomFactGenerator1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;_scopedRandomFactGenerator2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scopedRandomFactGenerator2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's take a look at how we can call these generators from our action methods.&lt;/p&gt;

&lt;h3&gt;
  
  
  Singleton binding
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Program.cs&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;SingletonRandomFactGenerator&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// FactsController.cs&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;Singleton&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;viewModel&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;FactsViewModel&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;fact1&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_singletonRandomFactGenerator1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetFact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FactTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Space&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;fact2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_singletonRandomFactGenerator2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetFact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FactTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Animal&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fact&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fact1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fact2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fact2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;ViewData&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Title"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Singleton"&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;View&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When we bind our &lt;code&gt;SingletonRandomFactGenerator&lt;/code&gt; and inject it twice, once for each fact. What do you think the output will be? &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%2F6rwmhfn41ma2ipe2lwqc.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%2F6rwmhfn41ma2ipe2lwqc.png" alt="Singleton Facts" width="622" height="263"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We got the same fact back! Why is this?&lt;/p&gt;

&lt;p&gt;When we bound the SingletonRandomFactGenerator implementation to our builder &lt;em&gt;as&lt;/em&gt; a singleton, only one instance is created. We called for an injection twice in our controller and the same instance was delivered to both references. So, it didn't matter that we called the &lt;code&gt;GetFact&lt;/code&gt; method again on our second reference, we still got the same fact back since the &lt;code&gt;GetFact&lt;/code&gt; method only returns one unique fact.&lt;/p&gt;

&lt;p&gt;Let's see how this is different with a transient binding.&lt;/p&gt;

&lt;h3&gt;
  
  
  Transient binding
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Program.cs&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;TransientRandomFactGenerator&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// FactsController.cs&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;Transient&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;viewModel&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;FactsViewModel&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;fact1&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_transientRandomFactGenerator1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetFact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FactTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Space&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;fact2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_transientRandomFactGenerator2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetFact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FactTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Animal&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fact&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fact1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fact2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fact2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;ViewData&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Title"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Transient"&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;View&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;viewModel&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 example, we are calling for two injections of &lt;code&gt;TransientRandomFactGenerator&lt;/code&gt;, just as we did with &lt;code&gt;SingletonRandomFactGenerator&lt;/code&gt;. And this is the output that we get:&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%2F7pvgal43o0mj4e3v30ra.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%2F7pvgal43o0mj4e3v30ra.png" alt="Transient Facts" width="793" height="264"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Two different facts! &lt;/p&gt;

&lt;p&gt;Since we used &lt;code&gt;AddTransient&lt;/code&gt;, when we call for two different injections of the same implementation, two &lt;em&gt;separate instances&lt;/em&gt; are injected. So when we call &lt;code&gt;GetFact&lt;/code&gt; on the first, it doesn't affect the second! &lt;/p&gt;

&lt;p&gt;Now that we understand the difference between transient and singleton, let tackle scoped, which is a little more subtle.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scoped binding
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Program.cs&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;ScopedRandomFactGenerator&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// FactController.cs&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;Scoped&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;viewModel&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;FactsViewModel&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;fact1&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_scopedRandomFactGenerator1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetFact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FactTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Space&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;fact2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_scopedRandomFactGenerator2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetFact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FactTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Animal&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fact&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fact1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fact2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fact2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;ViewData&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Title"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Scoped"&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;View&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;viewModel&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;With this action method set up the same as the other two, what do you expect will happen? &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%2F6rwmhfn41ma2ipe2lwqc.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%2F6rwmhfn41ma2ipe2lwqc.png" alt="Scoped Facts" width="622" height="263"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hm... the same fact? &lt;em&gt;So... it's a singleton?&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;It is. But, only for a while. &lt;/p&gt;

&lt;p&gt;When we called for two injections of the generator here, it built them upon request. Since the calls for both of the injections happened on the same request, we got the same instance injected for both, just like a singleton.&lt;/p&gt;

&lt;p&gt;We can create a second request by refreshing the page.&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%2Ftyuki6e34fdix2lxfdn8.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%2Ftyuki6e34fdix2lxfdn8.png" alt="Scoped Facts Refreshed" width="681" height="267"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After our refresh, we get a new fact! This is due to the fact that once we entered a new request, a new instance was generated and injected. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;This still seems like it's just a singleton.&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;Yep, I get it. They're very similar. But, watch what happens if I click back over the the singleton.&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%2F9zr2tt7q7nya3mq3syxl.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%2F9zr2tt7q7nya3mq3syxl.png" alt="Singleton Facts Refreshed" width="645" height="269"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The same fact as the first time we loaded the page!&lt;/p&gt;

&lt;p&gt;The singleton binding doesn't care that we've made a separate request. It is still delivering that exact same instance to our controller no matter what.&lt;/p&gt;

&lt;p&gt;If I click back over to see the scoped binding, we will get yet another random fact! &lt;/p&gt;

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

&lt;p&gt;Now you don't have to be nervous like me in your next interview. If you've never worked with dependency injection before, take an afternoon and create a small project like this one to get a handle on some of the concepts. &lt;/p&gt;

&lt;p&gt;I would suspect that a great majority of codebases use dependency injection in some form or another, and if you're self-taught it's a topic that doesn't seem to come up in the learning paths online. &lt;/p&gt;

&lt;p&gt;Thanks for taking your time to read this, and it is my sincere hope that it makes your life and coding journey a bit easier than mine was! &lt;/p&gt;

&lt;p&gt;If you found value in this, share it with a friend who wants to learn about dependency injection! &lt;/p&gt;




&lt;p&gt;Interested in getting these blog posts direct to your inbox? &lt;/p&gt;

&lt;p&gt;&lt;a href="https://d782b8fa.sibforms.com/serve/MUIFAK2keDpq4jw-krst9Ki0T2Asllq4pHVH7YEaci2JN2o3H1rLOXm-4H3G3lc31swK7WFMNYjoSJqaBleHxcV0vc8EEBLLxb3HK0U59_fRRDFUaj96lZyvOSE2NiYQSi1jC_0L0Tq8wj2_OcG8PFuNsL5SH65CQh_GpSOXqV3FqTJosq6tSRV2e2mw9MSXcAx7-2c_3fY-abRi" rel="noopener noreferrer"&gt;Click here to sign up!&lt;/a&gt;&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>oop</category>
      <category>learning</category>
    </item>
    <item>
      <title>Cure Depression with Software Development</title>
      <dc:creator>Nolan Miller</dc:creator>
      <pubDate>Wed, 19 Feb 2025 17:56:41 +0000</pubDate>
      <link>https://forem.com/nmiller15/cure-depression-with-software-development-5a8k</link>
      <guid>https://forem.com/nmiller15/cure-depression-with-software-development-5a8k</guid>
      <description>&lt;p&gt;Quotes in this post are courtesy of Liam Galvin in his article, &lt;a href="https://lia.mg/posts/despair-driven-development/?utm_source=pocket_shared" rel="noopener noreferrer"&gt;Despair-Driven Development: Harnessing Malaise for Effective Software Engineering&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Anxiety and depression are at all time high levels this generation, and rather than pointing fingers at causes, Liam Galvin points to a solution: develop more software. &lt;/p&gt;

&lt;p&gt;No joke! Liam's outlook, while bleak, is that developing software and achieving the flow state is the only escape from a reality filled with despair for some.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For many despair-driven developers, flow state is the closest thing to peace. It is not joy in the traditional sense but an absence of suffering, a momentary relief from the crushing weight of existence. While the world outside may be collapsing, in the confines of a well-structured function or an elegant algorithm, there is clarity, purpose, and even a strange form of tranquility.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Liam's cheeky "Despair-Driven Development" model champions pragmatism a functionality. He says that this is the model that those with steep requirements and little support fall into, and in some ways, it makes them better at their jobs.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In a despair-driven mindset, there is no time for over-engineering or gold-plating solutions. The key question shifts from “Is this the best way?” to “Will this work well enough to avoid catastrophe?” The result is a stripped-down, functional approach that prioritizes what actually matters over idealized abstractions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There's something to be taken here, even if you aren't as ruthless as Liam.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A snatched moment in the quiet focus of a well-structured function can provide something resembling peace. And sometimes, that is enough.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>via</category>
    </item>
    <item>
      <title>Do The Work That Needs Done</title>
      <dc:creator>Nolan Miller</dc:creator>
      <pubDate>Tue, 11 Feb 2025 14:51:06 +0000</pubDate>
      <link>https://forem.com/nmiller15/do-the-work-that-needs-done-2ph2</link>
      <guid>https://forem.com/nmiller15/do-the-work-that-needs-done-2ph2</guid>
      <description>&lt;p&gt;Quotes in this post courtesy of BrainBun Labs in the article, &lt;a href="https://www.brainbun.com/blog/i-conditioned-myself-to-fail?utm_source=pocket_shared" rel="noopener noreferrer"&gt;I conditioned myself to fail&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This article from BrainBun hit a little too close to home. I want to start a business, or sell a product, or something. But, I know that there's something that's holding me back. I think that it might be what the author talks about here.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Today I think I finally figured out what’s causing it.&lt;/p&gt;

&lt;p&gt;I became an information junkie over the years.&lt;/p&gt;

&lt;p&gt;That’s right, I’m addicted to information. I get my dopamine from feedback, from new information.&lt;/p&gt;

&lt;p&gt;When I’m building something, that information is the thing coming to life in front of my eyes, every new button etc is awesome. I can see the changes in the UI from the code I’m writing.&lt;/p&gt;

&lt;p&gt;But then when I launch, I either don’t get much feedback at all, or I get a lot of feedback for a day, which then dies down completely after the launch.&lt;/p&gt;

&lt;p&gt;And I can’t find the motivation to get back to work.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For me, I will quickly launch myself into a project, or a new technology to learn, and then my focus changes when the work actually gets hard. I tell myself, "Well this actually isn't pushing the needle." But, that's not true always. &lt;/p&gt;

&lt;p&gt;But, I also avoid doing the hard work by doing the opposite too. I'm in the middle of a larger project that I will use as an excuse to put off working on something that would actually start my business.&lt;/p&gt;

&lt;p&gt;The constant mantra, is "I need to learn more about X to do that." It is the first thing that I think when I get a piece of business advice, but it would be better to take Noah Kagan's advice "Now, not how."&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I partly blame the algorithmic feeds a la Twitter/X. It’s a lot easier to get your dopamine from reading than it is from building.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Take action. Be naive. Look stupid. Make mistakes.&lt;/p&gt;

</description>
      <category>via</category>
      <category>startup</category>
      <category>productivity</category>
      <category>career</category>
    </item>
    <item>
      <title>Can we add AI to that?</title>
      <dc:creator>Nolan Miller</dc:creator>
      <pubDate>Mon, 10 Feb 2025 18:19:13 +0000</pubDate>
      <link>https://forem.com/nmiller15/can-we-add-ai-to-that-pa6</link>
      <guid>https://forem.com/nmiller15/can-we-add-ai-to-that-pa6</guid>
      <description>&lt;p&gt;Quotes in this article are courtesy of Lawrence Jones in his article, &lt;a href="https://blog.lawrencejones.dev/ai-mvp/index.html" rel="noopener noreferrer"&gt;Beyond the AI MVP: What it really takes&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A little over a month ago, I was in a conference talk about the value of adding AI to products. The speaker asked the room, "Who has been asked to incorporate AI into a product you've already developed in the past year," and the amount of hands up around the room was staggering. &lt;/p&gt;

&lt;p&gt;While it may seem simple on the face of it to load up a model and incorporate a chat interface in your app, the software development lifecycle around AI is much different than traditional software. &lt;/p&gt;

&lt;p&gt;Lawrence Jones argues that there are many challenges that you don't see up front. He points out that you need robust test suites, hefty ai-integrated programs to evaluate ai responses, a test runner, and hosting strategies to keep costs manageable. On top of all of this, the languages of many of the frameworks is in the way:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Honestly, writing the tests themselves is the easy bit! Almost all AI tools and frameworks are written in Python, reflecting the origins of AI in the research teams who built the models and the machine-learning community who first adopted them.&lt;/p&gt;

&lt;p&gt;But most product teams don’t use Python, which means you need to create a lot of these tools from scratch. That’s big undertaking, and almost no one is talking about how to integrate this stuff into a normal software development lifecycle.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The biggest issue with AI is what Jones calls the "Deceptive MVP." Have you built a basic chat interface with OpenAI's API? It's not all that difficult or complex to do, and if you're using a framework you're familiar with, you could probably piece something together in an afternoon. But, once you begin adding requirements for this application, and expecting it to behave in deterministic(-ish) ways, you're going to run into issues.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You start iterating on your MVP, trying to improve it. But as you add complexity, the system becomes increasingly unpredictable. You’re making changes based on vibes, improving some edge cases while (invisibly) breaking others.&lt;/p&gt;

&lt;p&gt;This is the stage 90% of companies building AI are in. You can even see it in FANG: the AI features Google have added to GCP feel very much like an engineers first attempt to use an LLM in a product, spitting out terrible SQL suggestions in BigQuery. Apple’s message summarisation features cross-pollinating between messages and providing horribly inaccurate headlines is another.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Adding AI to an application is not just a peel-and-stick solution that will dramatically increase the impact of your product. While it may be easy to implement, if you're making any meaningful measurements of the efficacy of your product, it will be much, much, much more difficult.&lt;/p&gt;

&lt;p&gt;Adding the connection to an API, or downloading and hosting a model for your codebase to interact with is the easiest part of the product development stage. Brainstorming ways to leverage this technology in a &lt;em&gt;meaningful&lt;/em&gt; way, ensuring that it performs tasks &lt;em&gt;reliably&lt;/em&gt;, and setting up systems to &lt;em&gt;monitor&lt;/em&gt; the efficacy of your product are where your time is going to be spent. So, before you think about building out your AI side-project, thinking that you'll be able to turn this into the next big thing, make sure to evaluate the massive hidden costs first.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The companies that will succeed with AI won’t be the ones with the biggest budgets, access to the latest models, or even the most ML expertise. They’ll be the ones that invest in understanding their systems, that build the tools to measure and improve them, and that take the time to do things right.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>via</category>
      <category>ai</category>
      <category>product</category>
      <category>mvp</category>
    </item>
  </channel>
</rss>
