<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Kevin Griffin @ #Shedquarters</title>
    <description>The latest articles on DEV Community by Kevin Griffin @ #Shedquarters (@1kevgriff).</description>
    <link>https://dev.to/1kevgriff</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%2F388826%2Fae881ea3-6b0c-4414-bf19-810770853757.jpg</url>
      <title>DEV Community: Kevin Griffin @ #Shedquarters</title>
      <link>https://dev.to/1kevgriff</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/1kevgriff"/>
    <language>en</language>
    <item>
      <title>HttpContext Issues with Azure SignalR Service</title>
      <dc:creator>Kevin Griffin @ #Shedquarters</dc:creator>
      <pubDate>Tue, 12 Dec 2023 08:00:00 +0000</pubDate>
      <link>https://dev.to/1kevgriff/httpcontext-issues-with-azure-signalr-service-21d0</link>
      <guid>https://dev.to/1kevgriff/httpcontext-issues-with-azure-signalr-service-21d0</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This is my entry for this years &lt;a href="https://www.csadvent.christmas/"&gt;CS Advent&lt;/a&gt;.  Take a moment to go check out the other great entries!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Last week, the team and I were migrating an application built with ASP.NET Core and SignalR to use the Azure SignalR Service.  The migration was pretty straight forward, but we ran into an issue with the &lt;strong&gt;HttpContext&lt;/strong&gt; when using the Azure SignalR Service.&lt;/p&gt;

&lt;p&gt;When a normal SignalR integration is running under an ASP.NET host, you will typically have access to the &lt;strong&gt;HttpContext&lt;/strong&gt; for the SignalR request.  This is best done by injecting &lt;strong&gt;IHttpContextAccessor&lt;/strong&gt; into your &lt;strong&gt;Hub&lt;/strong&gt; class.&lt;/p&gt;

&lt;p&gt;We wrote a bit of code that needed to look at the HttpContext to pull some information from a cookie. In normal operation, this code worked fantastically and it served us well for YEARS.&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;SignalRHub&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Hub&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;IHttpContextAccessor&lt;/span&gt; &lt;span class="n"&gt;_httpContextAccessor&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;SignalRHub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IHttpContextAccessor&lt;/span&gt; &lt;span class="n"&gt;httpContextAccessor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_httpContextAccessor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;httpContextAccessor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;SendMessage&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;message&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;httpContext&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_httpContextAccessor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HttpContext&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// look up cookie tzInformation&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;tzInformation&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;httpContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Cookies&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"tzInformation"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

        &lt;span class="c1"&gt;// do something with tzInformation&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 is a bit of problem now that we migrated this code to Azure SignalR Service. The &lt;strong&gt;IHttpContextAccessor&lt;/strong&gt; is still injected into the &lt;strong&gt;Hub&lt;/strong&gt; class, but it won't have the same information you'd have in a normal SignalR integration.&lt;/p&gt;

&lt;p&gt;If you think about it for a moment, or &lt;a href="https://github.com/dotnet/aspnetcore/issues/12535"&gt;read this Github issue from 2019&lt;/a&gt;, you'll realize that it makes sense.  The HttpContext is from a connection between the client and the SignalR. When Azure SignalR Service is used, the hub is still on your server, but the connection is between the client and the Azure SignalR Service.  The Azure SignalR Service then forwards the messages to your hub.  &lt;/p&gt;

&lt;h2&gt;
  
  
  What's a better approach?
&lt;/h2&gt;

&lt;p&gt;The primary mistake we made was assuming the state was available when it wasn't.  The better approach is to pass the information you need from the client to the hub.  In our case, we needed the timezone information from the client.  We could have passed that information as a parameter to the &lt;strong&gt;SendMessage&lt;/strong&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;SignalRHub&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Hub&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;SendMessage&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;message&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;tzInformation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// do something with tzInformation&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;signalR&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;HubConnectionBuilder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;withUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/signalr&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="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;sendMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tzInformation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;America/New_York&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SendMessage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;tzInformation&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What about Identity?
&lt;/h2&gt;

&lt;p&gt;One of the cool things that Azure SignalR Service will do for you is it will pass along any IPrincipal information that is set on the HttpContext.  This is great if you are using Identity and want to know who the user is.  You can use the &lt;strong&gt;Context.User&lt;/strong&gt; property to get the user information.&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;SignalRHub&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Hub&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;SendMessage&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;message&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;user&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;User&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="c1"&gt;// do something with user&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;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;If you've found yourself here because of a Google search, I hope you have a little bit of resolve now.  Maybe if you're looking for more SignalR information, take a look at my course, &lt;a href="https://signalrmastery.com"&gt;SignalR Mastery&lt;/a&gt;.  It's a great way to learn SignalR and it's on sale for the holidays!  If you're looking for more information on Azure SignalR Service, check out the &lt;a href="https://docs.microsoft.com/en-us/azure/azure-signalr/"&gt;Azure SignalR Service documentation&lt;/a&gt;.  &lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>signalr</category>
      <category>azure</category>
    </item>
    <item>
      <title>Rapid Project Upgrades with the .NET Upgrade Assistant</title>
      <dc:creator>Kevin Griffin @ #Shedquarters</dc:creator>
      <pubDate>Wed, 08 Dec 2021 08:00:00 +0000</pubDate>
      <link>https://dev.to/1kevgriff/rapid-project-upgrades-with-the-net-upgrade-assistant-4o65</link>
      <guid>https://dev.to/1kevgriff/rapid-project-upgrades-with-the-net-upgrade-assistant-4o65</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This is my yearly submission for &lt;a href="https://www.csadvent.christmas"&gt;CS Advent 2021&lt;/a&gt;!  Please take a moment to check out all the other great submissions from folks in the community.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Quick history
&lt;/h2&gt;

&lt;p&gt;Let's rewind back a couple weeks.  I was maintaining a .NET Core 3.1 Web Application.  This particular app had been on quite the journey!  It started life in .NET Framework 4.6 (after I dabbled with the idea of writing the app in node.js, whew I dodged a bullet with that one).  Eventually, it was migrated to .NET Core 1.1.  Then .NET Core 2.2. And then .NET Core 3.1 where it's been since about two weeks ago.&lt;/p&gt;

&lt;p&gt;I had skipped the jump to .NET 5 partially out of laziness, but also out of concern.  This application had grown a bit in complexity and moving pieces, so I was wary to put the effort into upgrading it to the latest bits.  And .NET Core 3.1 was the LTS (long term service) version of .NET, so I wasn't in a huge hurry to move forward.&lt;/p&gt;

&lt;h2&gt;
  
  
  .NET 6 Launch
&lt;/h2&gt;

&lt;p&gt;I knew that I wanted to move this application to .NET 6, as it would be the new LTS version, and I was foregoing several dependency updates.  In particular, there was one dependency that was still based on .NET Framework that was giving me concern.  It never made the jump to .NET Standard, so I worried about future compatibility.  &lt;/p&gt;

&lt;p&gt;It was during the amazing Visual Studio 2021 launch video, I saw mention of the &lt;a href="https://dotnet.microsoft.com/platform/upgrade-assistant"&gt;dotnet upgrade assistant&lt;/a&gt;.  Now - I feel like a fool because this tool has been around for a while, but it was getting an update to support .NET 6.&lt;/p&gt;

&lt;p&gt;Maybe this was the tool that would help us go live with .NET 6?&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started with Upgrade Assistant
&lt;/h2&gt;

&lt;p&gt;All tools should be as straight forward to install as the .NET Upgrade Assistant.  We'll assume you already have the .NET 6 SDK and Runtimes installed on your machine.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet tool &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; upgrade-assistant
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After a moment, you'll have all the tools and a new command &lt;code&gt;upgrade-assistant&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Analysis
&lt;/h3&gt;

&lt;p&gt;If you run the command &lt;code&gt;upgrade-assistant analyze [.sln or .csproj]&lt;/code&gt;, you will be provided with a guided path of what an upgrade would look like.&lt;/p&gt;

&lt;p&gt;This involves a couple things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What TFM (Target Framework) should be used for the project?&lt;/li&gt;
&lt;li&gt;Do any of the project's dependencies need to be updated?&lt;/li&gt;
&lt;li&gt;Are there significant code changes that need to be made to support the upgrade?&lt;/li&gt;
&lt;li&gt;And more!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For my .NET 3.1 project, there were a couple small changes to some of my ASP.NET Core Controllers - but there wasn't a significant code change.&lt;/p&gt;

&lt;p&gt;I had another test project that I had taken from .NET Framework 4.6 to .NET Core 6.  This one was a concern, because things such as ASP.NET Identity had radically changed.  You could not do the upgrade without breaking the code.&lt;/p&gt;

&lt;p&gt;In all of these cases, the upgrade assistant will tell you what needs to be done and make as many changes it can.&lt;/p&gt;

&lt;h3&gt;
  
  
  Upgrade
&lt;/h3&gt;

&lt;p&gt;If you do the analysis step, then the upgrade is basically the same thing except you're provided an option to skip the step or perform the action.&lt;/p&gt;

&lt;p&gt;For example, the first step is to Backup all of the projects and code being worked on.  Since I do all of my work in Git branches, I skipped this step because source control.  I recommend you do the same.&lt;/p&gt;

&lt;p&gt;There is also an option to provide more detail on each step.  If you're not sure if the step will be expensive or cause a break your code, the upgrade assistant will tell you.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--X2eb2rFG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yg3pjocspf78go4zk1xp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--X2eb2rFG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yg3pjocspf78go4zk1xp.png" alt="Upgrade Assistant" width="880" height="599"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Go live time!
&lt;/h2&gt;

&lt;p&gt;Here was the funny part - my upgrade process compiled perfectly the first time.&lt;/p&gt;

&lt;p&gt;And that's scary.&lt;/p&gt;

&lt;p&gt;We went through the proper motions for testing, and everything worked great.  The application was a bit faster, and the memory usage decreased.&lt;/p&gt;

&lt;p&gt;I was really not looking forward to upgrading the project, but the upgrade assistant made it a breeze! &lt;/p&gt;

&lt;h1&gt;
  
  
  Questions Answered
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Does this handle solutions or just single projects?
&lt;/h2&gt;

&lt;p&gt;When I ran the upgrade assistant against my primary project (with ~20 projects in it), the upgrade assistant asked for to designate the entrypoint for the application.&lt;/p&gt;

&lt;p&gt;From there, the upgrade assistant looked at all the dependencies, their dependencies, and graphed the best way to tackle the upgrade.&lt;/p&gt;

&lt;p&gt;I ended up repeating this process two more times because I had additional entrypoints for the solution (MVC application, an Azure Functions application, and a console service application).&lt;/p&gt;

&lt;h2&gt;
  
  
  What .NET langages does the Upgrade Assistant support?
&lt;/h2&gt;

&lt;p&gt;C# and Visual Basic are fully supported!&lt;/p&gt;

&lt;h2&gt;
  
  
  What else can Upgrade Assistant help with?
&lt;/h2&gt;

&lt;p&gt;I haven't played around with all of the configurations that the .NET Upgrade Assistant can help you with, but according to the website, the Upgrade Assistant can help with the following project types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ASP.NET MVC&lt;/li&gt;
&lt;li&gt;Windows Forms&lt;/li&gt;
&lt;li&gt;Windows Presentation Foundation (WPF)&lt;/li&gt;
&lt;li&gt;Console applications&lt;/li&gt;
&lt;li&gt;Class Libraries&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What about other types of projects?
&lt;/h2&gt;

&lt;p&gt;You'll probably notice ASP.NET Web Forms is missing from the above list, and that's on the &lt;a href="https://github.com/dotnet/upgrade-assistant/blob/main/docs/roadmap.md"&gt;roadmap&lt;/a&gt; for the project along with many other features!&lt;/p&gt;

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

&lt;p&gt;I wasn't looking forward to the upgrade path for my applications, mainly because I didn't want to have to edit all the project files and deal with incremental issues that might have popped up.&lt;/p&gt;

&lt;p&gt;The .NET Upgrade Assistant was an amazing tool that helped us get our application into production with .NET 6 easily and quickly.  I'm hoping if you're on the fence about making the upgrade, take the time to check out this tool!&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>aspnetcore</category>
      <category>upgrade</category>
    </item>
    <item>
      <title>Building a Twitch Badge For My Site</title>
      <dc:creator>Kevin Griffin @ #Shedquarters</dc:creator>
      <pubDate>Thu, 28 May 2020 03:08:36 +0000</pubDate>
      <link>https://dev.to/1kevgriff/building-a-twitch-badge-for-my-site-35b1</link>
      <guid>https://dev.to/1kevgriff/building-a-twitch-badge-for-my-site-35b1</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This article was originally first on my site, &lt;a href="https://consultwithgriff.com/building-a-twitch-badge/" rel="noopener noreferrer"&gt;https://consultwithgriff.com&lt;/a&gt; - check it out!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;On my &lt;a href="https://twitch.tv/1kevgriff" rel="noopener noreferrer"&gt;stream&lt;/a&gt;, I wanted to play around with building out some tools that help me connect better with my readers and viewers.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/ht27gkTCeBQ"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;First task on the list was an indicator on &lt;em&gt;this site&lt;/em&gt; that would tell you if was currently online.  Eventually, this will extend to other tools - but first things first.&lt;/p&gt;

&lt;p&gt;Here are the steps I had to follow in order to build my Twitch badge:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create an endpoint that would tell me if I was online&lt;/li&gt;
&lt;li&gt;Generate a badge that said &lt;code&gt;online&lt;/code&gt; or &lt;code&gt;offline&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Display the badge on my site&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  TwitchLib
&lt;/h2&gt;

&lt;p&gt;When creating an endpoint that would tell me if I was online, I wanted to start with a solid base.  Turns out there is already an amazing open-source library called TwitchLib which helps facilitate the connection to the Twitch APIs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fconsultwithgriff.com%2Fassets%2Fstatic%2Ftwitchlib.b81fcc2.982525fee3da0d14c6b5c42673f55128.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fconsultwithgriff.com%2Fassets%2Fstatic%2Ftwitchlib.b81fcc2.982525fee3da0d14c6b5c42673f55128.png" alt="TwitchLib"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is a great set of APIs available, and the exact method call I wanted was in the examples: &lt;code&gt;BroadcasterOnlineAsync&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;user&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;_api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;V5&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetUserByNameAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;channelName&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;isOnline&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;_api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;V5&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Streams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;BroadcasterOnlineAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Matches&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;First&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Turns out, I had to take an additional step of getting my channel &lt;code&gt;ID&lt;/code&gt; instead of just using my channel name.  If anyone knows another way of doing this that's easier/faster/better, please let me know.&lt;/p&gt;

&lt;h2&gt;
  
  
  Azure Functions
&lt;/h2&gt;

&lt;p&gt;With my new ability to get channel status at the blink of an eye, I needed a way to query this whenever some came to my site.  &lt;/p&gt;

&lt;p&gt;Serverless was the answer.  &lt;/p&gt;

&lt;p&gt;I wrote a simple Azure Function for polling Twitch to see if I was online.&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;FunctionName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"IsChannelOnline"&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;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;IActionResult&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;HttpTrigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AuthorizationLevel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"get"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Route&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="n"&gt;HttpRequest&lt;/span&gt; &lt;span class="n"&gt;req&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;clientId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetEnvironmentVariable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"twitch:clientId"&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;accessToken&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetEnvironmentVariable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"twitch:accessToken"&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;twitch&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;Twitch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;accessToken&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="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"channelName"&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;name&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="nf"&gt;BadRequestObjectResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Channel name was missing."&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;isOnline&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;twitch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsChannelOnlineAsync&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="cm"&gt;/* other code */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This method would let me call a HTTP endpoint, like &lt;code&gt;https://myazurefunctions.com/api/IsChannelOnline?channelName=1kevgriff&lt;/code&gt; and it would return a response!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: The &lt;code&gt;await twitch.IsChannelOnlineAsync(name)&lt;/code&gt; is a wrapper around the TwitchLib code I wrote above.  Sorry if that was misleading!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Shields.io
&lt;/h2&gt;

&lt;p&gt;With my new Azure Function deployed, I need to set up to show if it said online or offline.  &lt;/p&gt;

&lt;p&gt;My buddy, &lt;a href="https://twitter.com/mbuckbee" rel="noopener noreferrer"&gt;Mike Buckbee&lt;/a&gt;, had an amazing idea - why not make it look like build badges used on various GitHub pages.  Another buddy, &lt;a href="https://twitter.com/_CalvinAllen" rel="noopener noreferrer"&gt;Calvin Allen&lt;/a&gt;, pointed out I could use &lt;a href="https://shields.io/" rel="noopener noreferrer"&gt;Shields.io&lt;/a&gt; to build the badge automatically.&lt;/p&gt;

&lt;p&gt;To that extent, I could give &lt;a href="https://shields.io/endpoint" rel="noopener noreferrer"&gt;Shields.io my Azure Functions endpoint&lt;/a&gt; and it would build the badge for me.&lt;/p&gt;

&lt;p&gt;My updated Azure Function to return the JSON necessary for Shields.io to build a badge.&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;ShieldBadge&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;SchemaVersion&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;private&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="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;/// Left Text&lt;/span&gt;
    &lt;span class="c1"&gt;/// &amp;lt;/summary&amp;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;Label&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;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;/// Right Text&lt;/span&gt;
    &lt;span class="c1"&gt;/// &amp;lt;/summary&amp;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;Message&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;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;/// Right Color&lt;/span&gt;
    &lt;span class="c1"&gt;/// &amp;lt;/summary&amp;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;Color&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;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;/// Left Color&lt;/span&gt;
    &lt;span class="c1"&gt;/// &lt;/span&gt;
    &lt;span class="c1"&gt;/// &amp;lt;/summary&amp;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;LabelColor&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;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;/// Style&lt;/span&gt;
    &lt;span class="c1"&gt;/// &lt;/span&gt;
    &lt;span class="c1"&gt;/// Options: flat, plastic, flat-square, for-the-badge, social &lt;/span&gt;
    &lt;span class="c1"&gt;/// &amp;lt;/summary&amp;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;Style&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;var&lt;/span&gt; &lt;span class="n"&gt;badge&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;ShieldBadge&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Label&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"twitch.tv/1kevgriff"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;LabelColor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"lightgrey"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Style&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"flat"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;isOnline&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s"&gt;"LIVE"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"OFFLINE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Color&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;isOnline&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s"&gt;"#2f855a"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"red"&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Adding it to my site
&lt;/h2&gt;

&lt;p&gt;This was the easiest step.  On my site, I added an image tag pointing to the following URL.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt;
&lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Am I streaming?"&lt;/span&gt;
&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://img.shields.io/endpoint?style=for-the-badge&amp;amp;url=https%3A%2F%2Fgriffin-twitch-functions.azurewebsites.net%2Fapi%2FIsChannelOnline%3Fcode%3DxCnE0Jr1XRSamEmyhLUYuJE%2FQ34ovvbST19kl3vOXbvnxIBKCBxzvw%3D%3D%26channelName%3D1kevgriff"&lt;/span&gt;
&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Doing this will add the awesome little badge you see at the top:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fendpoint%3Fstyle%3Dfor-the-badge%26url%3Dhttps%253A%252F%252Fgriffin-twitch-functions.azurewebsites.net%252Fapi%252FIsChannelOnline%253Fcode%253DxCnE0Jr1XRSamEmyhLUYuJE%252FQ34ovvbST19kl3vOXbvnxIBKCBxzvw%253D%253D%2526channelName%253D1kevgriff" class="article-body-image-wrapper"&gt;&lt;img alt="Am I streaming?" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fendpoint%3Fstyle%3Dfor-the-badge%26url%3Dhttps%253A%252F%252Fgriffin-twitch-functions.azurewebsites.net%252Fapi%252FIsChannelOnline%253Fcode%253DxCnE0Jr1XRSamEmyhLUYuJE%252FQ34ovvbST19kl3vOXbvnxIBKCBxzvw%253D%253D%2526channelName%253D1kevgriff"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap up!
&lt;/h2&gt;

&lt;p&gt;This was a fun little project that took me about 2 hours to figure out, start to finish.  Full source code is available at &lt;a href="https://github.com/1kevgriff/Griffin.TwitchBot" rel="noopener noreferrer"&gt;https://github.com/1kevgriff/Griffin.TwitchBot&lt;/a&gt;..&lt;/p&gt;

&lt;p&gt;Thanks for following along, and &lt;a href="https://twitch.tv/1kevgriff" rel="noopener noreferrer"&gt;follow me on Twitch&lt;/a&gt; to see when I go live!&lt;/p&gt;

</description>
      <category>azure</category>
      <category>serverless</category>
      <category>twitch</category>
      <category>staticsite</category>
    </item>
    <item>
      <title>What is Dapper, and why you should consider it for your .NET projects</title>
      <dc:creator>Kevin Griffin @ #Shedquarters</dc:creator>
      <pubDate>Mon, 18 May 2020 17:31:05 +0000</pubDate>
      <link>https://dev.to/1kevgriff/what-is-dapper-and-why-you-should-consider-it-for-your-net-projects-cm4</link>
      <guid>https://dev.to/1kevgriff/what-is-dapper-and-why-you-should-consider-it-for-your-net-projects-cm4</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This post was originally hosted on my site, &lt;a href="https://consultwithgriff.com/what-is-dapper/"&gt;https://consultwithgriff.com&lt;/a&gt; - check it out!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;On the speaking circuit, I've been doing a good number of presentations on Dapper.  My talk is entitled &lt;code&gt;Better Object Mapping in .NET with Dapper&lt;/code&gt; and this is an attempt to catch the eyes of developers who might have heard of object mapping from things like Entity Framework.  &lt;/p&gt;

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

&lt;p&gt;Dapper is a &lt;code&gt;Micro-ORM&lt;/code&gt; or &lt;code&gt;Micro Object Relational Mapper&lt;/code&gt;.  &lt;/p&gt;

&lt;p&gt;Maybe it's better to start at the beginning.  If you're using a relational database, such as SQL Server, MySql, or PostgreSQL, you probably have had to deal with the problem of "how do I turn a result set into an object I can actually do work with?"  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FUYpI1_N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://consultwithgriff.com/assets/static/whatisdapper_data_to_objects.0309e29.2083f64c0fe4c3367a2a6dd0408414a4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FUYpI1_N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://consultwithgriff.com/assets/static/whatisdapper_data_to_objects.0309e29.2083f64c0fe4c3367a2a6dd0408414a4.png" alt="SQL Result + Object"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are a ton of ways to do this currently:&lt;/p&gt;

&lt;h3&gt;
  
  
  Write your own mapping from a result set.
&lt;/h3&gt;

&lt;p&gt;This process is really tedious, and I've written my fair share of code that gets the &lt;code&gt;string&lt;/code&gt; from ordinal position 0 and the &lt;code&gt;long&lt;/code&gt; from ordinal position 52.&lt;/p&gt;

&lt;p&gt;&lt;del&gt;I'm not even going to show demo code, because I don't want you to write it.  Use Dapper.&lt;/del&gt;&lt;/p&gt;

&lt;p&gt;EDIT:  Ok - here's how'd you write it.&lt;/p&gt;

&lt;p&gt;Imagine you have a (relational) database table called &lt;code&gt;Users&lt;/code&gt;.  It has columns in it.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Column&lt;/th&gt;
&lt;th&gt;type&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Id&lt;/td&gt;
&lt;td&gt;bigint&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FirstName&lt;/td&gt;
&lt;td&gt;nvarchar(50)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LastName&lt;/td&gt;
&lt;td&gt;nvarchar(50)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EmailAddress&lt;/td&gt;
&lt;td&gt;nvarchar(255)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DateOfBirth&lt;/td&gt;
&lt;td&gt;datetime&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you wanted to query that content, you could simply write the following SQL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&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;FirstName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;LastName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;EmailAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DateOfBirth&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And if you wanted to get that data into an object that is actually useful... you'd... well..&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;ApplicationUser&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;long&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;FirstName&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;LastName&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;EmailAddress&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;DateOfBirth&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;Yeah!  Write a &lt;code&gt;DataReader&lt;/code&gt;...&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;sql&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;@"SELECT Id, FirstName, LastName, EmailAddress, DateOfBirth
        FROM [dbo].[Users]"&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;SqlConnection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CONNECTION_STRING&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&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;OpenAsync&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;reader&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;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ExecuteReaderAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sql&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;applicationUsers&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;ApplicationUser&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
        &lt;span class="k"&gt;while&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;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadAsync&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;applicationUsers&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;ApplicationUser&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;GetInt64&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="c1"&gt;// ordinal position&lt;/span&gt;
                &lt;span class="n"&gt;FirstName&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;GetString&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="n"&gt;LastName&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;GetString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="n"&gt;EmailAddress&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;GetString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="n"&gt;DateOfBirth&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;GetDateTime&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="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;applicationUsers&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;Not bad, right?  Maybe not, until you're trying to retrieve a 10+ column result set.&lt;/p&gt;

&lt;p&gt;Also, what if you want to change the order of your parameters?  You need to reorder the ordinal positions of your readers.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Yes, you can get the ordinal by calling &lt;code&gt;reader.GetOrdinal("EmailAddress");&lt;/code&gt;.  Please don't do that in the &lt;code&gt;.ReadAsync()&lt;/code&gt; loop though.  Call it once outside of the loop and cache the results.  Calling &lt;code&gt;GetOrdinal&lt;/code&gt; for each column on each row read is expensive and will slow down your application.&lt;br&gt;
And the more obvious detail, you need to know the data types for the columsn you're retrieving!  Is it a string? Or a datetime?  Or an Int16, Int32, or Int64??  Wowza.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Data Tables
&lt;/h3&gt;

&lt;p&gt;The first .NET project I worked on back in 2007 used DataTables exclusively for all data access.  This was to the extent where I believed DataTables were the ONLY way to get the results of a SQL Query.&lt;/p&gt;

&lt;p&gt;And DataTables aren't too bad.  The biggest downside to them is that they're memory hogs, and using them with larger datasets can imped performance.&lt;/p&gt;

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

&lt;div class="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;sql&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;@"SELECT Id, FirstName, LastName, EmailAddress, DateOfBirth
        FROM [dbo].[Users]"&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;SqlConnection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CONNECTION_STRING&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&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;OpenAsync&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;reader&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;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ExecuteReaderAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;DataTable&lt;/span&gt; &lt;span class="n"&gt;table&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;DataTable&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Load&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;emailAddress&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Rows&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="s"&gt;"EmailAddress"&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;Again - not bad!  This approach is more accessible (in my opinion) than the DataReader.&lt;/p&gt;

&lt;h3&gt;
  
  
  Entity Framework
&lt;/h3&gt;

&lt;p&gt;EF is the 6,000-pound gorilla in the room.  It's what Microsoft recommends using for data access.  And I have a lot of opinions on why I don't like Entity Framework for data access, but I don't feel this is the place nor the time.&lt;/p&gt;

&lt;p&gt;By the way, it's great for demos.&lt;/p&gt;

&lt;h3&gt;
  
  
  Other ORMS options
&lt;/h3&gt;

&lt;p&gt;Here are some other ORMs that are interesting to look at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/FransBouma/Massive"&gt;Massive&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/CollaboratingPlatypus/PetaPoco"&gt;PetaPOCO&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nhibernate.info"&gt;nHibernate&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What makes Dapper special?
&lt;/h2&gt;

&lt;p&gt;At its core, Dapper is simply a collection of extension methods off of a &lt;code&gt;SqlConnnection&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;Here is an example of using Dapper to query the database and return a list of objects.&lt;/p&gt;

&lt;p&gt;Remember our object?&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;ApplicationUser&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;long&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;FirstName&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;LastName&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;EmailAddress&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;DateOfBirth&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;Here's the Dapper approach to Querying and Mapping the results to an object (or in our case, a collection of objects).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight csharp"&gt;&lt;code&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;SqlConnection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CONNECTION_STRING&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;sql&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"SELECT Id, FirstName, LastName, EmailAddress, DateOfBirth From [dbo].[Users]"&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;results&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;connection&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QueryAsync&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ApplicationUser&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;sql&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;That's it.  No need to &lt;code&gt;.Open&lt;/code&gt; the connection.  Just create it and call the &lt;code&gt;Query&lt;/code&gt; or &lt;code&gt;QueryAsync&lt;/code&gt; method.  &lt;/p&gt;

&lt;h2&gt;
  
  
  What about parameters?  How do I avoid SQL injection?
&lt;/h2&gt;

&lt;p&gt;That's a great question.  Let's go back to the &lt;code&gt;DataReader&lt;/code&gt; example and see how it was done there:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;sql&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;@"SELECT Id, FirstName, LastName, EmailAddress, DateOfBirth
                    FROM [dbo].[Users] WHERE FirstName = @firstName"&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;SqlConnection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CONNECTION_STRING&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&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;OpenAsync&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;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="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;sql&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="s"&gt;"firstName"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Kevin"&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;reader&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;command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ExecuteReaderAsync&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;applicationUsers&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;ApplicationUser&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
            &lt;span class="k"&gt;while&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;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadAsync&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;applicationUsers&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;ApplicationUser&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;GetInt64&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="c1"&gt;// ordinal position&lt;/span&gt;
                    &lt;span class="n"&gt;FirstName&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;GetString&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="n"&gt;LastName&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;GetString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                    &lt;span class="n"&gt;EmailAddress&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;GetString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                    &lt;span class="n"&gt;DateOfBirth&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;GetDateTime&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="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;applicationUsers&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;What's the difference?  First, the SQL statement has a WHERE clause in it.  I've added a parameter with the &lt;code&gt;@firstName&lt;/code&gt; identifier.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: Please please please parameterize your SQL queries. This is one of the easiest things you can do to protect your databases.&lt;br&gt;&lt;br&gt;
In order for the query to work, you need to pass the parameter value to the data reader.  I had to take an extra step by creating a full &lt;code&gt;SqlCommand&lt;/code&gt; instead of just executing a reader.  Not a big deal - but it's necessary to add parameters.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;command.Parameters.AddWithValue("firstName", "Kevin");&lt;/code&gt; tells the command which parameter I want to map to and the value to use for it.&lt;/p&gt;

&lt;p&gt;Now!  Let's do the same with Dapper.&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;sql&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;@"SELECT Id, FirstName, LastName, EmailAddress, DateOfBirth
        FROM [dbo].[Users] WHERE FirstName = @firstName"&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;SqlConnection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CONNECTION_STRING&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;results&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;connection&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QueryAsync&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ApplicationUser&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;firstName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Kevin"&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 next parameter of &lt;code&gt;QueryAsync&lt;/code&gt; (or many other Dapper methods) is a parameter object.&lt;/p&gt;

&lt;p&gt;I'm passing an anonymous object for my parameters, and Dapper will assist with telling the database that I want &lt;code&gt;@firstName&lt;/code&gt; to map to &lt;code&gt;Kevin&lt;/code&gt;.  I don't need to worry about any of that work.&lt;/p&gt;

&lt;h2&gt;
  
  
  It seems like you're over-simplifying?
&lt;/h2&gt;

&lt;p&gt;I totally am.  But my goal here is to tell you what Dapper is meant to do.  &lt;/p&gt;

&lt;p&gt;Most database operations you need to make: SELECT, UPDATE, INSERT, DELETE are supported with a couple of lines of code.  I'm planning several follow up posts that cover scenarios around these topics, but I felt this article would become more reference than "hey, this is a tool I like and you should check it out."&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://twitter.com/robconery"&gt;Rob&lt;/a&gt; made a great point earlier, I'm not really diving deep enough into &lt;strong&gt;mapping&lt;/strong&gt;.  There is a rabbit hole of use-cases where Dapper can be combined with other awesome libraries, like &lt;a href="https://github.com/AutoMapper/AutoMapper"&gt;AutoMapper&lt;/a&gt;.  I'm not diving in deep here, but it seems like a great idea for future posts.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Use Stored Procedures?  &lt;a href="https://consultwithgriff.com/dapper-stored-procedures"&gt;No problem&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I also use Dapper in every single application I scaffold out.  It's &lt;em&gt;that&lt;/em&gt; critical to my project success.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is it open-source?
&lt;/h2&gt;

&lt;p&gt;Yes!  And even better, it's built by the good folks over at &lt;a href="https://stackoverflow.com"&gt;StackOverflow&lt;/a&gt;.  Maybe you've heard of it.  It's one of the most frequented websites on the internet, and they do not play around when it comes to performance.  &lt;/p&gt;

&lt;p&gt;Dapper was created by their team in order to make mapping data to objects as painless as possible while being fast. &lt;a href="https://github.com/StackExchange/Dapper#performance"&gt;Check out their performance benchmarks&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Give it a try!
&lt;/h2&gt;

&lt;p&gt;If you're jumping into Dapper for the first time, take it easy!  There are a lot of great examples in the &lt;a href="https://github.com/StackExchange/Dapper"&gt;GitHub repo&lt;/a&gt; for getting started.&lt;/p&gt;

&lt;p&gt;If you run into problems, feel free to ask me on &lt;a href="https://twitter.com/1kevgriff"&gt;Twitter&lt;/a&gt;.  I'm happy to research your questions and write some detailed explanations on more complex use-cases.&lt;/p&gt;

&lt;p&gt;Also - if you made it this far, &lt;a href="https://twitch.tv/1kevgriff"&gt;follow me on Twitch&lt;/a&gt;.  I do a daily stream where I work on random projects.  I'd love to chat with you!&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>orm</category>
      <category>database</category>
      <category>csharp</category>
    </item>
  </channel>
</rss>
