<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>ASP.NET Monsters</title>
  
  
  <link href="/atom.xml" rel="self"/>
  
  <link href="http://aspnetmonsters.com/"/>
  <updated>2019-04-27T15:03:14.933Z</updated>
  <id>http://aspnetmonsters.com/</id>
  
  <author>
    <name>The Monsters</name>
    
  </author>
  
  <generator uri="http://hexo.io/">Hexo</generator>
  
  <entry>
    <title>Azure Camp 2019</title>
    <link href="http://aspnetmonsters.com/2019/04/2019-04-27-azurecamp/"/>
    <id>http://aspnetmonsters.com/2019/04/2019-04-27-azurecamp/</id>
    <published>2019-04-27T15:00:00.000Z</published>
    <updated>2019-04-27T15:03:14.933Z</updated>
    
    <content type="html"><![CDATA[<p>If you’re reading this I’m hoping you’re in the room for Azure Camp 2019 because otherwise there isn’t much point. This article is just a bunch of resources for you.</p><p>We have a code of conduct here <a href="https://confcodeofconduct.com/" target="_blank" rel="noopener">https://confcodeofconduct.com/</a></p><h1 id="Code"><a href="#Code" class="headerlink" title="Code"></a>Code</h1><p>We’re going to use a couple of small sample projects during the day. They are on github at </p><ul><li><a href="https://github.com/stimms/ClassStatus" target="_blank" rel="noopener">https://github.com/stimms/ClassStatus</a></li><li><a href="https://github.com/stimms/ClassStatusUpdater" target="_blank" rel="noopener">https://github.com/stimms/ClassStatusUpdater</a></li></ul><h1 id="Slides"><a href="#Slides" class="headerlink" title="Slides"></a>Slides</h1><p>There are some slides, some of them have secret commands in them. They are up on one drive here: <a href="https://1drv.ms/f/s!AmN_cJhXT0rP1yd-qMdkgcHgvKD0" target="_blank" rel="noopener">https://1drv.ms/f/s!AmN_cJhXT0rP1yd-qMdkgcHgvKD0</a></p><h1 id="Class-Status"><a href="#Class-Status" class="headerlink" title="Class Status"></a>Class Status</h1><p>This serves a double purpose. It lets you update your status and it is the demo we’re building today. <a href="http://classstatus.aspnetmonsters.com/" target="_blank" rel="noopener">http://classstatus.aspnetmonsters.com/</a></p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;If you’re reading this I’m hoping you’re in the room for Azure Camp 2019 because otherwise there isn’t much point. This article is just a
      
    
    </summary>
    
      <category term="Development" scheme="http://aspnetmonsters.com/categories/Development/"/>
    
    
      <category term="docker" scheme="http://aspnetmonsters.com/tags/docker/"/>
    
      <category term="azure" scheme="http://aspnetmonsters.com/tags/azure/"/>
    
      <category term="k8s" scheme="http://aspnetmonsters.com/tags/k8s/"/>
    
  </entry>
  
  <entry>
    <title>Using NodaTime with Dapper</title>
    <link href="http://aspnetmonsters.com/2019/03/2019-03-27-using-noda-time-with-dapper/"/>
    <id>http://aspnetmonsters.com/2019/03/2019-03-27-using-noda-time-with-dapper/</id>
    <published>2019-03-28T01:00:00.000Z</published>
    <updated>2019-04-27T15:03:14.933Z</updated>
    
    <content type="html"><![CDATA[<p>This is a part of a series of blog posts on data access with Dapper. To see the full list of posts, visit the <a href="https://www.davepaquette.com/archive/2018/01/21/exploring-dapper-series.aspx" target="_blank" rel="noopener">Dapper Series Index Page</a>.</p><p>After my recent misadventures attempting to use Noda Time with <a href="https://www.davepaquette.com/archive/2019/03/26/using-noda-time-with-ef-core.aspx" target="_blank" rel="noopener">Entity Framework Core</a>, I decided to see what it would take to use Dapper in a the same scenario.</p><h2 id="A-quick-recap"><a href="#A-quick-recap" class="headerlink" title="A quick recap"></a>A quick recap</h2><p>In my app, I needed to model an <code>Event</code> that occurs on a particular date. It might be initially tempting to store the date of the event as a DateTime in UTC, but that’s not necessarily accurate unless the event happens to be held at the Royal Observatory Greenwich. I don’t want to deal with time at all, I’m only interested in the date the event is being held. </p><p>NodaTime provides a <code>LocalDate</code> type that is perfect for this scenario so I declared a <code>LocalDate</code> property named <code>Date</code> on my <code>Event</code> class.</p><figure class="highlight csharp"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title">Event</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">public</span> Guid Id &#123; <span class="keyword">get</span>; <span class="keyword">set</span>; &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">string</span> Name &#123; <span class="keyword">get</span>; <span class="keyword">set</span>; &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">string</span> Description &#123; <span class="keyword">get</span>; <span class="keyword">set</span>; &#125;</span><br><span class="line">    <span class="keyword">public</span> LocalDate Date &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="Querying-using-Dapper"><a href="#Querying-using-Dapper" class="headerlink" title="Querying using Dapper"></a>Querying using Dapper</h2><p>I modified my app to query for the <code>Event</code> entities using Dapper:</p><figure class="highlight csharp"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> queryDate = <span class="keyword">new</span> LocalDate(<span class="number">2019</span>, <span class="number">3</span>, <span class="number">26</span>);</span><br><span class="line"><span class="keyword">using</span> (<span class="keyword">var</span> connection = <span class="keyword">new</span> SqlConnection(myConnectionString))</span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">await</span> connection.OpenAsync();</span><br><span class="line">    Events = <span class="keyword">await</span> connection.QueryAsync&lt;Event&gt;(<span class="string">@"SELECT [e].[Id], [e].[Date], [e].[Description], [e].[Name]</span></span><br><span class="line"><span class="string">FROM [Events] AS[e]"</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>The app started up just fine, but gave me an error when I tried to query for events.</p><blockquote><p>System.Data.DataException: Error parsing column 1 (Date=3/26/19 12:00:00 AM - DateTime) —&gt; System.InvalidCastException: Invalid cast from ‘System.DateTime’ to ‘NodaTime.LocalDate’.</p></blockquote><p>Likewise, if I attempted to query for events using a <code>LocalDate</code> parameter, I got another error:</p><figure class="highlight csharp"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> queryDate = <span class="keyword">new</span> LocalDate(<span class="number">2019</span>, <span class="number">3</span>, <span class="number">26</span>);</span><br><span class="line"><span class="keyword">using</span> (<span class="keyword">var</span> connection = <span class="keyword">new</span> SqlConnection(<span class="string">"myConnectionString"</span>))</span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">await</span> connection.OpenAsync();</span><br><span class="line"></span><br><span class="line">    Events = <span class="keyword">await</span> connection.QueryAsync&lt;Event&gt;(<span class="string">@"SELECT [e].[Id], [e].[Date], [e].[Description], [e].[Name]</span></span><br><span class="line"><span class="string">FROM [Events] AS[e]</span></span><br><span class="line"><span class="string">WHERE [e].[Date] = @Date"</span>, <span class="keyword">new</span> &#123; Date = queryDate &#125;);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><blockquote><p>NotSupportedException: The member Date of type NodaTime.LocalDate cannot be used as a parameter value</p></blockquote><p>Fortunately, both these problems can be solved by implementing a simple <code>TypeHandler</code>.</p><h2 id="Implementing-a-Custom-Type-Handler"><a href="#Implementing-a-Custom-Type-Handler" class="headerlink" title="Implementing a Custom Type Handler"></a>Implementing a Custom Type Handler</h2><p>Out of the box, Dapper already knows how to map to the standard .NET types like Int32, Int64, string and DateTime. The problem we are running into here is that Dapper doesn’t know anything about the <code>LocalDate</code> type. If you want to map to a type that Dapper doesn’t know about, you can implement a custom type handler. To implement a type handler, create a class that inherits from <code>TypeHandler&lt;T&gt;</code>, where <code>T</code> is the type that you want to map to. In your type handler class, implement the <code>Parse</code> and <code>SetValue</code> methods. These methods will be used by Dapper when mapping to and from properties that are of type <code>T</code>. </p><p>Here is an example of a type handler for <code>LocalDate</code>.</p><figure class="highlight csharp"><table><tr><td class="code"><pre><span class="line">public class LocalDateTypeHandler : TypeHandler&lt;LocalDate&gt;</span><br><span class="line">&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">override</span> LocalDate <span class="title">Parse</span>(<span class="params"><span class="keyword">object</span> <span class="keyword">value</span></span>)</span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (<span class="keyword">value</span> <span class="keyword">is</span> DateTime)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">return</span> LocalDate.FromDateTime((DateTime)<span class="keyword">value</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> DataException(<span class="string">$"Unable to convert <span class="subst">&#123;<span class="keyword">value</span>&#125;</span> to LocalDate"</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">override</span> <span class="keyword">void</span> <span class="title">SetValue</span>(<span class="params">IDbDataParameter parameter, LocalDate <span class="keyword">value</span></span>)</span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        parameter.Value = <span class="keyword">value</span>.ToDateTimeUnspecified();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Finally, you need to tell Dapper about your new custom type handler. To do that, register the type handler somewhere in your application’s startup class by calling <code>Dapper.SqlMapper.AddTypeHandler</code>.</p><figure class="highlight csharp"><table><tr><td class="code"><pre><span class="line">Dapper.SqlMapper.AddTypeHandler(<span class="keyword">new</span> LocalDateTypeHandler());</span><br></pre></td></tr></table></figure><h2 id="There’s-a-NuGet-for-that"><a href="#There’s-a-NuGet-for-that" class="headerlink" title="There’s a NuGet for that"></a>There’s a NuGet for that</h2><p>As it turns out, someone has already created a helpful NuGet package containing TypeHandlers for many of the NodaTime types so you probably don’t need to write these yourself. Use the <a href="http://mj1856.github.io/Dapper-NodaTime/" target="_blank" rel="noopener">Dapper.NodaTime package</a> instead.</p><h2 id="Wrapping-it-up"><a href="#Wrapping-it-up" class="headerlink" title="Wrapping it up"></a>Wrapping it up</h2><p>TypeHandlers are a simple extension point that allows for Dapper to handle types that are not already handled by Dapper. You can write your own type handlers but you might also want to check if someone has already published a NuGet package that handles your types. </p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;This is a part of a series of blog posts on data access with Dapper. To see the full list of posts, visit the &lt;a href=&quot;https://www.davepa
      
    
    </summary>
    
      <category term="Development" scheme="http://aspnetmonsters.com/categories/Development/"/>
    
    
      <category term="Dapper" scheme="http://aspnetmonsters.com/tags/Dapper/"/>
    
      <category term=".NET" scheme="http://aspnetmonsters.com/tags/NET/"/>
    
      <category term=".NET Core" scheme="http://aspnetmonsters.com/tags/NET-Core/"/>
    
      <category term="Micro ORM" scheme="http://aspnetmonsters.com/tags/Micro-ORM/"/>
    
      <category term="Noda Time" scheme="http://aspnetmonsters.com/tags/Noda-Time/"/>
    
  </entry>
  
  <entry>
    <title>Optimistic Concurrency Tracking with Dapper and SQL Server</title>
    <link href="http://aspnetmonsters.com/2019/03/2019-03-20-optimistic-concurrency-tracking-with-dapper-and-sql-server/"/>
    <id>http://aspnetmonsters.com/2019/03/2019-03-20-optimistic-concurrency-tracking-with-dapper-and-sql-server/</id>
    <published>2019-03-20T14:45:36.000Z</published>
    <updated>2019-04-27T15:03:14.918Z</updated>
    
    <content type="html"><![CDATA[<p>This is a part of a series of blog posts on data access with Dapper. To see the full list of posts, visit the <a href="https://www.davepaquette.com/archive/2018/01/21/exploring-dapper-series.aspx" target="_blank" rel="noopener">Dapper Series Index Page</a>.</p><p>In today’s post, we explore a pattern to prevent multiple users (or processes) from accidentally overwriting each other’s change. Given our <a href="https://www.davepaquette.com/archive/2019/02/04/basic-insert-update-delete-with-dapper.aspx" target="_blank" rel="noopener">current implementation for updating the <code>Aircraft</code> record</a>, there is potential for data loss if there are multiple active sessions are attempting to update the same <code>Aircraft</code> record at the same time. In the example shown below, Bob accidentally overwrites Jane’s changes without even knowing that Jane made changes to the same <code>Aircraft</code> record</p><p><img src="https://www.davepaquette.com/images/dapper/concurrency.png" alt="Concurrent Updates"></p><p>The pattern we will use here is <a href="https://martinfowler.com/eaaCatalog/optimisticOfflineLock.html" target="_blank" rel="noopener">Optimistic Offline Lock</a>, which is often also referred to as Optimistic Concurrency Control.</p><h2 id="Modifying-the-Database-and-Entities"><a href="#Modifying-the-Database-and-Entities" class="headerlink" title="Modifying the Database and Entities"></a>Modifying the Database and Entities</h2><p>To implement this approach, we will use a <a href="https://docs.microsoft.com/sql/t-sql/data-types/rowversion-transact-sql" target="_blank" rel="noopener">rowversion column in SQL Server</a>. Essentially, this is a column that automatically version stamps a row in a table. Any time a row is modified, the <code>rowversion</code> column will is automatically incremented for that row. We will start by adding the column to our <code>Aircraft</code> table.</p><figure class="highlight sql"><table><tr><td class="code"><pre><span class="line"><span class="keyword">ALTER</span> <span class="keyword">TABLE</span> Aircraft <span class="keyword">ADD</span> RowVer rowversion</span><br></pre></td></tr></table></figure><p>Next, we add a <code>RowVer</code> property to the <code>Aircraft</code> table. The property is a <code>byte</code> array. When we read the <code>RowVer</code> column from the database, we will get an array of 8 bytes.  </p><figure class="highlight csharp"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title">Aircraft</span> </span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> Id &#123; <span class="keyword">get</span>; <span class="keyword">set</span>; &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">string</span> Manufacturer &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">string</span> Model &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">string</span> RegistrationNumber &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> FirstClassCapacity &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> RegularClassCapacity &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> CrewCapacity &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> DateTime ManufactureDate &#123;<span class="keyword">get</span>; <span class="keyword">set</span>; &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> NumberOfEngines &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> EmptyWeight &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> MaxTakeoffWeight &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">byte</span>[] RowVer &#123; <span class="keyword">get</span>; <span class="keyword">set</span>; &#125;</span><br><span class="line">&#125;   </span><br></pre></td></tr></table></figure><p>Finally, we will modify the query used to load <code>Aircraft</code> entities so it returns the <code>RowVer</code> column. We don’t need to change any of the Dapper code here.</p><figure class="highlight csharp"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">async</span> Task&lt;Aircraft&gt; <span class="title">Get</span>(<span class="params"><span class="keyword">int</span> id</span>)</span></span><br><span class="line"><span class="function"></span>&#123; </span><br><span class="line">    Aircraft aircraft;</span><br><span class="line">    <span class="keyword">using</span> (<span class="keyword">var</span> connection = <span class="keyword">new</span> SqlConnection(_connectionString))</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">await</span> connection.OpenAsync();</span><br><span class="line">        <span class="keyword">var</span> query = <span class="string">@"</span></span><br><span class="line"><span class="string">SELECT </span></span><br><span class="line"><span class="string">Id</span></span><br><span class="line"><span class="string">,Manufacturer</span></span><br><span class="line"><span class="string">,Model</span></span><br><span class="line"><span class="string">,RegistrationNumber</span></span><br><span class="line"><span class="string">,FirstClassCapacity</span></span><br><span class="line"><span class="string">,RegularClassCapacity</span></span><br><span class="line"><span class="string">,CrewCapacity</span></span><br><span class="line"><span class="string">,ManufactureDate</span></span><br><span class="line"><span class="string">,NumberOfEngines</span></span><br><span class="line"><span class="string">,EmptyWeight</span></span><br><span class="line"><span class="string">,MaxTakeoffWeight</span></span><br><span class="line"><span class="string">,RowVer</span></span><br><span class="line"><span class="string">FROM Aircraft WHERE Id = @Id"</span>;</span><br><span class="line">        aircraft = <span class="keyword">await</span> connection.QuerySingleAsync&lt;Aircraft&gt;(query, <span class="keyword">new</span> &#123;Id = id&#125;);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> aircraft;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="Adding-the-Concurrency-Checks"><a href="#Adding-the-Concurrency-Checks" class="headerlink" title="Adding the Concurrency Checks"></a>Adding the Concurrency Checks</h2><p>Now that we have the row version loaded in to our model, we need to add the checks to ensure that one user doesn’t accidentally overwrite another users changes. To do this, we simply need to add the <code>RowVer</code> to the <code>WHERE</code> clause on the <code>UPDATE</code> statement. By adding this constraint to the <code>WHERE</code> clause, we we ensure that the updates will only be applied if the <code>RowVer</code> has not changed since this user originally loaded the <code>Aircraft</code> entity.</p><figure class="highlight csharp"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">async</span> Task&lt;IActionResult&gt; <span class="title">Put</span>(<span class="params"><span class="keyword">int</span> id, [FromBody] Aircraft model</span>)</span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (id != model.Id) </span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">return</span> BadRequest();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">using</span> (<span class="keyword">var</span> connection = <span class="keyword">new</span> SqlConnection(_connectionString))</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">await</span> connection.OpenAsync();</span><br><span class="line">        <span class="keyword">var</span> query = <span class="string">@"</span></span><br><span class="line"><span class="string">UPDATE Aircraft </span></span><br><span class="line"><span class="string">SET  Manufacturer = @Manufacturer</span></span><br><span class="line"><span class="string">  ,Model = @Model</span></span><br><span class="line"><span class="string">  ,RegistrationNumber = @RegistrationNumber </span></span><br><span class="line"><span class="string">  ,FirstClassCapacity = @FirstClassCapacity</span></span><br><span class="line"><span class="string">  ,RegularClassCapacity = @RegularClassCapacity</span></span><br><span class="line"><span class="string">  ,CrewCapacity = @CrewCapacity</span></span><br><span class="line"><span class="string">  ,ManufactureDate = @ManufactureDate</span></span><br><span class="line"><span class="string">  ,NumberOfEngines = @NumberOfEngines</span></span><br><span class="line"><span class="string">  ,EmptyWeight = @EmptyWeight</span></span><br><span class="line"><span class="string">  ,MaxTakeoffWeight = @MaxTakeoffWeight</span></span><br><span class="line"><span class="string">WHERE Id = @Id</span></span><br><span class="line"><span class="string">      AND RowVer = @RowVer"</span>;</span><br><span class="line">      </span><br><span class="line">      <span class="keyword">await</span> connection.ExecuteAsync(query, model);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> Ok();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>So, the <code>WHERE</code> clause stops the update from happening, but how do we know if the update was applied successfully? We need to let the user know that the update was not applied due to a concurrency conflict. To do that, we add <code>OUTPUT inserted.RowVer</code> to the <code>UPDATE</code> statement. The effect of this is that the query will return the new value for the <code>RowVer</code> column if the update was applied. If not, it will return null. </p><figure class="highlight csharp"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">async</span> Task&lt;IActionResult&gt; <span class="title">Put</span>(<span class="params"><span class="keyword">int</span> id, [FromBody] Aircraft model</span>)</span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">byte</span>[] rowVersion;</span><br><span class="line">    <span class="keyword">if</span> (id != model.Id) </span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">return</span> BadRequest();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">using</span> (<span class="keyword">var</span> connection = <span class="keyword">new</span> SqlConnection(_connectionString))</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">await</span> connection.OpenAsync();</span><br><span class="line">        <span class="keyword">var</span> query = <span class="string">@"</span></span><br><span class="line"><span class="string">UPDATE Aircraft </span></span><br><span class="line"><span class="string">SET  Manufacturer = @Manufacturer</span></span><br><span class="line"><span class="string">  ,Model = @Model</span></span><br><span class="line"><span class="string">  ,RegistrationNumber = @RegistrationNumber </span></span><br><span class="line"><span class="string">  ,FirstClassCapacity = @FirstClassCapacity</span></span><br><span class="line"><span class="string">  ,RegularClassCapacity = @RegularClassCapacity</span></span><br><span class="line"><span class="string">  ,CrewCapacity = @CrewCapacity</span></span><br><span class="line"><span class="string">  ,ManufactureDate = @ManufactureDate</span></span><br><span class="line"><span class="string">  ,NumberOfEngines = @NumberOfEngines</span></span><br><span class="line"><span class="string">  ,EmptyWeight = @EmptyWeight</span></span><br><span class="line"><span class="string">  ,MaxTakeoffWeight = @MaxTakeoffWeight</span></span><br><span class="line"><span class="string">  OUTPUT inserted.RowVer</span></span><br><span class="line"><span class="string">WHERE Id = @Id</span></span><br><span class="line"><span class="string">      AND RowVer = @RowVer"</span>;</span><br><span class="line">        rowVersion = <span class="keyword">await</span> connection.ExecuteScalarAsync&lt;<span class="keyword">byte</span>[]&gt;(query, model);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (rowVersion == <span class="literal">null</span>) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> DBConcurrencyException(<span class="string">"The entity you were trying to edit has changed. Reload the entity and try again."</span>); </span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> Ok(rowVersion);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Instead of calling <code>ExecuteAsync</code>, we call <code>ExecuteScalarAsync&lt;byte[]&gt;</code>. Then we can check if the returned value is <code>null</code> and raise a <code>DBConcurrencyException</code> if it is null. If it is not null, we can return the new <code>RowVer</code> value. </p><h1 id="Wrapping-it-up"><a href="#Wrapping-it-up" class="headerlink" title="Wrapping it up"></a>Wrapping it up</h1><p>Using SQL Server’s <code>rowversion</code> column type makes it easy to implement optimistic concurrency checks in a .NET app that uses Dapper.</p><p>If you are building as REST api, you should really use the ETag header to represent the current RowVer for your entity. You can read more about this pattern <a href="https://sookocheff.com/post/api/optimistic-locking-in-a-rest-api/" target="_blank" rel="noopener">here</a>.</p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;This is a part of a series of blog posts on data access with Dapper. To see the full list of posts, visit the &lt;a href=&quot;https://www.davepa
      
    
    </summary>
    
      <category term="Development" scheme="http://aspnetmonsters.com/categories/Development/"/>
    
    
      <category term="Dapper" scheme="http://aspnetmonsters.com/tags/Dapper/"/>
    
      <category term=".NET" scheme="http://aspnetmonsters.com/tags/NET/"/>
    
      <category term=".NET Core" scheme="http://aspnetmonsters.com/tags/NET-Core/"/>
    
      <category term="Micro ORM" scheme="http://aspnetmonsters.com/tags/Micro-ORM/"/>
    
  </entry>
  
  <entry>
    <title>Managing Database Transactions in Dapper</title>
    <link href="http://aspnetmonsters.com/2019/02/2019-02-06-managing-transactions-in-dapper/"/>
    <id>http://aspnetmonsters.com/2019/02/2019-02-06-managing-transactions-in-dapper/</id>
    <published>2019-02-06T13:00:00.000Z</published>
    <updated>2019-04-27T15:03:14.918Z</updated>
    
    <content type="html"><![CDATA[<p>This is a part of a series of blog posts on data access with Dapper. To see the full list of posts, visit the <a href="https://www.davepaquette.com/archive/2018/01/21/exploring-dapper-series.aspx" target="_blank" rel="noopener">Dapper Series Index Page</a>.</p><p>In today’s post, we explore a more complex scenario that involves executing multiple <em>write</em> operations. In order to ensure consistency at the database level, these operations should all succeed / fail together as a single transaction. In this example, we will be inserting a new <code>ScheduledFlight</code> entity along with an associated set of <code>Flight</code> entities.</p><p> As a quick reminder, a <code>Flight</code> represents a particular occurrence of a <code>ScheduledFlight</code> on a particular day. That is, it has a reference to the <code>ScheduledFlight</code> along with some properties indicating the scheduled arrival and departure times. </p><figure class="highlight csharp"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title">Flight</span> </span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> Id &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> ScheduledFlightId &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> ScheduledFlight ScheduledFlight &#123; <span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> DateTime Day &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> DateTime ScheduledDeparture &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> DateTime ScheduledArrival &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight csharp"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title">ScheduledFlight</span> </span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> Id &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">string</span> FlightNumber &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> DepartureAirportId &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> Airport DepartureAirport &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> DepartureHour &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> DepartureMinute &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> ArrivalAirportId &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> Airport ArrivalAirport &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;        </span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> ArrivalHour &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> ArrivalMinute &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">bool</span> IsSundayFlight &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">bool</span> IsMondayFlight &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="comment">// Some other properties</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="Inserting-the-ScheduledFlight"><a href="#Inserting-the-ScheduledFlight" class="headerlink" title="Inserting the ScheduledFlight"></a>Inserting the ScheduledFlight</h2><p>Inserting the <code>ScheduledFlight</code> and retrieving the database generated id is easy enough. We can use the same approach we used in the <a href="https://www.davepaquette.com/archive/2019/02/04/basic-insert-update-delete-with-dapper.aspx" target="_blank" rel="noopener">previous blog post</a>.</p><figure class="highlight csharp"><table><tr><td class="code"><pre><span class="line"><span class="comment">// POST api/scheduledflight</span></span><br><span class="line">[<span class="meta">HttpPost()</span>]</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">async</span> Task&lt;IActionResult&gt; <span class="title">Post</span>(<span class="params">[FromBody] ScheduledFlight model</span>)</span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">int</span> newScheduledFlightId;</span><br><span class="line">    <span class="keyword">using</span> (<span class="keyword">var</span> connection = <span class="keyword">new</span> SqlConnection(_connectionString))</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">await</span> connection.OpenAsync();</span><br><span class="line">        <span class="keyword">var</span> insertScheduledFlightSql = <span class="string">@"</span></span><br><span class="line"><span class="string">INSERT INTO [dbo].[ScheduledFlight]</span></span><br><span class="line"><span class="string">    ([FlightNumber]</span></span><br><span class="line"><span class="string">    ,[DepartureAirportId]</span></span><br><span class="line"><span class="string">    ,[DepartureHour]</span></span><br><span class="line"><span class="string">    ,[DepartureMinute]</span></span><br><span class="line"><span class="string">    ,[ArrivalAirportId]</span></span><br><span class="line"><span class="string">    ,[ArrivalHour]</span></span><br><span class="line"><span class="string">    ,[ArrivalMinute]</span></span><br><span class="line"><span class="string">    ,[IsSundayFlight]</span></span><br><span class="line"><span class="string">    ,[IsMondayFlight]</span></span><br><span class="line"><span class="string">    ,[IsTuesdayFlight]</span></span><br><span class="line"><span class="string">    ,[IsWednesdayFlight]</span></span><br><span class="line"><span class="string">    ,[IsThursdayFlight]</span></span><br><span class="line"><span class="string">    ,[IsFridayFlight]</span></span><br><span class="line"><span class="string">    ,[IsSaturdayFlight])</span></span><br><span class="line"><span class="string">VALUES</span></span><br><span class="line"><span class="string">    (@FlightNumber</span></span><br><span class="line"><span class="string">    ,@DepartureAirportId</span></span><br><span class="line"><span class="string">    ,@DepartureHour</span></span><br><span class="line"><span class="string">    ,@DepartureMinute</span></span><br><span class="line"><span class="string">    ,@ArrivalAirportId</span></span><br><span class="line"><span class="string">    ,@ArrivalHour</span></span><br><span class="line"><span class="string">    ,@ArrivalMinute</span></span><br><span class="line"><span class="string">    ,@IsSundayFlight</span></span><br><span class="line"><span class="string">    ,@IsMondayFlight</span></span><br><span class="line"><span class="string">    ,@IsTuesdayFlight</span></span><br><span class="line"><span class="string">    ,@IsWednesdayFlight</span></span><br><span class="line"><span class="string">    ,@IsThursdayFlight</span></span><br><span class="line"><span class="string">    ,@IsFridayFlight</span></span><br><span class="line"><span class="string">    ,@IsSaturdayFlight);</span></span><br><span class="line"><span class="string">SELECT CAST(SCOPE_IDENTITY() as int)"</span>;</span><br><span class="line">        newScheduledFlightId = <span class="keyword">await</span> connection.ExecuteScalarAsync&lt;<span class="keyword">int</span>&gt;(insertScheduledFlightSql, model);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> Ok(newScheduledFlightId);</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>According to the bosses at Air Paquette, whenever we create a new <code>ScheduledFlight</code> entity, we also want to generate the <code>Flight</code> entities for the next 12 months of that <code>ScheduledFlight</code>. We can add a method to the <code>ScheduledFlight</code> class to generate the flight entities.</p><p><strong>NOTE:</strong> Let’s just ignore the obvious bugs related to timezones and to flights that take off and land on a different day.</p><figure class="highlight csharp"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> IEnumerable&lt;Flight&gt; <span class="title">GenerateFlights</span>(<span class="params">DateTime startDate, DateTime endDate</span>)</span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">var</span> flights = <span class="keyword">new</span> List&lt;Flight&gt;();</span><br><span class="line">    <span class="keyword">var</span> currentDate = startDate;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">while</span> (currentDate &lt;= endDate)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">if</span> (IsOnDayOfWeek(currentDate.DayOfWeek))</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">var</span> departureTime = <span class="keyword">new</span> DateTime(currentDate.Year, currentDate.Month, currentDate.Day, DepartureHour, DepartureMinute, <span class="number">0</span>);</span><br><span class="line">            <span class="keyword">var</span> arrivalTime = <span class="keyword">new</span> DateTime(currentDate.Year, currentDate.Month, currentDate.Day, ArrivalHour, ArrivalMinute, <span class="number">0</span>);</span><br><span class="line">            <span class="keyword">var</span> flight = <span class="keyword">new</span> Flight</span><br><span class="line">            &#123;</span><br><span class="line">                ScheduledFlightId = Id,</span><br><span class="line">                ScheduledDeparture = departureTime,</span><br><span class="line">                ScheduledArrival = arrivalTime,</span><br><span class="line">                Day = currentDate.Date</span><br><span class="line">            &#125;;</span><br><span class="line">            flights.Add(flight);</span><br><span class="line">        &#125;</span><br><span class="line">        currentDate = currentDate.AddDays(<span class="number">1</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> flights;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">bool</span> <span class="title">IsOnDayOfWeek</span>(<span class="params">DayOfWeek dayOfWeek</span>)</span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">return</span>     (dayOfWeek == DayOfWeek.Sunday &amp;&amp; IsSundayFlight)</span><br><span class="line">            || (dayOfWeek == DayOfWeek.Monday &amp;&amp; IsMondayFlight)</span><br><span class="line">            || (dayOfWeek == DayOfWeek.Tuesday &amp;&amp; IsTuesdayFlight)</span><br><span class="line">            || (dayOfWeek == DayOfWeek.Wednesday &amp;&amp; IsWednesdayFlight)</span><br><span class="line">            || (dayOfWeek == DayOfWeek.Thursday &amp;&amp; IsThursdayFlight)</span><br><span class="line">            || (dayOfWeek == DayOfWeek.Friday &amp;&amp; IsFridayFlight)</span><br><span class="line">            || (dayOfWeek == DayOfWeek.Saturday &amp;&amp; IsSaturdayFlight);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Now in the controller, we can add some logic to call the <code>GenerateFlight</code> method and then insert those <code>Flight</code> entities using Dapper.</p><figure class="highlight csharp"><table><tr><td class="code"><pre><span class="line"><span class="comment">// POST api/scheduledflight</span></span><br><span class="line">[<span class="meta">HttpPost()</span>]</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">async</span> Task&lt;IActionResult&gt; <span class="title">Post</span>(<span class="params">[FromBody] ScheduledFlight model</span>)</span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">int</span> newScheduledFlightId;</span><br><span class="line">    <span class="keyword">using</span> (<span class="keyword">var</span> connection = <span class="keyword">new</span> SqlConnection(_connectionString))</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">await</span> connection.OpenAsync();</span><br><span class="line">        <span class="keyword">var</span> insertScheduledFlightSql = <span class="string">@"</span></span><br><span class="line"><span class="string">INSERT INTO [dbo].[ScheduledFlight]</span></span><br><span class="line"><span class="string">    ([FlightNumber]</span></span><br><span class="line"><span class="string">    ,[DepartureAirportId]</span></span><br><span class="line"><span class="string">    ,[DepartureHour]</span></span><br><span class="line"><span class="string">    ,[DepartureMinute]</span></span><br><span class="line"><span class="string">    ,[ArrivalAirportId]</span></span><br><span class="line"><span class="string">    ,[ArrivalHour]</span></span><br><span class="line"><span class="string">    ,[ArrivalMinute]</span></span><br><span class="line"><span class="string">    ,[IsSundayFlight]</span></span><br><span class="line"><span class="string">    ,[IsMondayFlight]</span></span><br><span class="line"><span class="string">    ,[IsTuesdayFlight]</span></span><br><span class="line"><span class="string">    ,[IsWednesdayFlight]</span></span><br><span class="line"><span class="string">    ,[IsThursdayFlight]</span></span><br><span class="line"><span class="string">    ,[IsFridayFlight]</span></span><br><span class="line"><span class="string">    ,[IsSaturdayFlight])</span></span><br><span class="line"><span class="string">VALUES</span></span><br><span class="line"><span class="string">    (@FlightNumber</span></span><br><span class="line"><span class="string">    ,@DepartureAirportId</span></span><br><span class="line"><span class="string">    ,@DepartureHour</span></span><br><span class="line"><span class="string">    ,@DepartureMinute</span></span><br><span class="line"><span class="string">    ,@ArrivalAirportId</span></span><br><span class="line"><span class="string">    ,@ArrivalHour</span></span><br><span class="line"><span class="string">    ,@ArrivalMinute</span></span><br><span class="line"><span class="string">    ,@IsSundayFlight</span></span><br><span class="line"><span class="string">    ,@IsMondayFlight</span></span><br><span class="line"><span class="string">    ,@IsTuesdayFlight</span></span><br><span class="line"><span class="string">    ,@IsWednesdayFlight</span></span><br><span class="line"><span class="string">    ,@IsThursdayFlight</span></span><br><span class="line"><span class="string">    ,@IsFridayFlight</span></span><br><span class="line"><span class="string">    ,@IsSaturdayFlight);</span></span><br><span class="line"><span class="string">SELECT CAST(SCOPE_IDENTITY() as int)"</span>;</span><br><span class="line">        newScheduledFlightId = <span class="keyword">await</span> connection.ExecuteScalarAsync&lt;<span class="keyword">int</span>&gt;(insertScheduledFlightSql, model);</span><br><span class="line"></span><br><span class="line">        model.Id = newScheduledFlightId;</span><br><span class="line">        <span class="keyword">var</span> flights = model.GenerateFlights(DateTime.Now, DateTime.Now.AddMonths(<span class="number">12</span>));</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> insertFlightsSql = <span class="string">@"INSERT INTO [dbo].[Flight]</span></span><br><span class="line"><span class="string">    ([ScheduledFlightId]</span></span><br><span class="line"><span class="string">    ,[Day]</span></span><br><span class="line"><span class="string">    ,[ScheduledDeparture]</span></span><br><span class="line"><span class="string">    ,[ActualDeparture]</span></span><br><span class="line"><span class="string">    ,[ScheduledArrival]</span></span><br><span class="line"><span class="string">    ,[ActualArrival])</span></span><br><span class="line"><span class="string">VALUES</span></span><br><span class="line"><span class="string">    (@ScheduledFlightId</span></span><br><span class="line"><span class="string">    ,@Day</span></span><br><span class="line"><span class="string">    ,@ScheduledDeparture</span></span><br><span class="line"><span class="string">    ,@ActualDeparture</span></span><br><span class="line"><span class="string">    ,@ScheduledArrival</span></span><br><span class="line"><span class="string">    ,@ActualArrival)"</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">await</span> connection.ExecuteAsync(insertFlightsSql, flights);</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> Ok(newScheduledFlightId);</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>Note that we passed in an <code>IEnumerable&lt;Flight&gt;</code> as the second argument to the <code>ExecuteAsync</code> method. This is a handy shortcut in Dapper for executing a query multiple times. Instead of writing a loop and calling <code>ExecuteAsync</code> for each flight entity, we can pass in a list of flights and Dapper will execute the query once for each item in the list.</p><h2 id="Explicitly-managing-a-transaction"><a href="#Explicitly-managing-a-transaction" class="headerlink" title="Explicitly managing a transaction"></a>Explicitly managing a transaction</h2><p>So far, we have code that first inserts a <code>ScheduledFlight</code>, next generates a set of <code>Flight</code> entities and finally inserting all of those <code>Flight</code> entities. That’s the happy path, but what happens if something goes wrong along the way. Typically when we execute a set of related write operations (inserts, updates and deletes), we want those operations to all succeed or fail together. In the database world, we have transactions to help us with this.</p><p>The nice thing about using Dapper is that it uses standard .NET database connections and transactions. There is no need to re-invent the wheel here, we can simply use the transaction patterns that have been around in .NET since for nearly 2 decades now.</p><p>After opening the connection, we call <code>connection.BeginTransaction()</code> to start a new transaction. Whenever we call <code>ExecuteAsync</code> (or any other Dapper extension method), we need to pass in that transaction. At the end of all that work, we call <code>transaction.Commit()</code>. Finally, we wrap the logic in a <code>try / catch</code> block. If any exception is raised, we call <code>transaction.Rollback()</code> to ensure that none of those write operations are committed to the database.</p><figure class="highlight csharp"><table><tr><td class="code"><pre><span class="line">[<span class="meta">HttpPost()</span>]</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">async</span> Task&lt;IActionResult&gt; <span class="title">Post</span>(<span class="params">[FromBody] ScheduledFlight model</span>)</span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">int</span>? newScheduledFlightId = <span class="literal">null</span>;</span><br><span class="line">    <span class="keyword">using</span> (<span class="keyword">var</span> connection = <span class="keyword">new</span> SqlConnection(_connectionString))</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">await</span> connection.OpenAsync();</span><br><span class="line">        <span class="keyword">var</span> transaction = connection.BeginTransaction();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">try</span></span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">var</span> insertScheduledFlightSql = <span class="string">@"</span></span><br><span class="line"><span class="string">INSERT INTO [dbo].[ScheduledFlight]</span></span><br><span class="line"><span class="string">    ([FlightNumber]</span></span><br><span class="line"><span class="string">    ,[DepartureAirportId]</span></span><br><span class="line"><span class="string">    ,[DepartureHour]</span></span><br><span class="line"><span class="string">    ,[DepartureMinute]</span></span><br><span class="line"><span class="string">    ,[ArrivalAirportId]</span></span><br><span class="line"><span class="string">    ,[ArrivalHour]</span></span><br><span class="line"><span class="string">    ,[ArrivalMinute]</span></span><br><span class="line"><span class="string">    ,[IsSundayFlight]</span></span><br><span class="line"><span class="string">    ,[IsMondayFlight]</span></span><br><span class="line"><span class="string">    ,[IsTuesdayFlight]</span></span><br><span class="line"><span class="string">    ,[IsWednesdayFlight]</span></span><br><span class="line"><span class="string">    ,[IsThursdayFlight]</span></span><br><span class="line"><span class="string">    ,[IsFridayFlight]</span></span><br><span class="line"><span class="string">    ,[IsSaturdayFlight])</span></span><br><span class="line"><span class="string">VALUES</span></span><br><span class="line"><span class="string">    (@FlightNumber</span></span><br><span class="line"><span class="string">    ,@DepartureAirportId</span></span><br><span class="line"><span class="string">    ,@DepartureHour</span></span><br><span class="line"><span class="string">    ,@DepartureMinute</span></span><br><span class="line"><span class="string">    ,@ArrivalAirportId</span></span><br><span class="line"><span class="string">    ,@ArrivalHour</span></span><br><span class="line"><span class="string">    ,@ArrivalMinute</span></span><br><span class="line"><span class="string">    ,@IsSundayFlight</span></span><br><span class="line"><span class="string">    ,@IsMondayFlight</span></span><br><span class="line"><span class="string">    ,@IsTuesdayFlight</span></span><br><span class="line"><span class="string">    ,@IsWednesdayFlight</span></span><br><span class="line"><span class="string">    ,@IsThursdayFlight</span></span><br><span class="line"><span class="string">    ,@IsFridayFlight</span></span><br><span class="line"><span class="string">    ,@IsSaturdayFlight);</span></span><br><span class="line"><span class="string">SELECT CAST(SCOPE_IDENTITY() as int)"</span>;</span><br><span class="line">            newScheduledFlightId = <span class="keyword">await</span> connection.ExecuteScalarAsync&lt;<span class="keyword">int</span>&gt;(insertScheduledFlightSql, model, transaction);</span><br><span class="line"></span><br><span class="line">            model.Id = newScheduledFlightId.Value;</span><br><span class="line">            <span class="keyword">var</span> flights = model.GenerateFlights(DateTime.Now, DateTime.Now.AddMonths(<span class="number">12</span>));</span><br><span class="line"></span><br><span class="line">            <span class="keyword">var</span> insertFlightsSql = <span class="string">@"INSERT INTO [dbo].[Flight]</span></span><br><span class="line"><span class="string">    ([ScheduledFlightId]</span></span><br><span class="line"><span class="string">    ,[Day]</span></span><br><span class="line"><span class="string">    ,[ScheduledDeparture]</span></span><br><span class="line"><span class="string">    ,[ActualDeparture]</span></span><br><span class="line"><span class="string">    ,[ScheduledArrival]</span></span><br><span class="line"><span class="string">    ,[ActualArrival])</span></span><br><span class="line"><span class="string">VALUES</span></span><br><span class="line"><span class="string">    (@ScheduledFlightId</span></span><br><span class="line"><span class="string">    ,@Day</span></span><br><span class="line"><span class="string">    ,@ScheduledDeparture</span></span><br><span class="line"><span class="string">    ,@ActualDeparture</span></span><br><span class="line"><span class="string">    ,@ScheduledArrival</span></span><br><span class="line"><span class="string">    ,@ActualArrival)"</span>;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">await</span> connection.ExecuteAsync(insertFlightsSql, flights, transaction);</span><br><span class="line">            transaction.Commit();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">catch</span> (Exception ex)</span><br><span class="line">        &#123; </span><br><span class="line">            <span class="comment">//Log the exception (ex)</span></span><br><span class="line">            <span class="keyword">try</span></span><br><span class="line">            &#123;</span><br><span class="line">                transaction.Rollback();</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">catch</span> (Exception ex2)</span><br><span class="line">            &#123;</span><br><span class="line">                <span class="comment">// Handle any errors that may have occurred</span></span><br><span class="line">                <span class="comment">// on the server that would cause the rollback to fail, such as</span></span><br><span class="line">                <span class="comment">// a closed connection.</span></span><br><span class="line">                <span class="comment">// Log the exception ex2</span></span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> StatusCode(<span class="number">500</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> Ok(newScheduledFlightId);</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>Managing database transactions in .NET is a deep but well understood topic. We covered the basic pattern above and showed how Dapper can easily participate in a transaction. To learn more about managing database transactions in .NET, check out these docs:</p><ul><li><a href="https://docs.microsoft.com/dotnet/api/system.data.sqlclient.sqlconnection.begintransaction" target="_blank" rel="noopener">SqlConnection.BeginTransaction</a>  </li><li><a href="https://docs.microsoft.com/dotnet/framework/data/adonet/transactions-and-concurrency" target="_blank" rel="noopener">Transactions in ADO.NET</a></li></ul><h2 id="Wrapping-it-up"><a href="#Wrapping-it-up" class="headerlink" title="Wrapping it up"></a>Wrapping it up</h2><p>Using transactions with Dapper is fairly straight forward process. We just need to tell Dapper what transaction to use when executing queries. Now that we know how to use transactions, we can look at some more advanced scenarios like adding concurrency checks to update operations to ensure users aren’t overwriting each other’s changes. </p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;This is a part of a series of blog posts on data access with Dapper. To see the full list of posts, visit the &lt;a href=&quot;https://www.davepa
      
    
    </summary>
    
      <category term="Development" scheme="http://aspnetmonsters.com/categories/Development/"/>
    
    
      <category term="Dapper" scheme="http://aspnetmonsters.com/tags/Dapper/"/>
    
      <category term=".NET" scheme="http://aspnetmonsters.com/tags/NET/"/>
    
      <category term=".NET Core" scheme="http://aspnetmonsters.com/tags/NET-Core/"/>
    
      <category term="Micro ORM" scheme="http://aspnetmonsters.com/tags/Micro-ORM/"/>
    
  </entry>
  
  <entry>
    <title>Basic Insert Update and Delete with Dapper</title>
    <link href="http://aspnetmonsters.com/2019/02/2019-02-04-basic-insert-update-delete-with-dapper/"/>
    <id>http://aspnetmonsters.com/2019/02/2019-02-04-basic-insert-update-delete-with-dapper/</id>
    <published>2019-02-04T13:00:00.000Z</published>
    <updated>2019-04-27T15:03:14.918Z</updated>
    
    <content type="html"><![CDATA[<p>This is a part of a series of blog posts on data access with Dapper. To see the full list of posts, visit the <a href="https://www.davepaquette.com/archive/2018/01/21/exploring-dapper-series.aspx" target="_blank" rel="noopener">Dapper Series Index Page</a>.</p><p>In today’s post, we explore how easy it is to perform basic Insert, Update and Delete operations using the same <code>Aircraft</code> entity that we used in <a href="https://www.davepaquette.com/archive/2018/01/22/loading-an-object-graph-with-dapper.aspx" target="_blank" rel="noopener">the first post in this series</a>. Basically, instead of using Dapper’s <code>QueryAsync</code> extension method that we used to retrieve data, we will use the <code>ExecuteAsync</code> method.</p><p>As a quick reminder, here is the <code>Aircraft</code> class:</p><figure class="highlight csharp"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title">Aircraft</span> </span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> Id &#123; <span class="keyword">get</span>; <span class="keyword">set</span>; &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">string</span> Manufacturer &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">string</span> Model &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">string</span> RegistrationNumber &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> FirstClassCapacity &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> RegularClassCapacity &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> CrewCapacity &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> DateTime ManufactureDate &#123;<span class="keyword">get</span>; <span class="keyword">set</span>; &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> NumberOfEngines &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">&#125;   </span><br></pre></td></tr></table></figure><p><strong>NOTE:</strong> In these examples, I am ignoring some important aspects like validation. I want to focus specifically on the Dapper bits here but validation is really important. In a real-world scenario, you should be validating any data that is passed in to the server. I recommend using <a href="https://fluentvalidation.net/" target="_blank" rel="noopener">Fluent Validation</a>.</p><h2 id="Insert"><a href="#Insert" class="headerlink" title="Insert"></a>Insert</h2><p>Inserting a single new record is really easy. All we need to do is write an <code>INSERT</code> statement with parameters for each column that we want to set. </p><figure class="highlight csharp"><table><tr><td class="code"><pre><span class="line">[<span class="meta">HttpPost()</span>]</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">async</span> Task&lt;IActionResult&gt; <span class="title">Post</span>(<span class="params">[FromBody] Aircraft model</span>)</span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">using</span> (<span class="keyword">var</span> connection = <span class="keyword">new</span> SqlConnection(_connectionString))</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">await</span> connection.OpenAsync();</span><br><span class="line">        <span class="keyword">var</span> sqlStatement = <span class="string">@"</span></span><br><span class="line"><span class="string">INSERT INTO Aircraft </span></span><br><span class="line"><span class="string">(Manufacturer</span></span><br><span class="line"><span class="string">,Model</span></span><br><span class="line"><span class="string">,RegistrationNumber</span></span><br><span class="line"><span class="string">,FirstClassCapacity</span></span><br><span class="line"><span class="string">,RegularClassCapacity</span></span><br><span class="line"><span class="string">,CrewCapacity</span></span><br><span class="line"><span class="string">,ManufactureDate</span></span><br><span class="line"><span class="string">,NumberOfEngines</span></span><br><span class="line"><span class="string">,EmptyWeight</span></span><br><span class="line"><span class="string">,MaxTakeoffWeight)</span></span><br><span class="line"><span class="string">VALUES (@Manufacturer</span></span><br><span class="line"><span class="string">,@Model</span></span><br><span class="line"><span class="string">,@RegistrationNumber</span></span><br><span class="line"><span class="string">,@FirstClassCapacity</span></span><br><span class="line"><span class="string">,@RegularClassCapacity</span></span><br><span class="line"><span class="string">,@CrewCapacity</span></span><br><span class="line"><span class="string">,@ManufactureDate</span></span><br><span class="line"><span class="string">,@NumberOfEngines</span></span><br><span class="line"><span class="string">,@EmptyWeight</span></span><br><span class="line"><span class="string">,@MaxTakeoffWeight)"</span>;</span><br><span class="line">        <span class="keyword">await</span> connection.ExecuteAsync(sqlStatement, model);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> Ok();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>The version of the <code>ExecuteAsync</code> method we used here accepts two parameters: a string containing the SQL statement to execute and an object containing the parameter values to bind to the statement. In this case, it is an instance of the <code>Aircraft</code> class which has properties with names matching the parameters defined in the <code>INSERT</code> statement.</p><p>Our <code>Aircraft</code> table’s <code>Id</code> column is an auto-incremented identity column. That means the primary key is generated by the database when the row is inserted. We will likely need to pass that value back to whoever called the API so they know how to retrieve the newly inserted <code>Aircraft</code>.</p><p>An easy way to get the generated <code>Id</code> is to add <code>SELECT CAST(SCOPE_IDENTITY() as int)</code> after the <code>INSERT</code> statement. The <a href="https://docs.microsoft.com/en-us/sql/t-sql/functions/scope-identity-transact-sql?view=sql-server-2017" target="_blank" rel="noopener"><code>SCOPE_IDENTITY()</code></a> function returns the last identity value that was generated in any table in the current session and current scope. </p><p>Now, since the SQL statement we are executing will be returning a single value (the generated id), we need to call <code>ExecuteScalarAsync&lt;int&gt;</code>. The <code>ExecuteScalarAsync</code> method executes a SQL statement that returns a single value whereas the <code>ExecuteAsync</code> method executes a SQL statement that does not return a value.</p><figure class="highlight csharp"><table><tr><td class="code"><pre><span class="line">[<span class="meta">HttpPost()</span>]</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">async</span> Task&lt;IActionResult&gt; <span class="title">Post</span>(<span class="params">[FromBody] Aircraft model</span>)</span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">int</span> newAircraftId;</span><br><span class="line">    <span class="keyword">using</span> (<span class="keyword">var</span> connection = <span class="keyword">new</span> SqlConnection(_connectionString))</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">await</span> connection.OpenAsync();</span><br><span class="line">        <span class="keyword">var</span> sqlStatement = <span class="string">@"</span></span><br><span class="line"><span class="string">INSERT INTO Aircraft </span></span><br><span class="line"><span class="string">(Manufacturer</span></span><br><span class="line"><span class="string">,Model</span></span><br><span class="line"><span class="string">,RegistrationNumber</span></span><br><span class="line"><span class="string">,FirstClassCapacity</span></span><br><span class="line"><span class="string">,RegularClassCapacity</span></span><br><span class="line"><span class="string">,CrewCapacity</span></span><br><span class="line"><span class="string">,ManufactureDate</span></span><br><span class="line"><span class="string">,NumberOfEngines</span></span><br><span class="line"><span class="string">,EmptyWeight</span></span><br><span class="line"><span class="string">,MaxTakeoffWeight)</span></span><br><span class="line"><span class="string">VALUES (@Manufacturer</span></span><br><span class="line"><span class="string">,@Model</span></span><br><span class="line"><span class="string">,@RegistrationNumber</span></span><br><span class="line"><span class="string">,@FirstClassCapacity</span></span><br><span class="line"><span class="string">,@RegularClassCapacity</span></span><br><span class="line"><span class="string">,@CrewCapacity</span></span><br><span class="line"><span class="string">,@ManufactureDate</span></span><br><span class="line"><span class="string">,@NumberOfEngines</span></span><br><span class="line"><span class="string">,@EmptyWeight</span></span><br><span class="line"><span class="string">,@MaxTakeoffWeight);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">SELECT CAST(SCOPE_IDENTITY() as int)"</span>;</span><br><span class="line">        newAircraftId = <span class="keyword">await</span> connection.ExecuteScalarAsync&lt;<span class="keyword">int</span>&gt;(sqlStatement, model);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> Ok(newAircraftId);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="Update"><a href="#Update" class="headerlink" title="Update"></a>Update</h2><p>Updating an existing entity is similar to inserting. All we need is a SQL statement containing an <code>UPDATE</code> statement that sets the appropriate columns. We also want to make sure we include a <code>WHERE</code> clause limiting the update only to the row with the specified <code>Id</code>.</p><p>Again, the parameters in the SQL statement match the names of the properties in our <code>Aircraft</code> class. All we need to do is call the <code>ExecuteAsync</code> method passing in the SQL statement and the <code>Aircraft</code> entity.</p><figure class="highlight csharp"><table><tr><td class="code"><pre><span class="line"><span class="comment">// PUT api/aircraft/id</span></span><br><span class="line">[<span class="meta">HttpPut(<span class="meta-string">"&#123;id&#125;"</span>)</span>]</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">async</span> Task&lt;IActionResult&gt; <span class="title">Put</span>(<span class="params"><span class="keyword">int</span> id, [FromBody] Aircraft model</span>)</span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (id != model.Id) </span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">return</span> BadRequest();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">using</span> (<span class="keyword">var</span> connection = <span class="keyword">new</span> SqlConnection(_connectionString))</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">await</span> connection.OpenAsync();</span><br><span class="line">        <span class="keyword">var</span> sqlStatement = <span class="string">@"</span></span><br><span class="line"><span class="string">UPDATE Aircraft </span></span><br><span class="line"><span class="string">SET  Manufacturer = @Manufacturer</span></span><br><span class="line"><span class="string">,Model = @Model</span></span><br><span class="line"><span class="string">,RegistrationNumber = @RegistrationNumber </span></span><br><span class="line"><span class="string">,FirstClassCapacity = @FirstClassCapacity</span></span><br><span class="line"><span class="string">,RegularClassCapacity = @RegularClassCapacity</span></span><br><span class="line"><span class="string">,CrewCapacity = @CrewCapacity</span></span><br><span class="line"><span class="string">,ManufactureDate = @ManufactureDate</span></span><br><span class="line"><span class="string">,NumberOfEngines = @NumberOfEngines</span></span><br><span class="line"><span class="string">,EmptyWeight = @EmptyWeight</span></span><br><span class="line"><span class="string">,MaxTakeoffWeight = @MaxTakeoffWeight</span></span><br><span class="line"><span class="string">WHERE Id = @Id"</span>;</span><br><span class="line">        <span class="keyword">await</span> connection.ExecuteAsync(sqlStatement, model);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> Ok();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="Delete"><a href="#Delete" class="headerlink" title="Delete"></a>Delete</h2><p>Deleting an entity is the easiest of the three operations since it only requires a single parameter: the unique Id to identify the entity being deleted. The SQL statement is a simple <code>DELETE</code> with a <code>WHERE</code> clause on the <code>Id</code> column. To execute the delete, call the <code>ExecuteAsync</code> method passing in the SQL statement and an anonymous object containing the <code>Id</code> to delete.</p><figure class="highlight csharp"><table><tr><td class="code"><pre><span class="line"><span class="comment">// DELETE api/aircraft/id</span></span><br><span class="line">[<span class="meta">HttpDelete(<span class="meta-string">"&#123;id&#125;"</span>)</span>]</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">async</span> Task&lt;IActionResult&gt; <span class="title">Delete</span>(<span class="params"><span class="keyword">int</span> id</span>)</span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">using</span> (<span class="keyword">var</span> connection = <span class="keyword">new</span> SqlConnection(_connectionString))</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">await</span> connection.OpenAsync();</span><br><span class="line">        <span class="keyword">var</span> sqlStatement = <span class="string">"DELETE Aircraft WHERE Id = @Id"</span>;</span><br><span class="line">        <span class="keyword">await</span> connection.ExecuteAsync(sqlStatement, <span class="keyword">new</span> &#123;Id = id&#125;);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> Ok();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>I really appreciate how simple delete is using Dapper. When using Entity Framework, delete requires you to first fetch the existing entity, then delete it. That requires 2 round trips to the database while the approach we used here only requires a single round trip.</p><h2 id="Wrapping-it-up"><a href="#Wrapping-it-up" class="headerlink" title="Wrapping it up"></a>Wrapping it up</h2><p>Basic insert, update and delete operations are easy to implement using Dapper. Real world scenarios are often a little more complex and we will dig into some of those scenarios in future posts:</p><ul><li>Bulk inserts, updates and deletes</li><li>Managing transactions</li><li>Optimistic concurrency checks</li></ul>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;This is a part of a series of blog posts on data access with Dapper. To see the full list of posts, visit the &lt;a href=&quot;https://www.davepa
      
    
    </summary>
    
      <category term="Development" scheme="http://aspnetmonsters.com/categories/Development/"/>
    
    
      <category term="Dapper" scheme="http://aspnetmonsters.com/tags/Dapper/"/>
    
      <category term=".NET" scheme="http://aspnetmonsters.com/tags/NET/"/>
    
      <category term=".NET Core" scheme="http://aspnetmonsters.com/tags/NET-Core/"/>
    
      <category term="Micro ORM" scheme="http://aspnetmonsters.com/tags/Micro-ORM/"/>
    
  </entry>
  
  <entry>
    <title>Paging Large Result Sets with Dapper and SQL Server</title>
    <link href="http://aspnetmonsters.com/2019/01/2019-01-28-paging-large-result-sets-with-dapper-and-sql-server/"/>
    <id>http://aspnetmonsters.com/2019/01/2019-01-28-paging-large-result-sets-with-dapper-and-sql-server/</id>
    <published>2019-01-29T02:15:42.000Z</published>
    <updated>2019-04-27T15:03:14.918Z</updated>
    
    <content type="html"><![CDATA[<p>This is a part of a series of blog posts on data access with Dapper. To see the full list of posts, visit the <a href="https://www.davepaquette.com/archive/2018/01/21/exploring-dapper-series.aspx" target="_blank" rel="noopener">Dapper Series Index Page</a>.</p><p>In today’s post, we explore paging through large result sets. Paging is a common technique that is used when dealing with large results sets. Typically, it is not useful for an application to request millions of records at a time because there is no efficient way to deal with all those records in memory all at once. This is especially true when rendering data on a grid in a user interface. The screen can only display a limited number of records at a time so it is generally a bad use of system resources to hold everything in memory when only a small subset of those records can be displayed at any given time.</p><p><img src="https://www.davepaquette.com/images/dapper/paged_table_example.png" alt="Paged Table"><br><em>Source: <a href="https://themes.getbootstrap.com/product/appstack-responsive-admin-template/" target="_blank" rel="noopener">AppStack Bootstrap Template</a></em></p><p>Modern versions of SQL Server support the <a href="https://docs.microsoft.com//sql/t-sql/queries/select-order-by-clause-transact-sql#using-offset-and-fetch-to-limit-the-rows-returned" target="_blank" rel="noopener">OFFSET / FETCH clause</a> to implement query paging.</p><p>In continuing with our airline theme, consider a <code>Flight</code> entity. A <code>Flight</code> represents a particular occurrence of a <code>ScheduledFlight</code> on a particular day. That is, it has a reference to the <code>ScheduledFlight</code> along with some properties indicating the scheduled arrival and departure times. </p><figure class="highlight csharp"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title">Flight</span> </span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> Id &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> ScheduledFlightId &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> ScheduledFlight ScheduledFlight &#123; <span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> DateTime Day &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> DateTime ScheduledDeparture &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> DateTime ScheduledArrival &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight csharp"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title">ScheduledFlight</span> </span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> Id &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">string</span> FlightNumber &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> DepartureAirportId &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> Airport DepartureAirport &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> DepartureHour &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> DepartureMinute &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> ArrivalAirportId &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> Airport ArrivalAirport &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;        </span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> ArrivalHour &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> ArrivalMinute &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">bool</span> IsSundayFlight &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">bool</span> IsMondayFlight &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="comment">// Some other properties</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="Writing-the-query"><a href="#Writing-the-query" class="headerlink" title="Writing the query"></a>Writing the query</h2><p>As we learned in a <a href="https://www.davepaquette.com/archive/2018/02/07/loading-related-entities-many-to-one.aspx" target="_blank" rel="noopener">previous post</a>, we can load the <code>Flight</code> entity along with it’s related <code>ScheduledFlight</code> entity using a technique called multi-mapping. </p><p>In this case, loading all the flights to or from a particular airport, we would use the following query.</p><figure class="highlight sql"><table><tr><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> f.*, sf.*</span><br><span class="line"><span class="keyword">FROM</span> Flight f</span><br><span class="line"><span class="keyword">INNER</span> <span class="keyword">JOIN</span> ScheduledFlight sf <span class="keyword">ON</span> f.ScheduledFlightId = sf.Id</span><br><span class="line"><span class="keyword">INNER</span> <span class="keyword">JOIN</span> Airport a <span class="keyword">ON</span> sf.ArrivalAirportId = a.Id</span><br><span class="line"><span class="keyword">INNER</span> <span class="keyword">JOIN</span> Airport d <span class="keyword">ON</span> sf.DepartureAirportId = d.Id</span><br><span class="line"><span class="keyword">WHERE</span> a.Code = @AirportCode <span class="keyword">OR</span> d.Code = @AirportCode</span><br></pre></td></tr></table></figure><p>But this query could yield more results than we want to deal with at any given time. Using OFFSET/FETCH, we can ask for only a block of results at a time.</p><figure class="highlight sql"><table><tr><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> f.*, sf.*</span><br><span class="line"><span class="keyword">FROM</span> Flight f</span><br><span class="line"><span class="keyword">INNER</span> <span class="keyword">JOIN</span> ScheduledFlight sf <span class="keyword">ON</span> f.ScheduledFlightId = sf.Id</span><br><span class="line"><span class="keyword">INNER</span> <span class="keyword">JOIN</span> Airport a <span class="keyword">ON</span> sf.ArrivalAirportId = a.Id</span><br><span class="line"><span class="keyword">INNER</span> <span class="keyword">JOIN</span> Airport d <span class="keyword">ON</span> sf.DepartureAirportId = d.Id</span><br><span class="line"><span class="keyword">WHERE</span> a.Code = @AirportCode <span class="keyword">OR</span> d.Code = @AirportCode</span><br><span class="line"><span class="keyword">ORDER</span> <span class="keyword">BY</span> f.Day, sf.FlightNumber</span><br><span class="line"><span class="keyword">OFFSET</span> @<span class="keyword">Offset</span> <span class="keyword">ROWS</span></span><br><span class="line"><span class="keyword">FETCH</span> <span class="keyword">NEXT</span> @PageSize <span class="keyword">ROWS</span> <span class="keyword">ONLY</span></span><br></pre></td></tr></table></figure><p>Note that an ORDER BY clause is required when using OFFSET/FETCH. </p><h2 id="Executing-the-Query"><a href="#Executing-the-Query" class="headerlink" title="Executing the Query"></a>Executing the Query</h2><figure class="highlight csharp"><table><tr><td class="code"><pre><span class="line"><span class="comment">//GET api/flights</span></span><br><span class="line">[<span class="meta">HttpGet</span>]</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">async</span> Task&lt;IEnumerable&lt;Flight&gt;&gt; Get(<span class="keyword">string</span> airportCode, <span class="keyword">int</span> page=<span class="number">1</span>, <span class="keyword">int</span> pageSize=<span class="number">10</span>)</span><br><span class="line">&#123;</span><br><span class="line">    IEnumerable&lt;Flight&gt; results;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">using</span> (<span class="keyword">var</span> connection = <span class="keyword">new</span> SqlConnection(_connectionString))</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">await</span> connection.OpenAsync();</span><br><span class="line">        <span class="keyword">var</span> query = <span class="string">@"</span></span><br><span class="line"><span class="string">SELECT f.*, sf.*</span></span><br><span class="line"><span class="string">FROM Flight f</span></span><br><span class="line"><span class="string">INNER JOIN ScheduledFlight sf ON f.ScheduledFlightId = sf.Id</span></span><br><span class="line"><span class="string">INNER JOIN Airport a ON sf.ArrivalAirportId = a.Id</span></span><br><span class="line"><span class="string">INNER JOIN Airport d ON sf.DepartureAirportId = d.Id</span></span><br><span class="line"><span class="string">WHERE a.Code = @AirportCode OR d.Code = @AirportCode</span></span><br><span class="line"><span class="string">ORDER BY f.Day, sf.FlightNumber</span></span><br><span class="line"><span class="string">OFFSET @Offset ROWS</span></span><br><span class="line"><span class="string">FETCH NEXT @PageSize ROWS ONLY;</span></span><br><span class="line"><span class="string">"</span>;</span><br><span class="line"></span><br><span class="line">        results = <span class="keyword">await</span> connection.QueryAsync&lt;Flight, ScheduledFlight, Flight&gt;(query,</span><br><span class="line">          (f, sf) =&gt;</span><br><span class="line">              &#123;</span><br><span class="line">                  f.ScheduledFlight = sf;</span><br><span class="line">                  <span class="keyword">return</span> f;</span><br><span class="line">              &#125;,</span><br><span class="line">            <span class="keyword">new</span> &#123; AirportCode = airportCode,</span><br><span class="line">                              Offset = (page - <span class="number">1</span>) * pageSize,</span><br><span class="line">                              PageSize = pageSize &#125;</span><br><span class="line">            );        </span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> results;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Here we calculate the offset by based on the <code>page</code> and <code>pageSize</code> arguments that were passed in. This allows the caller of the API to request a particular number of rows and the starting point.</p><h2 id="One-step-further"><a href="#One-step-further" class="headerlink" title="One step further"></a>One step further</h2><p>When dealing with paged result sets, it can be useful for the caller of the API to also know the total number of records. Without the total number of records, it would be difficult to know how many records are remaining which in turn makes it difficult to render a paging control, a progress bar or a scroll bar (depending on the use case).</p><p>A technique I like to use here is to have my API return a <code>PagedResults&lt;T&gt;</code> class that contains the list of items for the current page along with the total count.</p><figure class="highlight csharp"><table><tr><td class="code"><pre><span class="line">public class PagedResults&lt;T&gt;</span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">public</span> IEnumerable&lt;T&gt; Items &#123; <span class="keyword">get</span>; <span class="keyword">set</span>; &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> TotalCount &#123; <span class="keyword">get</span>; <span class="keyword">set</span>; &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>To populate this using Dapper, we can add a second result set to the query. That second result set will simply be a count of all the records. Note that the same WHERE clause is used in both queries.</p><figure class="highlight sql"><table><tr><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> f.*, sf.*</span><br><span class="line"><span class="keyword">FROM</span> Flight f</span><br><span class="line"><span class="keyword">INNER</span> <span class="keyword">JOIN</span> ScheduledFlight sf <span class="keyword">ON</span> f.ScheduledFlightId = sf.Id</span><br><span class="line"><span class="keyword">INNER</span> <span class="keyword">JOIN</span> Airport a <span class="keyword">ON</span> sf.ArrivalAirportId = a.Id</span><br><span class="line"><span class="keyword">INNER</span> <span class="keyword">JOIN</span> Airport d <span class="keyword">ON</span> sf.DepartureAirportId = d.Id</span><br><span class="line"><span class="keyword">WHERE</span> a.Code = @AirportCode <span class="keyword">OR</span> d.Code = @AirportCode</span><br><span class="line"><span class="keyword">ORDER</span> <span class="keyword">BY</span> f.Day, sf.FlightNumber</span><br><span class="line"><span class="keyword">OFFSET</span> @<span class="keyword">Offset</span> <span class="keyword">ROWS</span></span><br><span class="line"><span class="keyword">FETCH</span> <span class="keyword">NEXT</span> @PageSize <span class="keyword">ROWS</span> <span class="keyword">ONLY</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">SELECT</span> <span class="keyword">COUNT</span>(*)</span><br><span class="line"><span class="keyword">FROM</span> Flight f</span><br><span class="line"><span class="keyword">INNER</span> <span class="keyword">JOIN</span> ScheduledFlight sf <span class="keyword">ON</span> f.ScheduledFlightId = sf.Id</span><br><span class="line"><span class="keyword">INNER</span> <span class="keyword">JOIN</span> Airport a <span class="keyword">ON</span> sf.ArrivalAirportId = a.Id</span><br><span class="line"><span class="keyword">INNER</span> <span class="keyword">JOIN</span> Airport d <span class="keyword">ON</span> sf.DepartureAirportId = d.Id</span><br><span class="line"><span class="keyword">WHERE</span> a.Code = @AirportCode <span class="keyword">OR</span> d.Code = @AirportCode</span><br></pre></td></tr></table></figure><p>Now in our code that executes the query, we will the <code>QueryMultipleAsync</code> method to execute both SQL statements in a single round trip. </p><figure class="highlight csharp"><table><tr><td class="code"><pre><span class="line"><span class="comment">//GET api/flights</span></span><br><span class="line">[<span class="meta">HttpGet</span>]</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">async</span> Task&lt;PagedResults&lt;Flight&gt;&gt; Get(<span class="keyword">string</span> airportCode, <span class="keyword">int</span> page=<span class="number">1</span>, <span class="keyword">int</span> pageSize=<span class="number">10</span>)</span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">var</span> results = <span class="keyword">new</span> PagedResults&lt;Flight&gt;();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">using</span> (<span class="keyword">var</span> connection = <span class="keyword">new</span> SqlConnection(_connectionString))</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">await</span> connection.OpenAsync();</span><br><span class="line">        <span class="keyword">var</span> query = <span class="string">@"</span></span><br><span class="line"><span class="string">SELECT f.*, sf.*</span></span><br><span class="line"><span class="string">FROM Flight f</span></span><br><span class="line"><span class="string">INNER JOIN ScheduledFlight sf ON f.ScheduledFlightId = sf.Id</span></span><br><span class="line"><span class="string">INNER JOIN Airport a ON sf.ArrivalAirportId = a.Id</span></span><br><span class="line"><span class="string">INNER JOIN Airport d ON sf.DepartureAirportId = d.Id</span></span><br><span class="line"><span class="string">WHERE a.Code = @AirportCode OR d.Code = @AirportCode</span></span><br><span class="line"><span class="string">ORDER BY f.Day, sf.FlightNumber</span></span><br><span class="line"><span class="string">OFFSET @Offset ROWS</span></span><br><span class="line"><span class="string">FETCH NEXT @PageSize ROWS ONLY;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">SELECT COUNT(*)</span></span><br><span class="line"><span class="string">FROM Flight f</span></span><br><span class="line"><span class="string">INNER JOIN ScheduledFlight sf ON f.ScheduledFlightId = sf.Id</span></span><br><span class="line"><span class="string">INNER JOIN Airport a ON sf.ArrivalAirportId = a.Id</span></span><br><span class="line"><span class="string">INNER JOIN Airport d ON sf.DepartureAirportId = d.Id</span></span><br><span class="line"><span class="string">WHERE a.Code = @AirportCode OR d.Code = @AirportCode</span></span><br><span class="line"><span class="string">"</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">using</span> (<span class="keyword">var</span> multi = <span class="keyword">await</span> connection.QueryMultipleAsync(query,</span><br><span class="line">                    <span class="keyword">new</span> &#123; AirportCode = airportCode,</span><br><span class="line">                          Offset = (page - <span class="number">1</span>) * pageSize,</span><br><span class="line">                          PageSize = pageSize &#125;))</span><br><span class="line">        &#123;</span><br><span class="line">            results.Items = multi.Read&lt;Flight, ScheduledFlight, Flight&gt;((f, sf) =&gt;</span><br><span class="line">                &#123;</span><br><span class="line">                    f.ScheduledFlight = sf;</span><br><span class="line">                    <span class="keyword">return</span> f;</span><br><span class="line">                &#125;).ToList();</span><br><span class="line"></span><br><span class="line">            results.TotalCount = multi.ReadFirst&lt;<span class="keyword">int</span>&gt;();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> results;</span><br><span class="line">&#125;</span><br><span class="line">    </span><br></pre></td></tr></table></figure><h2 id="Wrapping-it-up"><a href="#Wrapping-it-up" class="headerlink" title="Wrapping it up"></a>Wrapping it up</h2><p>Paged result sets is an important technique when dealing with large amounts of data. When using a full ORM like Entity Framework, this is implemented easily using LINQ’s  <code>Skip</code> and <code>Take</code> methods. It’s so easy in fact that it can look a little like magic. In reality, it is actually very simple to write your own queries to support paged result sets and execute those queries using Dapper. </p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;This is a part of a series of blog posts on data access with Dapper. To see the full list of posts, visit the &lt;a href=&quot;https://www.davepa
      
    
    </summary>
    
      <category term="Development" scheme="http://aspnetmonsters.com/categories/Development/"/>
    
    
      <category term="Dapper" scheme="http://aspnetmonsters.com/tags/Dapper/"/>
    
      <category term=".NET" scheme="http://aspnetmonsters.com/tags/NET/"/>
    
      <category term=".NET Core" scheme="http://aspnetmonsters.com/tags/NET-Core/"/>
    
      <category term="Micro ORM" scheme="http://aspnetmonsters.com/tags/Micro-ORM/"/>
    
  </entry>
  
  <entry>
    <title>Using Vue as a drop-in replacement for Knockout in an ASP.NET MVC project</title>
    <link href="http://aspnetmonsters.com/2019/01/2019-01-21-using-vue-as-a-drop-in-replacement-for-knockout-in-an-MVC-project/"/>
    <id>http://aspnetmonsters.com/2019/01/2019-01-21-using-vue-as-a-drop-in-replacement-for-knockout-in-an-MVC-project/</id>
    <published>2019-01-21T12:57:12.000Z</published>
    <updated>2019-04-27T15:03:14.918Z</updated>
    
    <content type="html"><![CDATA[<p>So you’re working an existing (brown-field) ASP.NET MVC application. The application’s views are rendered server-side using Razor. Everything is working great and life is good. Suddenly, someone asks for a bit of additional functionality that will require some client side logic. Okay, no big deal. We do this all the time. The question though, is what framework/JavaScript library you will use to implement that client side functionality. </p><p>The default MVC project templates already include jQuery, so you might use that. You’ll probably end up writing a lot of code if you go down that path. Chances are, you will want to use a JavaScript framework that offers two-way data binding between the elements in the DOM to a your model data. </p><p>I seems that for many people, <a href="https://knockoutjs.com/" target="_blank" rel="noopener">Knockout.js</a> is the default library to use in these scenarios. I won’t get into the specifics but I think that Knockout is a little dated and that there are better options these days. If you want to dig into some of the issues with Knockout, you can read <a href="https://westerndevs.com/a-discussion-on-knockout/" target="_blank" rel="noopener">Simon Timms’ rant on the subject</a>.</p><h2 id="Vue-js"><a href="#Vue-js" class="headerlink" title="Vue.js"></a>Vue.js</h2><p>My fellow <a href="https://aspnetmonsters.com">ASP.NET Monster</a> <a href="http://jameschambers.com" target="_blank" rel="noopener">James Chambers</a> recently strongly recommended I take a look at <a href="https://vuejs.org" target="_blank" rel="noopener">Vue.js</a>. I had been meaning to give Vue a try for some time now and I finally had a chance to use it on a recent project. Let me tell you…I love it. </p><p>I love it for a whole bunch of reasons. The <a href="https://vuejs.org/v2/guide/" target="_blank" rel="noopener">documentation</a> is great! It is super easy to get drop in to your existing project and it doesn’t get in the way. For what I needed to do, it just did the job and allowed me to get on with my day. It is also designed to be “incrementally adoptable”, which means you can start out with just using the core view layer, then start pulling in other things like routing and state management if/when you need them. </p><h2 id="A-simple-example"><a href="#A-simple-example" class="headerlink" title="A simple example"></a>A simple example</h2><p>I won’t go into great detail about how to use Vue. If you want a full tutorial, head on over to the <a href="https://vuejs.org/v2/guide/" target="_blank" rel="noopener">Vue docs</a>. What I want to show here is just how simple it is to drop Vue into an existing ASP.NET MVC project and add a bit of client side functionality. </p><p>The simplest example I can think of is a set of cascading dropdowns. Let’s consider a form where a user is asked to enter their Country / Province. When the Country is selected, we would expect the Province dropdown to only display the valid Provinces/States for the selected Country. That probably involves a call to an HTTP endpoint that will return the list of valid values.</p><figure class="highlight csharp"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title">ProvinceLookupController</span> : <span class="title">Controller</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> ActionResult <span class="title">Index</span>(<span class="params"><span class="keyword">string</span> countryCode</span>)</span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">var</span> provinces = ProvinceLookupService.GetProvinces(countryCode);</span><br><span class="line">        <span class="keyword">return</span> Json(provinces, JsonRequestBehavior.AllowGet);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="Including-Vue-in-your-Razor-cshtml-view"><a href="#Including-Vue-in-your-Razor-cshtml-view" class="headerlink" title="Including Vue in your Razor (cshtml) view"></a>Including Vue in your Razor (cshtml) view</h3><p>The easiest way to include Vue on a particular Razor view is to link to the <code>vue.js</code> file from a CDN. You can add the following Script tag to your <code>scripts</code> section.</p><figure class="highlight html"><table><tr><td class="code"><pre><span class="line">@section scripts  &#123;</span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">"https://cdn.jsdelivr.net/npm/vue@2.5.22/dist/vue.js"</span>&gt;</span><span class="undefined"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Be sure to <a href="https://vuejs.org/v2/guide/installation.html" target="_blank" rel="noopener">check the docs</a> to make sure you are referencing the latest version of Vue.</p><h3 id="Binding-data-to-the-our-View"><a href="#Binding-data-to-the-our-View" class="headerlink" title="Binding data to the our View"></a>Binding data to the our View</h3><p>Now that you have included the core Vue library, you can start using Vue to bind DOM elements to model data. </p><p>Start by defining a <code>Vue</code> object in JavaScript. You can add this in a new <code>&lt;script&gt;</code> tag in your <code>scripts</code> section.</p><figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line">@section scripts  &#123;</span><br><span class="line">    &lt;script src=<span class="string">"https://cdn.jsdelivr.net/npm/vue@2.5.22/dist/vue.js"</span>&gt;<span class="xml"><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span></span><br><span class="line"></span><br><span class="line">    &lt;script type=<span class="string">"text/javascript"</span>&gt;</span><br><span class="line">        <span class="keyword">var</span> app = <span class="keyword">new</span> Vue(&#123;</span><br><span class="line">            el: <span class="string">'#vueApp'</span>,</span><br><span class="line">            data: &#123;</span><br><span class="line">                selectedCountryCode: <span class="literal">null</span>,</span><br><span class="line">                countries: [</span><br><span class="line">                    &#123; <span class="attr">code</span>: <span class="string">'ca'</span>, <span class="attr">name</span>: <span class="string">'Canada'</span> &#125;,</span><br><span class="line">                    &#123; <span class="attr">code</span>: <span class="string">'us'</span>, <span class="attr">name</span>: <span class="string">'United States'</span> &#125;</span><br><span class="line">                ]            </span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">    &lt;<span class="regexp">/script&gt;</span></span><br><span class="line"><span class="regexp">&#125;</span></span><br></pre></td></tr></table></figure><p>This <code>Vue</code> object targets the DOM element with id <code>vueApp</code> and contains some simple data. The currently selected country code and the list of countries. </p><p>Now, back in the HTML part of your csthml, wrap the <code>form</code> in a div that has an <code>id=&quot;vueApp&quot;</code>.</p><figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">"vueApp"</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- your form --&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure><p>Next, bind the <code>&lt;select&gt;</code> element to the data in your <code>Vue</code> object. In Vue, data binding is done using a combination of custom attributes that start with <code>v-</code> and the double curly bracket (aka. Mustache) syntax for text. </p><figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"form-group"</span>&gt;</span></span><br><span class="line">    @Html.LabelFor(model =&gt; model.CountryCode, new &#123; @class = "control-label col-md-2" &#125;)</span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"col-md-10"</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">select</span> <span class="attr">id</span>=<span class="string">"CountryCode"</span> <span class="attr">name</span>=<span class="string">"CountryCode"</span> <span class="attr">class</span>=<span class="string">"form-control"</span> </span></span><br><span class="line"><span class="tag">                <span class="attr">v-model</span>=<span class="string">"selectedCountryCode"</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">option</span> <span class="attr">v-for</span>=<span class="string">"country in countries"</span> <span class="attr">v-bind:value</span>=<span class="string">"country.code"</span>&gt;</span></span><br><span class="line">                &#123;&#123; country.name &#125;&#125;</span><br><span class="line">            <span class="tag">&lt;/<span class="name">option</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">select</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure><p>Now, when you run the app, you should see a dropdown containing Canada and United States.</p><p><img src="https://www.davepaquette.com/images/vue/simple-country-dropdown.png" alt="Country Dropdown"></p><h3 id="Adding-functionality"><a href="#Adding-functionality" class="headerlink" title="Adding functionality"></a>Adding functionality</h3><p>Next, you will want to add some client side logic to get the list of valid provinces from the server whenever the selected country changes.</p><p>First, add an empty <code>provinces</code> array and a <code>selectedProvinceCode</code> property to the <code>Vue</code> object’s data.</p><p>Next, add a method called <code>countryChanged</code> to the <code>Vue</code> object. This method will call the <code>ProvinceLookup</code> action method on the server, passing in the <code>selectedCountryCode</code> as a parameter. Assign the response data to the <code>provinces</code> array.</p><figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> app = <span class="keyword">new</span> Vue(&#123;</span><br><span class="line">    el: <span class="string">'#vueApp'</span>,</span><br><span class="line">    data: &#123;</span><br><span class="line">        selectedCountryCode: <span class="literal">null</span>,</span><br><span class="line">        countries: [</span><br><span class="line">            &#123; <span class="attr">code</span>: <span class="string">'ca'</span>, <span class="attr">name</span>: <span class="string">'Canada'</span> &#125;,</span><br><span class="line">            &#123; <span class="attr">code</span>: <span class="string">'us'</span>, <span class="attr">name</span>: <span class="string">'United States'</span> &#125;</span><br><span class="line">        ],</span><br><span class="line">        selectedProvinceCode: <span class="literal">null</span>,</span><br><span class="line">        provinces: []</span><br><span class="line">    &#125;,</span><br><span class="line">    methods: &#123;</span><br><span class="line">        countryChanged: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">            $.getJSON(<span class="string">'@Url.Action("Index", "ProvinceLookup")?countryCode='</span> + <span class="keyword">this</span>.selectedCountryCode, <span class="function"><span class="keyword">function</span> (<span class="params">data</span>) </span>&#123;</span><br><span class="line">                <span class="keyword">this</span>.provinces = data;</span><br><span class="line">            &#125;.bind(<span class="keyword">this</span>));</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>Here I used jQuery to make the call to the server. In the Vue community, <a href="https://github.com/axios/axios" target="_blank" rel="noopener">Axios</a> is a popular library for making HTTP requests.</p><p>Back in the HTML, bind the <code>change</code> event from the country select element to the <code>countryChanged</code> method using the <code>v-on:change</code> attribute.</p><figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">select</span> <span class="attr">id</span>=<span class="string">"CountryCode"</span> <span class="attr">name</span>=<span class="string">"CountryCode"</span> <span class="attr">class</span>=<span class="string">"form-control"</span> </span></span><br><span class="line"><span class="tag">        <span class="attr">v-model</span>=<span class="string">"selectedCountryCode"</span> <span class="attr">v-on:change</span>=<span class="string">"countryChanged"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">option</span> <span class="attr">v-for</span>=<span class="string">"country in countries"</span> <span class="attr">v-bind:value</span>=<span class="string">"country.code"</span>&gt;</span></span><br><span class="line">        &#123;&#123;country.name&#125;&#125;</span><br><span class="line">    <span class="tag">&lt;/<span class="name">option</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">select</span>&gt;</span></span><br></pre></td></tr></table></figure><p>Now you can add a select element for the provinces.<br><figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"form-group"</span>&gt;</span></span><br><span class="line">    @Html.LabelFor(model =&gt; model.ProvinceCode, new &#123; @class = "control-label col-md-2" &#125;)</span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"col-md-10"</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">select</span> <span class="attr">id</span>=<span class="string">"ProvinceCode"</span> <span class="attr">name</span>=<span class="string">"ProvinceCode"</span> <span class="attr">class</span>=<span class="string">"form-control"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">v-model</span>=<span class="string">"selectedProvinceCode"</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">option</span> <span class="attr">v-for</span>=<span class="string">"province in provinces"</span> <span class="attr">v-bind:value</span>=<span class="string">"province.Code"</span>&gt;</span></span><br><span class="line">                &#123;&#123;province.Name&#125;&#125;</span><br><span class="line">            <span class="tag">&lt;/<span class="name">option</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">select</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure></p><p>Voila! You now have a working set of cascading dropdowns.</p><p><img src="https://www.davepaquette.com/images/vue/country-province-dropdown.png" alt="Country Dropdown"></p><h3 id="One-last-thing"><a href="#One-last-thing" class="headerlink" title="One last thing"></a>One last thing</h3><p>You might want to disable the provinces dropdown whenever a request is being made to get the list of provinces for the selected country. You can do this by adding an <code>isProvincesLoading</code> property to the <code>Vue</code> object’s data, then setting that property in the <code>countryChanged</code> method.</p><figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> app = <span class="keyword">new</span> Vue(&#123;</span><br><span class="line">    el: <span class="string">'#vueApp'</span>,</span><br><span class="line">    data: &#123;</span><br><span class="line">        selectedCountryCode: <span class="literal">null</span>,</span><br><span class="line">        countries: [</span><br><span class="line">            &#123; <span class="attr">code</span>: <span class="string">'ca'</span>, <span class="attr">name</span>: <span class="string">'Canada'</span> &#125;,</span><br><span class="line">            &#123; <span class="attr">code</span>: <span class="string">'us'</span>, <span class="attr">name</span>: <span class="string">'United States'</span> &#125;</span><br><span class="line">        ],</span><br><span class="line">        selectedProvinceCode: <span class="literal">null</span>,</span><br><span class="line">        provinces: [],</span><br><span class="line">        isProvincesLoading: <span class="literal">false</span></span><br><span class="line">    &#125;,</span><br><span class="line">    methods: &#123;</span><br><span class="line">        countryChanged: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">            <span class="keyword">this</span>.isProvincesLoading = <span class="literal">true</span>;</span><br><span class="line">            $.getJSON(<span class="string">'@Url.Action("Index", "ProvinceLookup")?countryCode='</span> + <span class="keyword">this</span>.selectedCountryCode, <span class="function"><span class="keyword">function</span> (<span class="params">data</span>) </span>&#123;</span><br><span class="line">                <span class="keyword">this</span>.provinces = data;</span><br><span class="line">                <span class="keyword">this</span>.isProvincesLoading = <span class="literal">false</span>;</span><br><span class="line">            &#125;.bind(<span class="keyword">this</span>));</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>In your HTML, bind the <code>disabled</code> attribute to the <code>isProvincesLoading</code> property.<br><figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"form-group"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">select</span> <span class="attr">id</span>=<span class="string">"ProvinceCode"</span> <span class="attr">name</span>=<span class="string">"ProvinceCode"</span> <span class="attr">class</span>=<span class="string">"form-control"</span></span></span><br><span class="line"><span class="tag">        <span class="attr">v-model</span>=<span class="string">"selectedProvinceCode"</span></span></span><br><span class="line"><span class="tag">        <span class="attr">v-bind:disabled</span>=<span class="string">"isProvincesLoading"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">option</span> <span class="attr">v-for</span>=<span class="string">"province in provinces"</span> <span class="attr">v-bind:value</span>=<span class="string">"province.Code"</span>&gt;</span></span><br><span class="line">        &#123;&#123;province.Name&#125;&#125;</span><br><span class="line">    <span class="tag">&lt;/<span class="name">option</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">select</span>&gt;</span></span><br></pre></td></tr></table></figure></p><h3 id="Putting-it-all-together"><a href="#Putting-it-all-together" class="headerlink" title="Putting it all together"></a>Putting it all together</h3><p>Here is the entire cshtml file.</p><figure class="highlight html"><table><tr><td class="code"><pre><span class="line">@&#123;</span><br><span class="line">    ViewBag.Title = "Location Settings";</span><br><span class="line">&#125;</span><br><span class="line">@model Mvc5VueJsExample.Models.LocationSettingsModel</span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">h2</span>&gt;</span>@ViewBag.Title.<span class="tag">&lt;/<span class="name">h2</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">h3</span>&gt;</span>@ViewBag.Message<span class="tag">&lt;/<span class="name">h3</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">"vueApp"</span>&gt;</span></span><br><span class="line">    @using (Html.BeginForm("LocationSettings", "Home", FormMethod.Post, new &#123; @class = "form" &#125;))</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"form-group"</span>&gt;</span></span><br><span class="line">            @Html.LabelFor(model =&gt; model.CountryCode, new &#123; @class = "control-label col-md-2" &#125;)</span><br><span class="line">            <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"col-md-10"</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">select</span> <span class="attr">id</span>=<span class="string">"CountryCode"</span> <span class="attr">name</span>=<span class="string">"CountryCode"</span> <span class="attr">class</span>=<span class="string">"form-control"</span> </span></span><br><span class="line"><span class="tag">                        <span class="attr">v-model</span>=<span class="string">"selectedCountryCode"</span> <span class="attr">v-on:change</span>=<span class="string">"countryChanged"</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">option</span> <span class="attr">v-for</span>=<span class="string">"country in countries"</span> <span class="attr">v-bind:value</span>=<span class="string">"country.code"</span>&gt;</span></span><br><span class="line">                        &#123;&#123; country.name&#125;&#125;</span><br><span class="line">                    <span class="tag">&lt;/<span class="name">option</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;/<span class="name">select</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"></span><br><span class="line">        <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"form-group"</span>&gt;</span></span><br><span class="line">            @Html.LabelFor(model =&gt; model.ProvinceCode, new &#123; @class = "control-label col-md-2" &#125;)</span><br><span class="line">            <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"col-md-10"</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">select</span> <span class="attr">id</span>=<span class="string">"ProvinceCode"</span> <span class="attr">name</span>=<span class="string">"ProvinceCode"</span> <span class="attr">class</span>=<span class="string">"form-control"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">v-model</span>=<span class="string">"selectedProvinceCode"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">v-bind:disabled</span>=<span class="string">"isProvincesLoading"</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">option</span> <span class="attr">v-for</span>=<span class="string">"province in provinces"</span> <span class="attr">v-bind:value</span>=<span class="string">"province.Code"</span>&gt;</span></span><br><span class="line">                        &#123;&#123;province.Name&#125;&#125;</span><br><span class="line">                    <span class="tag">&lt;/<span class="name">option</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;/<span class="name">select</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">button</span> <span class="attr">class</span>=<span class="string">"btn btn-primary"</span> <span class="attr">type</span>=<span class="string">"submit"</span>&gt;</span>Save<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">@section scripts  &#123;</span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">"https://cdn.jsdelivr.net/npm/vue@2.5.22/dist/vue.js"</span>&gt;</span><span class="undefined"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span> <span class="attr">type</span>=<span class="string">"text/javascript"</span>&gt;</span><span class="undefined"></span></span><br><span class="line"><span class="actionscript">        <span class="keyword">var</span> app = <span class="keyword">new</span> Vue(&#123;</span></span><br><span class="line"><span class="actionscript">            el: <span class="string">'#vueApp'</span>,</span></span><br><span class="line"><span class="undefined">            data: &#123;</span></span><br><span class="line"><span class="actionscript">                selectedCountryCode: <span class="literal">null</span>,</span></span><br><span class="line"><span class="undefined">                countries: [</span></span><br><span class="line"><span class="actionscript">                    &#123; code: <span class="string">'ca'</span>, name: <span class="string">'Canada'</span> &#125;,</span></span><br><span class="line"><span class="actionscript">                    &#123; code: <span class="string">'us'</span>, name: <span class="string">'United States'</span> &#125;</span></span><br><span class="line"><span class="undefined">                ],</span></span><br><span class="line"><span class="actionscript">                selectedProvinceCode: <span class="literal">null</span>,</span></span><br><span class="line"><span class="undefined">                provinces: [],</span></span><br><span class="line"><span class="actionscript">                isProvincesLoading: <span class="literal">false</span></span></span><br><span class="line"><span class="undefined">            &#125;,</span></span><br><span class="line"><span class="undefined">            methods: &#123;</span></span><br><span class="line"><span class="actionscript">                countryChanged: <span class="function"><span class="keyword">function</span> <span class="params">()</span> </span>&#123;</span></span><br><span class="line"><span class="actionscript">                    <span class="keyword">this</span>.isProvincesLoading = <span class="literal">true</span>;</span></span><br><span class="line"><span class="javascript">                    $.getJSON(<span class="string">'@Url.Action("Index", "ProvinceLookup")?countryCode='</span> + <span class="keyword">this</span>.selectedCountryCode, <span class="function"><span class="keyword">function</span> (<span class="params">data</span>) </span>&#123;</span></span><br><span class="line"><span class="actionscript">                        <span class="keyword">this</span>.provinces = data;</span></span><br><span class="line"><span class="actionscript">                        <span class="keyword">this</span>.isProvincesLoading = <span class="literal">false</span>;</span></span><br><span class="line"><span class="actionscript">                    &#125;.bind(<span class="keyword">this</span>));</span></span><br><span class="line"><span class="undefined">                &#125;</span></span><br><span class="line"><span class="undefined">            &#125;</span></span><br><span class="line"><span class="undefined">        &#125;);</span></span><br><span class="line"><span class="undefined">    </span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="Wrapping-it-up"><a href="#Wrapping-it-up" class="headerlink" title="Wrapping it up"></a>Wrapping it up</h2><p>I hope this gives you a taste for how easy it is to work with Vue. My current thinking is that Vue should be the default choice for client side frameworks in existing ASP.NET MVC apps.</p><p>NOTE: This example uses ASP.NET MVC 5 to illustrate that Vue can be used with brownfield applications. It would be just as easy, if not easier, to use Vue in an ASP.NET Core project.</p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;So you’re working an existing (brown-field) ASP.NET MVC application. The application’s views are rendered server-side using Razor. Everyt
      
    
    </summary>
    
      <category term="Development" scheme="http://aspnetmonsters.com/categories/Development/"/>
    
    
      <category term="ASP.NET Core" scheme="http://aspnetmonsters.com/tags/ASP-NET-Core/"/>
    
      <category term="MVC" scheme="http://aspnetmonsters.com/tags/MVC/"/>
    
      <category term="ASP.NET" scheme="http://aspnetmonsters.com/tags/ASP-NET/"/>
    
      <category term="Vue.js" scheme="http://aspnetmonsters.com/tags/Vue-js/"/>
    
      <category term="Javascript" scheme="http://aspnetmonsters.com/tags/Javascript/"/>
    
      <category term="Knockout.js" scheme="http://aspnetmonsters.com/tags/Knockout-js/"/>
    
  </entry>
  
  <entry>
    <title>Blazor Geolocation updated</title>
    <link href="http://aspnetmonsters.com/2018/11/2018-11-27-blazor-geolocation-updated/"/>
    <id>http://aspnetmonsters.com/2018/11/2018-11-27-blazor-geolocation-updated/</id>
    <published>2018-11-28T01:43:50.000Z</published>
    <updated>2019-04-27T15:03:14.918Z</updated>
    
    <content type="html"><![CDATA[<p>There have been significant changes over the past year or so since we published our Geolocation API package for Blazor 0.3. Today we’re pushing version 0.4 which updates the package for use with Blazor 0.7. </p><p>There were quite a few changes to the JavaScript interop APIs since we last published the package - all of them really good. However they were, as you get with alpha software, breaking changes. We now do a better of of serializing payloads too.</p><h2 id="Usage"><a href="#Usage" class="headerlink" title="Usage"></a>Usage</h2><p>1) In your Blazor app, add the <code>AspNetMonsters.Blazor.Geolocation</code> <a href="https://www.nuget.org/packages/AspNetMonsters.Blazor.Geolocation/" target="_blank" rel="noopener">NuGet package</a></p><figure class="highlight stylus"><table><tr><td class="code"><pre><span class="line">Install-Package AspNetMonsters<span class="selector-class">.Blazor</span><span class="selector-class">.Geolocation</span> -IncludePrerelease</span><br></pre></td></tr></table></figure><p>1) In your Blazor app’s <code>Startup.cs</code>, register the ‘LocationService’.</p><figure class="highlight lasso"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="literal">void</span> ConfigureServices(IServiceCollection services)</span><br><span class="line">&#123;</span><br><span class="line">    <span class="params">...</span></span><br><span class="line">    services.AddSingleton&lt;LocationService&gt;();</span><br><span class="line">    <span class="params">...</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>1) Now you can inject the LocationService into any Blazor page and use it like this:</p><figure class="highlight gherkin"><table><tr><td class="code"><pre><span class="line"><span class="meta">@using</span> AspNetMonsters.Blazor.Geolocation</span><br><span class="line"><span class="meta">@inject</span> LocationService  LocationService</span><br><span class="line"><span class="variable">&lt;h3&gt;</span>You are here<span class="variable">&lt;/h3&gt;</span></span><br><span class="line"><span class="variable">&lt;div&gt;</span></span><br><span class="line">Lat: <span class="meta">@location?.Latitude</span> <span class="variable">&lt;br/&gt;</span></span><br><span class="line">Long: <span class="meta">@location?.Longitude</span> <span class="variable">&lt;br /&gt;</span></span><br><span class="line">Accuracy: <span class="meta">@location?.Accuracy</span> <span class="variable">&lt;br /&gt;</span></span><br><span class="line"><span class="variable">&lt;/div&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="meta">@functions</span></span><br><span class="line">&#123;</span><br><span class="line">    Location location;</span><br><span class="line"></span><br><span class="line">    protected override async Task OnInitAsync()</span><br><span class="line">    &#123;</span><br><span class="line">        location = await LocationService.GetLocationAsync();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;There have been significant changes over the past year or so since we published our Geolocation API package for Blazor 0.3. Today we’re p
      
    
    </summary>
    
      <category term="Development" scheme="http://aspnetmonsters.com/categories/Development/"/>
    
    
      <category term="Blazor" scheme="http://aspnetmonsters.com/tags/Blazor/"/>
    
  </entry>
  
  <entry>
    <title>Installing an Azure Web App Site Extension with PowerShell</title>
    <link href="http://aspnetmonsters.com/2018/11/2018-11-13-installing-an-azure-web-app-site-extension-with-powershell/"/>
    <id>http://aspnetmonsters.com/2018/11/2018-11-13-installing-an-azure-web-app-site-extension-with-powershell/</id>
    <published>2018-11-14T01:43:50.000Z</published>
    <updated>2019-04-27T15:03:14.918Z</updated>
    
    <content type="html"><![CDATA[<p>I recently ran into a scenario where I needed to script the installation of a site extension into an existing Azure Web App. Typically, I would use an <a href="https://github.com/tomasr/webapp-appinsights" target="_blank" rel="noopener">Azure ARM deployment to accomplish this</a> but in this particular situation that wasn’t going to work.</p><p>I wanted to install the site extension that enables <a href="https://docs.microsoft.com/en-us/azure/application-insights/app-insights-monitor-performance-live-website-now" target="_blank" rel="noopener">Application Insights Monitoring of a live website</a>. After digging into existing arm templates, I found the name of that extension is <code>Microsoft.ApplicationInsights.AzureWebSites</code>. </p><p>After searching for way too long, I eventually found PowerShell command I needed on a forum somewhere. I can’t find it again so I’m posting this here in hopes that it will be easier for others to find in the future.</p><h2 id="Installing-a-site-extension-to-an-existing-App-Service-Web-App"><a href="#Installing-a-site-extension-to-an-existing-App-Service-Web-App" class="headerlink" title="Installing a site extension to an existing App Service Web App"></a>Installing a site extension to an existing App Service Web App</h2><figure class="highlight vhdl"><table><tr><td class="code"><pre><span class="line"><span class="keyword">New</span>-AzureRmResource -ResourceType <span class="string">"Microsoft.Web/sites/siteextensions"</span> -ResourceGroupName MyResourceGroup -Name <span class="string">"MyWebApp/SiteExtensionName"</span> -ApiVersion <span class="string">"2018-02-01"</span> -<span class="keyword">Force</span></span><br></pre></td></tr></table></figure><p>For example, given a resource group named <code>Test</code>, a web app named <code>testsite</code> and a site extension named  <code>Microsoft.ApplicationInsights.AzureWebSites</code>.</p><figure class="highlight vhdl"><table><tr><td class="code"><pre><span class="line"><span class="keyword">New</span>-AzureRmResource -ResourceType <span class="string">"Microsoft.Web/sites/siteextensions"</span> -ResourceGroupName <span class="string">"Test"</span> -Name <span class="string">"testsite/Microsoft.ApplicationInsights.AzureWebSites"</span> -ApiVersion <span class="string">"2018-02-01"</span> -<span class="keyword">Force</span></span><br></pre></td></tr></table></figure><h2 id="Installing-a-site-extension-to-a-Web-App-Deployment-Slot"><a href="#Installing-a-site-extension-to-a-Web-App-Deployment-Slot" class="headerlink" title="Installing a site extension to a Web App Deployment Slot"></a>Installing a site extension to a Web App Deployment Slot</h2><p>The scenario I ran into was actually attempting to add this site extension to a deployment slot. When you create a deployment slot, it doesn’t copy over any existing site extensions, which is a problem because when you swap your new slot to production, your new production slot ends up losing the site extensions that were in the old production slot.</p><figure class="highlight vhdl"><table><tr><td class="code"><pre><span class="line"><span class="keyword">New</span>-AzureRmResource -ResourceType <span class="string">"Microsoft.Web/sites/slots/siteextensions"</span> -ResourceGroupName MyResourceGroup -Name <span class="string">"MyWebApp/SlotName/SiteExtensionName"</span> -ApiVersion <span class="string">"2018-02-01"</span> -<span class="keyword">Force</span></span><br></pre></td></tr></table></figure><p>Using the same example as above and  a slot named <code>Staging</code>:</p><figure class="highlight vhdl"><table><tr><td class="code"><pre><span class="line"><span class="keyword">New</span>-AzureRmResource -ResourceType <span class="string">"Microsoft.Web/sites/slots/siteextensions"</span> -ResourceGroupName <span class="string">"Test"</span> -Name <span class="string">"testsite/Staging/Microsoft.ApplicationInsights.AzureWebSites"</span> -ApiVersion <span class="string">"2018-02-01"</span> -<span class="keyword">Force</span></span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;I recently ran into a scenario where I needed to script the installation of a site extension into an existing Azure Web App. Typically, I
      
    
    </summary>
    
      <category term="Development" scheme="http://aspnetmonsters.com/categories/Development/"/>
    
    
      <category term="Azure" scheme="http://aspnetmonsters.com/tags/Azure/"/>
    
      <category term="App Service" scheme="http://aspnetmonsters.com/tags/App-Service/"/>
    
      <category term="Web App" scheme="http://aspnetmonsters.com/tags/Web-App/"/>
    
      <category term="Powershell" scheme="http://aspnetmonsters.com/tags/Powershell/"/>
    
      <category term="Application Insights" scheme="http://aspnetmonsters.com/tags/Application-Insights/"/>
    
  </entry>
  
  <entry>
    <title>Loading Related Entities with Dapper Many-to-One - Part 2</title>
    <link href="http://aspnetmonsters.com/2018/04/2018-04-10-loading-related-entities-many-to-one-part-2/"/>
    <id>http://aspnetmonsters.com/2018/04/2018-04-10-loading-related-entities-many-to-one-part-2/</id>
    <published>2018-04-10T23:04:42.000Z</published>
    <updated>2019-04-27T15:03:14.918Z</updated>
    
    <content type="html"><![CDATA[<p>This is a part of a series of blog posts on data access with Dapper. To see the full list of posts, visit the <a href="https://www.davepaquette.com/archive/2018/01/21/exploring-dapper-series.aspx" target="_blank" rel="noopener">Dapper Series Index Page</a>.</p><p><em>Update: April 16, 2018</em> Something really cool happened in the comments. The amazing <a href="https://twitter.com/PathTooLong" target="_blank" rel="noopener">Phil Bolduc</a> very kindly pointed out that the query I wrote was not optimal and as a result, my benchmarks were not showing the best results. He didn’t stop there, he also <a href="https://github.com/AspNetMonsters/DapperSeries/pull/2" target="_blank" rel="noopener">submitted a pull request</a> to the sample repo so I could rerun my benchmarks. Great job Phil and thanks a ton for being constructive in the comments section! I have updated the post to include Phil’s superior query.   </p><p>In today’s post, we look at another option for how to load Many-to-One relationships. In the last post, we used a technique called Multi-Mapping to load related Many-to-One entities. In that post, I had a theory that maybe this approach was not the most efficient method for loading related entities because it duplicated a lot of data.</p><p><img src="https://www.davepaquette.com/images/dapper/flight_to_airport_many_to_one.png" alt="Many-to-One"></p><p>To recap, we would like to load a list of <code>ScheduledFlight</code> entities. A <code>ScheduleFlight</code> has a departure <code>Airport</code> and an arrival <code>Airport</code>.</p><figure class="highlight csharp"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title">ScheduledFlight</span> </span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> Id &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">string</span> FlightNumber &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> Airport DepartureAirport &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> DepartureHour &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> DepartureMinute &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> Airport ArrivalAirport &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;        </span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> ArrivalHour &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> ArrivalMinute &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line"></span><br><span class="line">   <span class="comment">//Other properties omitted for brevity </span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title">Airport</span> </span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> Id &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">string</span> Code &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">string</span> City &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">string</span> ProvinceState &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">string</span> Country &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure> <h2 id="Using-Multiple-Result-Sets"><a href="#Using-Multiple-Result-Sets" class="headerlink" title="Using Multiple Result Sets"></a>Using Multiple Result Sets</h2><p>In the previous post, we loaded the <code>ScheduledFlight</code> entities and all related <code>Airport</code> entities in a single query. In this example we will use 2 separate queries: One for the <code>ScheduledFlight</code> entities, one for the related arrival and departure <code>Airport</code> entities. These 2 queries will all be executed as a single sql command that returns multiple result sets. </p><figure class="highlight sql"><table><tr><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> s.Id, s.FlightNumber, s.DepartureHour, s.DepartureMinute, s.ArrivalHour, s.ArrivalMinute, s.IsSundayFlight, s.IsMondayFlight, s.IsTuesdayFlight, s.IsWednesdayFlight, s.IsThursdayFlight, s.IsFridayFlight, s.IsSaturdayFlight,</span><br><span class="line">s.DepartureAirportId, s.ArrivalAirportId</span><br><span class="line"><span class="keyword">FROM</span> ScheduledFlight s</span><br><span class="line"><span class="keyword">INNER</span> <span class="keyword">JOIN</span> Airport a1</span><br><span class="line"><span class="keyword">ON</span> s.DepartureAirportId = a1.Id</span><br><span class="line">    <span class="keyword">WHERE</span> a1.Code = @FromCode</span><br><span class="line">    </span><br><span class="line"><span class="keyword">SELECT</span> Airport.Id, Airport.Code, Airport.City, Airport.ProvinceState, Airport.Country</span><br><span class="line"><span class="keyword">FROM</span> Airport</span><br><span class="line">  <span class="keyword">WHERE</span> Airport.Id = @DepartureAirportId</span><br><span class="line">    <span class="keyword">OR</span> Airport.Id <span class="keyword">IN</span> (<span class="keyword">SELECT</span> s.ArrivalAirportId</span><br><span class="line">    <span class="keyword">FROM</span> ScheduledFlight s</span><br><span class="line"><span class="keyword">WHERE</span> s.DepartureAirportId = @DepartureAirportId)</span><br></pre></td></tr></table></figure>  <p>Using Dapper’s <code>QueryMultipleAsync</code> method, we pass in 2 arguments: the query and the parameters for the query. </p><figure class="highlight csharp"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">async</span> Task&lt;IEnumerable&lt;ScheduledFlight&gt;&gt; GetAlt(<span class="keyword">string</span> <span class="keyword">from</span>)</span><br><span class="line">&#123;</span><br><span class="line">  IEnumerable&lt;ScheduledFlight&gt; scheduledFlights;</span><br><span class="line">  <span class="keyword">using</span> (<span class="keyword">var</span> connection = <span class="keyword">new</span> SqlConnection(_connectionString))</span><br><span class="line">  &#123;</span><br><span class="line">  <span class="keyword">await</span> connection.OpenAsync();</span><br><span class="line">  <span class="keyword">var</span> query = <span class="string">@"</span></span><br><span class="line"><span class="string">SELECT s.Id, s.FlightNumber, s.DepartureHour, s.DepartureMinute, s.ArrivalHour, s.ArrivalMinute, s.IsSundayFlight, s.IsMondayFlight, s.IsTuesdayFlight, s.IsWednesdayFlight, s.IsThursdayFlight, s.IsFridayFlight, s.IsSaturdayFlight,</span></span><br><span class="line"><span class="string">s.DepartureAirportId, s.ArrivalAirportId</span></span><br><span class="line"><span class="string">FROM ScheduledFlight s</span></span><br><span class="line"><span class="string">INNER JOIN Airport a1</span></span><br><span class="line"><span class="string">ON s.DepartureAirportId = a1.Id</span></span><br><span class="line"><span class="string">    WHERE a1.Code = @FromCode</span></span><br><span class="line"><span class="string">    </span></span><br><span class="line"><span class="string">SELECT Airport.Id, Airport.Code, Airport.City, Airport.ProvinceState, Airport.Country</span></span><br><span class="line"><span class="string">FROM Airport</span></span><br><span class="line"><span class="string">WHERE Airport.Id = @DepartureAirportId</span></span><br><span class="line"><span class="string">  OR Airport.Id IN (SELECT s.ArrivalAirportId</span></span><br><span class="line"><span class="string">       FROM ScheduledFlight s</span></span><br><span class="line"><span class="string">   WHERE s.DepartureAirportId = @DepartureAirportId)"</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">using</span> (<span class="keyword">var</span> multi = <span class="keyword">await</span> connection.QueryMultipleAsync(query, <span class="keyword">new</span>&#123;FromCode = <span class="keyword">from</span>&#125; ))</span><br><span class="line">    &#123;</span><br><span class="line">        scheduledFlights = multi.Read&lt;ScheduledFlight&gt;();</span><br><span class="line">        <span class="keyword">var</span> airports = multi.Read&lt;Airport&gt;().ToDictionary(a =&gt; a.Id);</span><br><span class="line">        <span class="keyword">foreach</span>(<span class="keyword">var</span> flight <span class="keyword">in</span> scheduledFlights)</span><br><span class="line">        &#123;</span><br><span class="line">            flight.ArrivalAirport = airports[flight.ArrivalAirportId];</span><br><span class="line">            flight.DepartureAirport = airports[flight.DepartureAirportId];</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> scheduledFlights;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>  <p>The <code>QueryMultipleAsync</code> method returns a <code>GridReader</code>. The <code>GridReader</code> makes it very easy to map mutliple result sets to different objects using the <code>Read&lt;T&gt;</code> method. When you call the <code>Read&lt;T&gt;</code> method, it will read all the results from the next result set that was returned by the query. In our case, we call <code>Read&lt;ScheduledFlight&gt;</code> to read the first result set and map the results into a collection of <code>ScheduledFlight</code> entities. Next, we call <code>Read&lt;Airport&gt;</code> to read the second result set. We then call <code>ToDictionary(a =&gt; a.Id)</code> to populate those <code>Airport</code> entities into a dictionary. This is to make it easier to read the results when setting the <code>ArrivalAirport</code> and <code>DepartureAirport</code> properties for each <code>ScheduledFlight</code>. </p><p>Finally, we iterate through the scheduled flights and set the <code>ArrivalAirport</code> and <code>DepartureAirport</code> properties to the correct <code>Airport</code> entity.  </p><p>The big difference between this approach and the previous approach is that we no longer have duplicate instances for <code>Airport</code> entities. For example, if the query returned 100 scheduled flights departing from Calgary (YYC), there would be a single instance of the <code>Airport</code> entity representing YYC, whereas the previous approach would have resulted in 100 separate instances of the <code>Airport</code> entity.</p><p>There is also less raw data returned by the query itself since the columns from the <code>Airport</code> table are not repeated in each row from the <code>ScheduleFlight</code> table.</p><h2 id="Comparing-Performance"><a href="#Comparing-Performance" class="headerlink" title="Comparing Performance"></a>Comparing Performance</h2><p>I had a theory that the multi-mapping approach outlined in the previous blog post would be less efficient than the multiple result set approach outlined in this blog post, at least from a memory usage perspective. However, a theory is just theory until it is tested. I was curious and also wanted to make sure I wasn’t misleading anyone so I decided to test things out using <a href="http://benchmarkdotnet.org/" target="_blank" rel="noopener">Benchmark.NET</a>. Using Benchmark.NET, I compared both methods using different sizes of data sets.</p><p>I won’t get into the details of Benchmark.NET. If you want to dig into it in more detail, visit the <a href="http://benchmarkdotnet.org/" target="_blank" rel="noopener">official site</a> and read through the docs. For the purposes of this blog post, the following legend should suffice:</p><figure class="highlight ada"><table><tr><td class="code"><pre><span class="line">Mean      : <span class="type">Arithmetic</span> mean <span class="keyword">of</span> <span class="keyword">all</span> measurements</span><br><span class="line">Error     : <span class="type">Half</span> <span class="keyword">of</span> <span class="number">99.9</span>% confidence interval</span><br><span class="line">StdDev    : <span class="type">Standard</span> deviation <span class="keyword">of</span> <span class="keyword">all</span> measurements</span><br><span class="line">Gen <span class="number">0</span>     : <span class="type">GC</span> Generation <span class="number">0</span> collects per <span class="number">1</span>k Operations</span><br><span class="line">Gen <span class="number">1</span>     : <span class="type">GC</span> Generation <span class="number">1</span> collects per <span class="number">1</span>k Operations</span><br><span class="line">Gen <span class="number">2</span>     : <span class="type">GC</span> Generation <span class="number">2</span> collects per <span class="number">1</span>k Operations</span><br><span class="line">Allocated : <span class="type">Allocated</span> memory per single operation (managed only, inclusive, <span class="number">1</span>KB = <span class="number">1024</span>B)</span><br></pre></td></tr></table></figure><h3 id="10-ScheduledFlight-records"><a href="#10-ScheduledFlight-records" class="headerlink" title="10 ScheduledFlight records"></a>10 ScheduledFlight records</h3><table><thead><tr><th>Method</th><th style="text-align:right">Mean</th><th style="text-align:right">Error</th><th style="text-align:right">StdDev</th><th style="text-align:right">Gen 0</th><th style="text-align:right">Allocated</th></tr></thead><tbody><tr><td>MultiMapping</td><td style="text-align:right">397.5 us</td><td style="text-align:right">3.918 us</td><td style="text-align:right">4.192 us</td><td style="text-align:right">5.8594</td><td style="text-align:right">6.77 KB</td></tr><tr><td>MultipleResultSets</td><td style="text-align:right">414.2 us</td><td style="text-align:right">6.856 us</td><td style="text-align:right">6.077 us</td><td style="text-align:right">4.8828</td><td style="text-align:right">6.69 KB</td></tr></tbody></table><p>As I suspected, the difference is minimal when dealing with small result sets. The results here are in microseconds so in both cases, executing the query and mapping the results takes less 1/2 a millisecond. The mutliple result sets approach takes a little longer, which I kind of expected because of the overhead of creating a dictionary and doing lookups into that dictionary when setting the <code>ArrivalAirport</code> and <code>DepartureAirport</code> properties. The difference is minimal and in a most real world scenarios, this won’t be noticable. What is interesting is that even with this small amount of data, we can see that there is ~1 more Gen 0 garbage collection happening per 1,000 operations. I suspect we will see this creep up as the amount of data increases.</p><h3 id="100-ScheduledFlight-records"><a href="#100-ScheduledFlight-records" class="headerlink" title="100 ScheduledFlight records"></a>100 ScheduledFlight records</h3><table><thead><tr><th>Method</th><th style="text-align:right">Mean</th><th style="text-align:right">Error</th><th style="text-align:right">StdDev</th><th style="text-align:right">Gen 0</th><th style="text-align:right">Gen 1</th><th style="text-align:right">Allocated</th></tr></thead><tbody><tr><td>MultiMapping</td><td style="text-align:right">1.013 ms</td><td style="text-align:right">0.0200 ms</td><td style="text-align:right">0.0287 ms</td><td style="text-align:right">25.3906</td><td style="text-align:right">5.8594</td><td style="text-align:right">6.77 KB</td></tr><tr><td>MultipleResultSets</td><td style="text-align:right">1.114 ms</td><td style="text-align:right">0.0220 ms</td><td style="text-align:right">0.0225 ms</td><td style="text-align:right">15.6250</td><td style="text-align:right">-</td><td style="text-align:right">6.69 KB</td></tr></tbody></table><table><thead><tr><th>Method</th><th style="text-align:right">Mean</th><th style="text-align:right">Error</th><th style="text-align:right">StdDev</th><th style="text-align:right">Gen 0</th><th style="text-align:right">Allocated</th></tr></thead><tbody><tr><td>MultiMapping</td><td style="text-align:right">926.5 us</td><td style="text-align:right">21.481 us</td><td style="text-align:right">32.804 us</td><td style="text-align:right">25.3906</td><td style="text-align:right">6.77 KB</td></tr><tr><td>MultipleResultSets</td><td style="text-align:right">705.9 us</td><td style="text-align:right">7.543 us</td><td style="text-align:right">7.056 us</td><td style="text-align:right">15.6250</td><td style="text-align:right">6.69 KB</td></tr></tbody></table><p> When mapping 100 results, the multiple result sets query is already almost 25% faster. Keep in mind though that both cases are still completing in less than 1ms so this is very much still a micro optimization (pun intented). Either way, less than a millsecond to map 100 records is crazy fast. </p><h3 id="1000-ScheduledFlight-records"><a href="#1000-ScheduledFlight-records" class="headerlink" title="1000 ScheduledFlight records"></a>1000 ScheduledFlight records</h3><table><thead><tr><th>Method</th><th style="text-align:right">Mean</th><th style="text-align:right">Error</th><th style="text-align:right">StdDev</th><th style="text-align:right">Gen 0</th><th style="text-align:right">Gen 1</th><th style="text-align:right">Allocated</th></tr></thead><tbody><tr><td>MultiMapping</td><td style="text-align:right">5.098 ms</td><td style="text-align:right">0.1135 ms</td><td style="text-align:right">0.2720 ms</td><td style="text-align:right">148.4375</td><td style="text-align:right">70.3125</td><td style="text-align:right">6.77 KB</td></tr><tr><td>MultipleResultSets</td><td style="text-align:right">2.809 ms</td><td style="text-align:right">0.0549 ms</td><td style="text-align:right">0.0674 ms</td><td style="text-align:right">109.3750</td><td style="text-align:right">31.2500</td><td style="text-align:right">6.69 KB</td></tr></tbody></table><p>Here we go! Now the multiple result sets approach finally wins out, and you can see why. There are way more Gen 0 and Gen 1 garbage collections happening per 1,000 operations when using the multi-mapping approach. As a result, the multiple result sets approach is nearly twice as fast as the multi mapping approach. </p><h3 id="10-000-ScheduledFlight-records"><a href="#10-000-ScheduledFlight-records" class="headerlink" title="10,000 ScheduledFlight records"></a>10,000 ScheduledFlight records</h3><table><thead><tr><th>Method</th><th style="text-align:right">Mean</th><th style="text-align:right">Error</th><th style="text-align:right">StdDev</th><th style="text-align:right">Gen 0</th><th style="text-align:right">Gen 1</th><th style="text-align:right">Gen 2</th><th style="text-align:right">Allocated</th></tr></thead><tbody><tr><td>MultiMapping</td><td style="text-align:right">56.08 ms</td><td style="text-align:right">1.5822 ms</td><td style="text-align:right">1.4026 ms</td><td style="text-align:right">1687.5000</td><td style="text-align:right">687.5000</td><td style="text-align:right">187.5000</td><td style="text-align:right">6.78 KB</td></tr><tr><td>MultipleResultSets</td><td style="text-align:right">24.93 ms</td><td style="text-align:right">0.1937 ms</td><td style="text-align:right">0.1812 ms</td><td style="text-align:right">843.7500</td><td style="text-align:right">312.5000</td><td style="text-align:right">125.0000</td><td style="text-align:right">6.69 KB </td></tr></tbody></table><p>One last test with 10,000 records shows a more substantial difference. The multiple result sets approach is a full 22ms faster!</p><h2 id="Wrapping-it-up"><a href="#Wrapping-it-up" class="headerlink" title="Wrapping it up"></a>Wrapping it up</h2><p>I think that in most realistic scenarios, there is no discernable difference between the 2 approaches to loading many-to-one related entities. If you loading larger amounts of records into memory in a single query, then the multiple result sets approach will likely give you better performance. If you are dealing with &lt; 100 records per query, then you likely won’t notice a difference. Keep in mind also that your results will vary depending on the specific data you are loading. </p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;This is a part of a series of blog posts on data access with Dapper. To see the full list of posts, visit the &lt;a href=&quot;https://www.davepa
      
    
    </summary>
    
      <category term="Development" scheme="http://aspnetmonsters.com/categories/Development/"/>
    
    
      <category term="Dapper" scheme="http://aspnetmonsters.com/tags/Dapper/"/>
    
      <category term=".NET" scheme="http://aspnetmonsters.com/tags/NET/"/>
    
      <category term=".NET Core" scheme="http://aspnetmonsters.com/tags/NET-Core/"/>
    
      <category term="Micro ORM" scheme="http://aspnetmonsters.com/tags/Micro-ORM/"/>
    
  </entry>
  
  <entry>
    <title>Loading Related Entities: Many-to-One</title>
    <link href="http://aspnetmonsters.com/2018/02/2018-02-07-loading-related-entities-many-to-one/"/>
    <id>http://aspnetmonsters.com/2018/02/2018-02-07-loading-related-entities-many-to-one/</id>
    <published>2018-02-07T06:00:00.000Z</published>
    <updated>2019-04-27T15:03:14.918Z</updated>
    
    <content type="html"><![CDATA[<p>This is a part of a series of blog posts on data access with Dapper. To see the full list of posts, visit the <a href="https://www.davepaquette.com/archive/2018/01/21/exploring-dapper-series.aspx" target="_blank" rel="noopener">Dapper Series Index Page</a>.</p><p>In today’s post, we will start our journey into more complex query scenarios by exploring how to load related entities. There are a few different scenarios to cover here. In this post we will be covering the Many-to-One scenario.</p><p><img src="https://www.davepaquette.com/images/dapper/flight_to_airport_many_to_one.png" alt="Many-to-One"></p><p>Continuing with our sample domain for the ever expanding <em>Air Paquette</em> airline, we will now look at loading a list of <code>ScheduledFlight</code> entities. A <code>ScheduleFlight</code> has a departure <code>Airport</code> and an arrival <code>Airport</code>.</p><figure class="highlight csharp"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title">ScheduledFlight</span> </span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> Id &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">string</span> FlightNumber &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> Airport DepartureAirport &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> DepartureHour &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> DepartureMinute &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> Airport ArrivalAirport &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;        </span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> ArrivalHour &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> ArrivalMinute &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line"></span><br><span class="line">   <span class="comment">//Other properties omitted for brevity </span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title">Airport</span> </span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> Id &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">string</span> Code &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">string</span> City &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">string</span> ProvinceState &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">string</span> Country &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure> <p><em>Side Note:</em> Let’s ignore my poor representation of the arrival and departure times of the scheduled flights. In a future most we might look using Noda Time to properly represent these values.</p><h2 id="Loading-everything-in-a-single-query"><a href="#Loading-everything-in-a-single-query" class="headerlink" title="Loading everything in a single query"></a>Loading everything in a single query</h2><p>Using Dapper, we can easily load a list of <code>ScheduledFlight</code> using a single query. First, we need to craft a query that returns all the columns for a <code>ScheduledFlight</code>, the departure <code>Airport</code> and the arrival <code>Airport</code> in a single row.</p><figure class="highlight sql"><table><tr><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> s.Id, s.FlightNumber, s.DepartureHour, s.DepartureMinute, s.ArrivalHour, s.ArrivalMinute, s.IsSundayFlight, s.IsMondayFlight, s.IsTuesdayFlight, s.IsWednesdayFlight, s.IsThursdayFlight, s.IsFridayFlight, s.IsSaturdayFlight,</span><br><span class="line">       a1.Id, a1.Code, a1.City, a1.ProvinceState, a1.Country,</span><br><span class="line">   a2.Id, a2.Code, a2.City, a2.ProvinceState, a2.Country</span><br><span class="line"><span class="keyword">FROM</span> ScheduledFlight s</span><br><span class="line"><span class="keyword">INNER</span> <span class="keyword">JOIN</span> Airport a1</span><br><span class="line"><span class="keyword">ON</span> s.DepartureAirportId = a1.Id</span><br><span class="line"><span class="keyword">INNER</span> <span class="keyword">JOIN</span> Airport a2</span><br><span class="line"><span class="keyword">ON</span> s.ArrivalAirportId = a2.Id</span><br></pre></td></tr></table></figure><p>We use the <code>QueryAsync</code> method to load a list of <code>ScheduledFlight</code> entities along with their related <code>DepartureAirport</code> and <code>ArrivalAirport</code> entities. The parameters we pass in are a little different from what we saw in our previous posts. </p><figure class="highlight csharp"><table><tr><td class="code"><pre><span class="line">[<span class="meta">HttpGet</span>]</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">async</span> Task&lt;IEnumerable&lt;ScheduledFlight&gt;&gt; Get(<span class="keyword">string</span> <span class="keyword">from</span>)</span><br><span class="line">&#123;</span><br><span class="line">    IEnumerable&lt;ScheduledFlight&gt; scheduledFlights;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">using</span> (<span class="keyword">var</span> connection = <span class="keyword">new</span> SqlConnection(_connectionString))</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">await</span> connection.OpenAsync();</span><br><span class="line"></span><br><span class="line">            <span class="keyword">var</span> query = <span class="string">@"</span></span><br><span class="line"><span class="string">SELECT s.Id, s.FlightNumber, s.DepartureHour, s.DepartureMinute, s.ArrivalHour, s.ArrivalMinute, s.IsSundayFlight, s.IsMondayFlight, s.IsTuesdayFlight, s.IsWednesdayFlight, s.IsThursdayFlight, s.IsFridayFlight, s.IsSaturdayFlight,</span></span><br><span class="line"><span class="string">     a1.Id, a1.Code, a1.City, a1.ProvinceState, a1.Country,</span></span><br><span class="line"><span class="string">     a2.Id, a2.Code, a2.City, a2.ProvinceState, a2.Country</span></span><br><span class="line"><span class="string">FROM ScheduledFlight s</span></span><br><span class="line"><span class="string">     INNER JOIN Airport a1</span></span><br><span class="line"><span class="string">          ON s.DepartureAirportId = a1.Id</span></span><br><span class="line"><span class="string">    INNER JOIN Airport a2</span></span><br><span class="line"><span class="string">          ON s.ArrivalAirportId = a2.Id</span></span><br><span class="line"><span class="string">WHERE a1.Code = @FromCode"</span>;</span><br><span class="line"></span><br><span class="line">        scheduledFlights = </span><br><span class="line">            <span class="keyword">await</span> connection.QueryAsync&lt;ScheduledFlight, Airport, Airport, ScheduledFlight&gt;(query,</span><br><span class="line">                    (flight, departure, arrival ) =&gt; &#123;</span><br><span class="line">                        flight.DepartureAirport = departure;</span><br><span class="line">                        flight.ArrivalAirport = arrival;</span><br><span class="line">                        <span class="keyword">return</span> flight;</span><br><span class="line">                    &#125;,</span><br><span class="line">                    <span class="keyword">new</span>&#123;FromCode = <span class="keyword">from</span>&#125; );</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> scheduledFlights;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>First, instead of a single type parameter <code>&lt;ScheduledFlight&gt;</code>, we need to provide a series of type parameters: <code>&lt;ScheduledFlight, Airport, Airport, ScheduledFlight&gt;</code>. The first 3 parameters specify the types that are contained in each row that the query returns. In this example, each row contains columns that will be mapped to <code>ScheduledFlight</code> and 2 <code>Airports</code>. The order matters here, and Dapper assumes that when it seems a column named <code>Id</code> then it is looking at columns for the next entity type. In the example below, the columns from <code>Id</code> to <code>IsSaturdayFlight</code> are mapped to a <code>ScheduledFlight</code> entity. The next 5 columns <code>Id, Code, City, ProvinceState, Country</code> are mapped to an <code>Airport</code> entity, and the last 5 columns are mapped to a second <code>Airport</code> entity. If you aren’t using <code>Id</code>, you can use the optional <code>splitOn</code> argument to specify the column names that Dapper should use to identity the start of each entity type.</p><p>What’s that last type parameter? Why do we need to specify <code>ScheduledFlight</code> again? Well, I’m glad you asked. The thing about Dapper is that it doesn’t actually know much about the structure of our entities so we need to tell it how to wire up the 3 entities that it just mapped from a row. That last <code>ScheduledFlight</code> type parameter is telling Dapper that <code>ScheduledFlight</code> is ultimately the entity we want to return from this query. It is important for the second argument that is passed to the <code>QueryAsync</code> method. </p><p>That second argument is a function that takes in the 3 entities that were mapped back from that row and returns and entity of the type that was specified as the last type parameter. In this case, we assign the first <code>Airport</code> to the flight’s <code>DepartureAirport</code> property and assign the second <code>Airport</code> to the flight’s <code>ArrivalAiport</code> parameter, then we return the flight that was passed in.</p><figure class="highlight csharp"><table><tr><td class="code"><pre><span class="line">(flight, departure, arrival ) =&gt; &#123;</span><br><span class="line">    flight.DepartureAirport = departure;</span><br><span class="line">    flight.ArrivalAirport = arrival;</span><br><span class="line">    <span class="keyword">return</span> flight;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>The first argument argument passed to the <code>QueryAsync</code> method is the SQL query, and the third argument is an anonymous object containing any parameters for that query. Those arguments are really no different than the simple examples we saw in <a href="https://www.davepaquette.com/archive/2018/01/22/loading-an-object-graph-with-dapper.aspx" target="_blank" rel="noopener">previous blog posts</a>.</p><h2 id="Wrapping-it-up"><a href="#Wrapping-it-up" class="headerlink" title="Wrapping it up"></a>Wrapping it up</h2><p>Dapper refers to this technique as <a href="https://github.com/StackExchange/Dapper#multi-mapping" target="_blank" rel="noopener">Multi Mapping</a>. I think it’s called that because we are mapping multiple entities from each row that the query returns. In a fully featured ORM like Entity Framework, we call this feature Eager Loading. It is an optimization technique that avoids the need for multiple queries in order to load an entity and it’s associated entities. </p><p>This approach is simple enough to use and it does reduce the number of round trips needed to load a set of entities. It does, however, come at a cost. Specifically, the results of the query end up causing some duplication of data. As you can see below, the data for the Calgary and Vancouver airports is repeated in each row. </p><p><img src="https://www.davepaquette.com/images/dapper/multi_mapping_data_duplication.png" alt="Data Duplication"></p><p>This isn’t a huge problem if the result set only contains 3 rows but it can become problematic when dealing with large result sets. In addition to creating somewhat bloated result sets, Dapper will also create new instances of those related entities for each row in the result set. In the example above, we would end up with 3 instances of the <code>Airport</code> class representing YYC - Calgary and 3 instances of the <code>Airport</code> class representing YVR - Vancouver. Again, this isn’t necessarily a big problem when we have 3 rows in the result set but with larger result sets it could cause your application to use a lot more memory than necessary. </p><p>It is worth considering the cost associated with this approach. Given the added memory cost, this approach might be better suited to One-to-One associations rather than the Many-to-One example we talked about in this post. In the next post, we will explore an alternate approach that is more memory efficient but probably a little more costly on the CPU for the mapping. </p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;This is a part of a series of blog posts on data access with Dapper. To see the full list of posts, visit the &lt;a href=&quot;https://www.davepa
      
    
    </summary>
    
      <category term="Development" scheme="http://aspnetmonsters.com/categories/Development/"/>
    
    
      <category term="Dapper" scheme="http://aspnetmonsters.com/tags/Dapper/"/>
    
      <category term=".NET" scheme="http://aspnetmonsters.com/tags/NET/"/>
    
      <category term=".NET Core" scheme="http://aspnetmonsters.com/tags/NET-Core/"/>
    
      <category term="Micro ORM" scheme="http://aspnetmonsters.com/tags/Micro-ORM/"/>
    
  </entry>
  
  <entry>
    <title>Using Stored Procedures to Load Data with Dapper</title>
    <link href="http://aspnetmonsters.com/2018/01/2018-01-28-using-stored-procedures-to-load-data-with-dapper/"/>
    <id>http://aspnetmonsters.com/2018/01/2018-01-28-using-stored-procedures-to-load-data-with-dapper/</id>
    <published>2018-01-29T02:00:01.000Z</published>
    <updated>2019-04-27T15:03:14.918Z</updated>
    
    <content type="html"><![CDATA[<p>This is a part of a series of blog posts on data access with Dapper. To see the full list of posts, visit the <a href="https://www.davepaquette.com/archive/2018/01/21/exploring-dapper-series.aspx" target="_blank" rel="noopener">Dapper Series Index Page</a>.</p><p>Let’s just get this one out of the way early. Stored procedures are not my favorite way to get data from SQL Server but there was a time when they were extremely popular. They are still heavily used today and so this series would not be complete without covering how to use stored procedures with Dapper. </p><h2 id="A-Simple-Example"><a href="#A-Simple-Example" class="headerlink" title="A Simple Example"></a>A Simple Example</h2><p>Let’s imagine a simple stored procedure that allows us to query for <code>Aircraft</code> by model.</p><figure class="highlight sql"><table><tr><td class="code"><pre><span class="line"><span class="keyword">CREATE</span> <span class="keyword">PROCEDURE</span> GetAircraftByModel @<span class="keyword">Model</span> <span class="keyword">NVARCHAR</span>(<span class="number">255</span>) <span class="keyword">AS</span></span><br><span class="line"><span class="keyword">BEGIN</span></span><br><span class="line">    <span class="keyword">SELECT</span> </span><br><span class="line">       <span class="keyword">Id</span></span><br><span class="line">      ,Manufacturer</span><br><span class="line">      ,<span class="keyword">Model</span></span><br><span class="line">      ,RegistrationNumber</span><br><span class="line">      ,FirstClassCapacity</span><br><span class="line">      ,RegularClassCapacity</span><br><span class="line">      ,CrewCapacity</span><br><span class="line">      ,ManufactureDate</span><br><span class="line">      ,NumberOfEngines</span><br><span class="line">      ,EmptyWeight</span><br><span class="line">      ,MaxTakeoffWeight</span><br><span class="line">    <span class="keyword">FROM</span> Aircraft a</span><br><span class="line">    <span class="keyword">WHERE</span> a.Model = @<span class="keyword">Model</span></span><br><span class="line"><span class="keyword">END</span></span><br></pre></td></tr></table></figure><p>To execute this stored procedure and map the results to a collection of <code>Aircraft</code> objects, use the <code>QueryAsync</code> method almost exactly like we did in the <a href="https://www.davepaquette.com/archive/2018/01/22/loading-an-object-graph-with-dapper.aspx" target="_blank" rel="noopener">last post</a>. </p><figure class="highlight csharp"><table><tr><td class="code"><pre><span class="line"><span class="comment">//GET api/aircraft</span></span><br><span class="line">[<span class="meta">HttpGet</span>]</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">async</span> Task&lt;IEnumerable&lt;Aircraft&gt;&gt; Get(<span class="keyword">string</span> model)</span><br><span class="line">&#123;</span><br><span class="line">    IEnumerable&lt;Aircraft&gt; aircraft;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">using</span> (<span class="keyword">var</span> connection = <span class="keyword">new</span> SqlConnection(_connectionString))</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">await</span> connection.OpenAsync();</span><br><span class="line"></span><br><span class="line">        aircraft = <span class="keyword">await</span> connection.QueryAsync&lt;Aircraft&gt;(<span class="string">"GetAircraftByModel"</span>,</span><br><span class="line">                        <span class="keyword">new</span> &#123;Model = model&#125;, </span><br><span class="line">                        commandType: CommandType.StoredProcedure);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> aircraft;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Instead of passing in the raw SQL statement, we simply pass in the name of the stored procedure. We also pass in an object that has properties for each of the stored procedures arguments, in this case <code>new {Model = model}</code> maps the <code>model</code> variable to the stored procedure’s <code>@Model</code> argument. Finally, we specify the <code>commandType</code> as <code>CommandType.StoredProcedure</code>. </p><h2 id="Wrapping-it-up"><a href="#Wrapping-it-up" class="headerlink" title="Wrapping it up"></a>Wrapping it up</h2><p>That’s all there is to using stored procedures with Dapper. As much as I dislike using stored procedures in my applications, I often do have to call stored procedures to fetch data from legacy databases. When that situation comes up, Dapper is my tool of choice. </p><p>Stay tuned for the next installment in this Dapper series. Comment below if there is a specific topic you would like covered.</p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;This is a part of a series of blog posts on data access with Dapper. To see the full list of posts, visit the &lt;a href=&quot;https://www.davepa
      
    
    </summary>
    
      <category term="Development" scheme="http://aspnetmonsters.com/categories/Development/"/>
    
    
      <category term="Dapper" scheme="http://aspnetmonsters.com/tags/Dapper/"/>
    
      <category term=".NET" scheme="http://aspnetmonsters.com/tags/NET/"/>
    
      <category term=".NET Core" scheme="http://aspnetmonsters.com/tags/NET-Core/"/>
    
      <category term="Micro ORM" scheme="http://aspnetmonsters.com/tags/Micro-ORM/"/>
    
  </entry>
  
  <entry>
    <title>Loading an Object From SQL Server Using Dapper</title>
    <link href="http://aspnetmonsters.com/2018/01/2018-01-22-loading-an-object-graph-with-dapper/"/>
    <id>http://aspnetmonsters.com/2018/01/2018-01-22-loading-an-object-graph-with-dapper/</id>
    <published>2018-01-23T03:30:00.000Z</published>
    <updated>2019-04-27T15:03:14.918Z</updated>
    
    <content type="html"><![CDATA[<p>I was recently asked to create a read-only web API to expose some parts of a system’s data model to third party developers. While <a href="https://docs.microsoft.com/en-us/ef/" target="_blank" rel="noopener">Entity Framework</a> is often my go-to tool for data access, I thought this was a good scenario to use Dapper instead. This series of blog posts explores dapper and how you might use it in your application. To see the full list of posts, visit the <a href="https://www.davepaquette.com/archive/2018/01/21/exploring-dapper-series.aspx" target="_blank" rel="noopener">Dapper Series Index Page</a>.</p><p> Today, we will start with the basics of loading a mapping and database table to a C# class. </p><h1 id="What-is-Dapper"><a href="#What-is-Dapper" class="headerlink" title="What is Dapper?"></a>What is Dapper?</h1><p><a href="https://github.com/StackExchange/Dapper" target="_blank" rel="noopener">Dapper</a> calls itself a simple object mapper for .NET and is usually lumped into the category of micro ORM (Object Relational Mapper). When compared to a fully featured ORM like Entity Framework, Dapper lacks certain features like change-tracking, lazy loading and the ability to translate complex LINQ expressions to SQL queries. The fact that Dapper is missing these features is probably the single best thing about Dapper. While it might seem like you’re giving up a lot, you are also gaining a lot by dropping those types of features. Dapper is fast since it doesn’t do a lot of the magic that Entity Framework does under the covers. Since there is less magic, Dapper is also a lot easier to understand which can lead to lower maintenance costs and maybe even fewer bugs. </p><h1 id="How-does-it-work"><a href="#How-does-it-work" class="headerlink" title="How does it work?"></a>How does it work?</h1><p>Throughout this series we will build on an example domain for an airline. All airlines need to manage a fleet of aircraft, so let’s start there. Imagine a database with a table named <code>Aircraft</code> and a C# class with property names that match the column names of the <code>Aircraft</code> table.</p><figure class="highlight sql"><table><tr><td class="code"><pre><span class="line"><span class="keyword">CREATE</span> <span class="keyword">TABLE</span> Aircraft</span><br><span class="line">    (</span><br><span class="line">        <span class="keyword">Id</span> <span class="built_in">int</span> <span class="keyword">not</span> <span class="literal">null</span> <span class="keyword">IDENTITY</span>(<span class="number">1</span>,<span class="number">1</span>) <span class="keyword">CONSTRAINT</span> pk_Aircraft_Id PRIMARY <span class="keyword">KEY</span>,</span><br><span class="line">        Manufacturer <span class="keyword">nvarchar</span>(<span class="number">255</span>),</span><br><span class="line">        <span class="keyword">Model</span> <span class="keyword">nvarchar</span>(<span class="number">255</span>),</span><br><span class="line">        RegistrationNumber <span class="keyword">nvarchar</span>(<span class="number">50</span>),</span><br><span class="line">        FirstClassCapacity <span class="built_in">int</span>,</span><br><span class="line">        RegularClassCapacity <span class="built_in">int</span>,</span><br><span class="line">        CrewCapacity <span class="built_in">int</span>,</span><br><span class="line">        ManufactureDate <span class="built_in">date</span>,</span><br><span class="line">        NumberOfEngines <span class="built_in">int</span>,</span><br><span class="line">        EmptyWeight <span class="built_in">int</span>,</span><br><span class="line">        MaxTakeoffWeight <span class="built_in">int</span></span><br><span class="line">    )</span><br></pre></td></tr></table></figure><figure class="highlight csharp"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title">Aircraft</span> </span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> Id &#123; <span class="keyword">get</span>; <span class="keyword">set</span>; &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">string</span> Manufacturer &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">string</span> Model &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">string</span> RegistrationNumber &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> FirstClassCapacity &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> RegularClassCapacity &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> CrewCapacity &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> DateTime ManufactureDate &#123;<span class="keyword">get</span>; <span class="keyword">set</span>; &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> NumberOfEngines &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> EmptyWeight &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> MaxTakeoffWeight &#123;<span class="keyword">get</span>; <span class="keyword">set</span>;&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="Installing-Dapper"><a href="#Installing-Dapper" class="headerlink" title="Installing Dapper"></a>Installing Dapper</h2><p>Dapper is available as a <a href="https://www.nuget.org/packages/Dapper/" target="_blank" rel="noopener">Nuget package</a>. To use Dapper, all you need to do is add the <code>Dapper</code> package to your project.</p><p> <strong>.NET Core CLI</strong>: <code>dotnet add package Dapper</code></p><p><strong>Package Manager Console</strong>: <code>Install-Package Dapper</code></p><h2 id="Querying-a-single-object"><a href="#Querying-a-single-object" class="headerlink" title="Querying a single object"></a>Querying a single object</h2><p>Dapper provides a set of extension methods for .NET’s <code>IDbConnection</code> interface. For our first task, we want to execute a query to return the data for a single row from the <code>Aircraft</code> table and place the results in an instance of the <code>Aircraft</code> class. This is easily accomplished using Dapper’s <code>QuerySingleAsync</code> method.</p><figure class="highlight csharp"><table><tr><td class="code"><pre><span class="line">[<span class="meta">HttpGet(<span class="meta-string">"&#123;id&#125;"</span>)</span>]</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">async</span> Task&lt;Aircraft&gt; <span class="title">Get</span>(<span class="params"><span class="keyword">int</span> id</span>)</span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">  Aircraft aircraft;</span><br><span class="line">  <span class="keyword">using</span> (<span class="keyword">var</span> connection = <span class="keyword">new</span> SqlConnection(_connectionString))</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="keyword">await</span> connection.OpenAsync();</span><br><span class="line">    <span class="keyword">var</span> query = <span class="string">@"</span></span><br><span class="line"><span class="string">SELECT </span></span><br><span class="line"><span class="string">       Id</span></span><br><span class="line"><span class="string">      ,Manufacturer</span></span><br><span class="line"><span class="string">      ,Model</span></span><br><span class="line"><span class="string">      ,RegistrationNumber</span></span><br><span class="line"><span class="string">      ,FirstClassCapacity</span></span><br><span class="line"><span class="string">      ,RegularClassCapacity</span></span><br><span class="line"><span class="string">      ,CrewCapacity</span></span><br><span class="line"><span class="string">      ,ManufactureDate</span></span><br><span class="line"><span class="string">      ,NumberOfEngines</span></span><br><span class="line"><span class="string">      ,EmptyWeight</span></span><br><span class="line"><span class="string">      ,MaxTakeoffWeight</span></span><br><span class="line"><span class="string">  FROM Aircraft WHERE Id = @Id"</span>;</span><br><span class="line"></span><br><span class="line">    aircraft = <span class="keyword">await</span> connection.QuerySingleAsync&lt;Aircraft&gt;(query, <span class="keyword">new</span> &#123;Id = id&#125;);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> aircraft;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure> <p>Before we can call Dapper’s <code>QuerySingleASync</code> method, we need an instance of an open <code>SqlConnection</code>. If you are an Entity Framework user, you might not be used to working directly with the <code>SqlConnection</code> class because Entity Framework generally manages connections for you. All we need to do is create a new <code>SqlConnection</code>, passing in the connection string, then call <code>OpenAsync</code> to open that connection. We wrap the connection in a <code>using</code> statement to ensure that <code>connection.Dispose()</code> is called when we are done with the connection. This is important because it ensures the connection is returned to the connection pool that is managed by .NET. If you forget to do this, you will quickly run into problems where your application is not able to connect to the database because the connection pool is starved. Check out the <a href="https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/sql-server-connection-pooling" target="_blank" rel="noopener">.NET Docs</a> for  more information on connection pooling.</p><p>We will use the following pattern throughout this series of blogs posts:</p><figure class="highlight csharp"><table><tr><td class="code"><pre><span class="line"><span class="keyword">using</span>(<span class="keyword">var</span> connection = <span class="keyword">new</span> SqlConnection(_connectionString))</span><br><span class="line">&#123;</span><br><span class="line">  <span class="keyword">await</span> connection.OpenAsync();</span><br><span class="line">  <span class="comment">//Do Dapper Things</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>As @Disman pointed out in the comments, it is not necessary to call <code>connection.OpenAsync()</code>. If the connection is not already opened, Dapper will call <code>OpenAsync</code> for you. Call me old fashioned but I think that whoever created the connection should be the one responsible for opening it, that’s why I like to open the connection before calling Dapper.</p><p>Let’s get back to our example. To query for a single <code>Aircraft</code>, we call the <code>QuerySingleAsync</code> method, specifying the <code>Aircraft</code> type parameter. The type parameter tells Dapper what class type to return. Dapper will take the results of the query that gets executed and map the column values to properties of the specified type. We also pass in two arguments. The first is the query that will return a single row based on a specified <code>@Id</code> parameter.</p><figure class="highlight csharp"><table><tr><td class="code"><pre><span class="line">SELECT </span><br><span class="line">       Id</span><br><span class="line">      ,Manufacturer</span><br><span class="line">      ,Model</span><br><span class="line">      ,RegistrationNumber</span><br><span class="line">      ,FirstClassCapacity</span><br><span class="line">      ,RegularClassCapacity</span><br><span class="line">      ,CrewCapacity</span><br><span class="line">      ,ManufactureDate</span><br><span class="line">      ,NumberOfEngines</span><br><span class="line">      ,EmptyWeight</span><br><span class="line">      ,MaxTakeoffWeight</span><br><span class="line">  FROM Aircraft WHERE Id = @Id</span><br></pre></td></tr></table></figure> <p>The next parameter is an anonymous class containing properties that will map to the parameters of the query. </p><figure class="highlight csharp"><table><tr><td class="code"><pre><span class="line"><span class="keyword">new</span> &#123;Id = id&#125;</span><br></pre></td></tr></table></figure><p>Passing the parameters in this way ensures that our queries are not susceptible to SQL injection attacks.</p><p>That’s really all there is to it. As long as the column names and data types match the property of your class, Dapper takes care of executing the query, creating an instance of the <code>Aircraft</code> class and setting all the properties.</p><p>If the query doesn’t contain return any results, Dapper will throw an <code>InvalidOperationException</code>.</p><blockquote><p>InvalidOperationException: Sequence contains no elements</p></blockquote><p>If you prefer that Dapper returns null when there are no results, use the <code>QuerySingleOrDefaultAsnyc</code> method instead.</p><h2 id="Querying-a-list-of-objects"><a href="#Querying-a-list-of-objects" class="headerlink" title="Querying a list of objects"></a>Querying a list of objects</h2><p>Querying for a list of objects is just as easy as querying for a single object. Simply call the <code>QueryAsync</code> method as follows.</p><figure class="highlight csharp"><table><tr><td class="code"><pre><span class="line">[<span class="meta">HttpGet</span>]</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">async</span> Task&lt;IEnumerable&lt;Aircraft&gt;&gt; Get()</span><br><span class="line">&#123;</span><br><span class="line">  IEnumerable&lt;Aircraft&gt; aircraft;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">using</span> (<span class="keyword">var</span> connection = <span class="keyword">new</span> SqlConnection(_connectionString))</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="keyword">await</span> connection.OpenAsync();</span><br><span class="line">    <span class="keyword">var</span> query = <span class="string">@"</span></span><br><span class="line"><span class="string">SELECT </span></span><br><span class="line"><span class="string">       Id</span></span><br><span class="line"><span class="string">      ,Manufacturer</span></span><br><span class="line"><span class="string">      ,Model</span></span><br><span class="line"><span class="string">      ,RegistrationNumber</span></span><br><span class="line"><span class="string">      ,FirstClassCapacity</span></span><br><span class="line"><span class="string">      ,RegularClassCapacity</span></span><br><span class="line"><span class="string">      ,CrewCapacity</span></span><br><span class="line"><span class="string">      ,ManufactureDate</span></span><br><span class="line"><span class="string">      ,NumberOfEngines</span></span><br><span class="line"><span class="string">      ,EmptyWeight</span></span><br><span class="line"><span class="string">      ,MaxTakeoffWeight</span></span><br><span class="line"><span class="string">  FROM Aircraft"</span>;</span><br><span class="line">    aircraft = <span class="keyword">await</span> connection.QueryAsync&lt;Aircraft&gt;(query);</span><br><span class="line">    &#125;</span><br><span class="line">  <span class="keyword">return</span> aircraft;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>In this case, the query did not contain any parameters. If it did, we would pass those parameters in as an argument to the <code>QueryAsync</code> method just like we did for the <code>QuerySingleAsync</code> method.</p><h2 id="What’s-next"><a href="#What’s-next" class="headerlink" title="What’s next?"></a>What’s next?</h2><p>This is just the beginning of what I expect will be a long series of blog posts. You can follow along on this blog and you can track the <a href="https://github.com/AspNetMonsters/DapperSeries" target="_blank" rel="noopener">sample code on GitHub</a>. </p><p>Leave a comment below if there is a topic you would like me to cover. </p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;I was recently asked to create a read-only web API to expose some parts of a system’s data model to third party developers. While &lt;a href
      
    
    </summary>
    
      <category term="Development" scheme="http://aspnetmonsters.com/categories/Development/"/>
    
    
      <category term="Dapper" scheme="http://aspnetmonsters.com/tags/Dapper/"/>
    
      <category term=".NET" scheme="http://aspnetmonsters.com/tags/NET/"/>
    
      <category term=".NET Core" scheme="http://aspnetmonsters.com/tags/NET-Core/"/>
    
      <category term="Micro ORM" scheme="http://aspnetmonsters.com/tags/Micro-ORM/"/>
    
  </entry>
  
  <entry>
    <title>Angular Testing Patterns - TestBed</title>
    <link href="http://aspnetmonsters.com/2017/12/2017-11-20-angular-testing/"/>
    <id>http://aspnetmonsters.com/2017/12/2017-11-20-angular-testing/</id>
    <published>2017-12-23T20:38:30.000Z</published>
    <updated>2019-04-27T15:03:14.918Z</updated>
    
    <content type="html"><![CDATA[<p>Spec files are automatically generated by Angular 5’s CLI but most projects leave them empty. Why not actually write some tests? This post covers some useful patterns to make the whole process as painless as possible.</p><a id="more"></a><p>I’ve recently been working on a team which has some downright amazing leadership on the testing side. As a result I’ve had to raise my testing game to a level I’ve not been at before. During the process the team developed some testing patters which might be useful to the general populace. Here they are:</p><ol><li>Keep the number of test bed tests to a minimum. </li><li>Leverage <code>Observable</code> as a testing seam</li><li>Leverage monkey patching as a testing seam</li><li>No matter what anybody says e2e tests still need sleeps</li></ol><p>I’m going to split this post into parts to keep the posts relatively short. </p><h1 id="Test-Bed"><a href="#Test-Bed" class="headerlink" title="Test Bed"></a>Test Bed</h1><p>Angular 2 introduced the idea of the <code>TestBed</code> which is basically a way of testing out a component with a “real” DOM behind it. There is support for injecting services either real or mock into your component as well as binding your component’s model to the template. TestBed tests are the default type of test generated by the angular-cli when you create a new component. They are great and can be used to test a component much more thoroughly than testing with isolated tests alone. </p><p>The issue with them is that they tend to be quite slow to run. The interaction with the DOM and the setup of an entire dependency injection instance per test adds several hundred milliseconds for every TestBed test run. Just watching the test counter tick up in my command-line test reporter I can easily see when TestBed tests are encountered as the counter slows right now. The added time may not be huge in isolation but if we add 500ms (pretty conservative in my experience) per test on a collection of 1500 tests (pretty small project) then we’re talking twelve and a half minutes. Angular testing is already glacial so adding this coupled with the Karma runner’s inability to selectively run tests and you’re really in trouble. </p><p>Testing should be lightening fast because you want the feedback loop to be as tight as possible. That’s why I’m such a big fan of <a href="https://blogs.msdn.microsoft.com/visualstudio/2017/03/09/live-unit-testing-in-visual-studio-2017-enterprise/" target="_blank" rel="noopener">Live Unit Testing</a>. My mantra is that you should be able to hold your breath during a test run without feeling uncomfortable (this makes former pearl divers well adapted to being Angular developers). Most of the functionality that we test on a component doesn’t need to be tested using a full featured TestBed. Any functions which mutate the state or call out to other services can be written without the need for the TestBed. Many of my components contain just two TestBed tests: one to check the component can be created and one to check it can be initted. These two test generally catch any typos in the template which is a big source of errors as the TypeScript compiler doesn’t catch things in there. In the init test you can also check that appropriate bindings are in place. It is faster to have a test which tests a bunch of properties at once than one test per property. </p><p>This being said there are still plenty of time when TestBed tests do come in useful, typically any time you’re building a complex user interface and want to validate that it works cross browsers. I’m certainly not saying don’t use TestBed at all but rather that its use should be limited and isolation tests should be favoured. </p><p>Let’s take a look at an example test which we can migrate away from the TestBed. </p><p>This component does some simple addition. Left side + right side = answer, unless the answer is less than 0 then ‘Value too small’:</p><figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; Component, OnInit &#125; <span class="keyword">from</span> <span class="string">'@angular/core'</span>;</span><br><span class="line"></span><br><span class="line">@Component(&#123;</span><br><span class="line">  selector: <span class="string">'app-math-component'</span>,</span><br><span class="line">  templateUrl: <span class="string">'./math-component.component.html'</span>,</span><br><span class="line">  styleUrls: [<span class="string">'./math-component.component.css'</span>]</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="class"><span class="keyword">class</span> <span class="title">MathComponent</span> <span class="title">implements</span> <span class="title">OnInit</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">  model: MathComponentModel = &#123;</span><br><span class="line">    left: <span class="number">0</span>,</span><br><span class="line">    right: <span class="number">0</span>,</span><br><span class="line">    answer: <span class="number">0</span></span><br><span class="line">  &#125;;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">constructor</span>() &#123; &#125;</span><br><span class="line"></span><br><span class="line">  ngOnInit() &#123;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  update() &#123;</span><br><span class="line">    <span class="keyword">this</span>.model.answer = <span class="keyword">this</span>.model.left + <span class="keyword">this</span>.model.right;</span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">this</span>.model.answer &lt; <span class="number">0</span>) &#123;</span><br><span class="line">      <span class="keyword">this</span>.model.answer = <span class="string">'Value too small'</span>;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="class"><span class="keyword">class</span> <span class="title">MathComponentModel</span> </span>&#123;</span><br><span class="line">  left: number;</span><br><span class="line">  right: number;</span><br><span class="line">  answer: number | string;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>The template for it is equally simple</p><figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">p</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">input</span> [(<span class="attr">ngModel</span>)]=<span class="string">"model.left"</span> (<span class="attr">change</span>)=<span class="string">"update()"</span> <span class="attr">type</span>=<span class="string">"number"</span>/&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">input</span> [(<span class="attr">ngModel</span>)]=<span class="string">"model.right"</span> (<span class="attr">change</span>)=<span class="string">"update()"</span> <span class="attr">type</span>=<span class="string">"number"</span>/&gt;</span>=</span><br><span class="line">  <span class="tag">&lt;<span class="name">input</span> [(<span class="attr">ngModel</span>)]=<span class="string">"model.answer"</span> <span class="attr">disabled</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br></pre></td></tr></table></figure><p>A fully testbed test for this might look like</p><figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line">describe(<span class="string">'MathComponent'</span>, () =&gt; &#123;</span><br><span class="line">  <span class="keyword">let</span> component: MathComponent;</span><br><span class="line">  <span class="keyword">let</span> fixture: ComponentFixture&lt;MathComponent&gt;;</span><br><span class="line"></span><br><span class="line">  beforeEach(<span class="keyword">async</span>(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">    TestBed.configureTestingModule(&#123;</span><br><span class="line">      declarations: [MathComponent],</span><br><span class="line">      imports: [FormsModule]</span><br><span class="line">    &#125;)</span><br><span class="line">      .compileComponents();</span><br><span class="line">  &#125;));</span><br><span class="line"></span><br><span class="line">  beforeEach(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">    fixture = TestBed.createComponent(MathComponent);</span><br><span class="line">    component = fixture.componentInstance;</span><br><span class="line">    fixture.detectChanges();</span><br><span class="line">  &#125;);</span><br><span class="line"></span><br><span class="line">  it(<span class="string">'should create'</span>, () =&gt; &#123;</span><br><span class="line">    expect(component).toBeTruthy();</span><br><span class="line">  &#125;);</span><br><span class="line"></span><br><span class="line">  it(<span class="string">'should add up two numbers'</span>, fakeAsync(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">const</span> compiled = fixture.debugElement.nativeElement;</span><br><span class="line">    compiled.querySelector(<span class="string">'[data-autom=left]'</span>).value = <span class="string">'2'</span>;</span><br><span class="line">    compiled.querySelector(<span class="string">'[data-autom=left]'</span>).dispatchEvent(<span class="keyword">new</span> Event(<span class="string">'input'</span>));</span><br><span class="line"></span><br><span class="line">    compiled.querySelector(<span class="string">'[data-autom=right]'</span>).value = <span class="string">'3'</span>;</span><br><span class="line">    compiled.querySelector(<span class="string">'[data-autom=right]'</span>).dispatchEvent(<span class="keyword">new</span> Event(<span class="string">'input'</span>));</span><br><span class="line"></span><br><span class="line">    component.update();</span><br><span class="line">    fixture.detectChanges();</span><br><span class="line">    tick();</span><br><span class="line">    expect(compiled.querySelector(<span class="string">'[data-autom=answer]'</span>).value).toBe(<span class="string">'5'</span>);</span><br><span class="line">  &#125;));</span><br><span class="line"></span><br><span class="line">  it(<span class="string">'should set answer to "Value too small" if answer &lt; 0'</span>, fakeAsync(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">const</span> compiled = fixture.debugElement.nativeElement;</span><br><span class="line">    compiled.querySelector(<span class="string">'[data-autom=left]'</span>).value = <span class="string">'2'</span>;</span><br><span class="line">    compiled.querySelector(<span class="string">'[data-autom=left]'</span>).dispatchEvent(<span class="keyword">new</span> Event(<span class="string">'input'</span>));</span><br><span class="line"></span><br><span class="line">    compiled.querySelector(<span class="string">'[data-autom=right]'</span>).value = <span class="string">'-3'</span>;</span><br><span class="line">    compiled.querySelector(<span class="string">'[data-autom=right]'</span>).dispatchEvent(<span class="keyword">new</span> Event(<span class="string">'input'</span>));</span><br><span class="line"></span><br><span class="line">    component.update();</span><br><span class="line">    fixture.detectChanges();</span><br><span class="line">    tick();</span><br><span class="line"></span><br><span class="line">    expect(compiled.querySelector(<span class="string">'[data-autom=answer]'</span>).value).toBe(<span class="string">'Value too small'</span>);</span><br><span class="line">  &#125;));</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>A couple of things to point out here: the first is that there is quite a bit of magic to interact with input boxes on the page. The second thing is that compiled component tests seem to be <a href="https://github.com/angular/angular/issues/12409" target="_blank" rel="noopener">quite slow</a>, doubly so if you haven’t made your modules highly granular. Much of the testing here could be handled by testing the model rather than the rendering. A testbed test is still needed to check the rendering once but after that we’re good with simpler tests.</p><figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line">describe(<span class="string">'MathComponent bindings'</span>, () =&gt; &#123;</span><br><span class="line">  <span class="keyword">let</span> component: MathComponent;</span><br><span class="line">  <span class="keyword">let</span> fixture: ComponentFixture&lt;MathComponent&gt;;</span><br><span class="line"></span><br><span class="line">  beforeEach(<span class="keyword">async</span>(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">    TestBed.configureTestingModule(&#123;</span><br><span class="line">      declarations: [MathComponent],</span><br><span class="line">      imports: [FormsModule]</span><br><span class="line">    &#125;)</span><br><span class="line">      .compileComponents();</span><br><span class="line">  &#125;));</span><br><span class="line"></span><br><span class="line">  beforeEach(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">    fixture = TestBed.createComponent(MathComponent);</span><br><span class="line">    component = fixture.componentInstance;</span><br><span class="line">    fixture.detectChanges();</span><br><span class="line">  &#125;);</span><br><span class="line"></span><br><span class="line">  it(<span class="string">'should init'</span>, () =&gt; &#123;</span><br><span class="line">    expect(component).toBeTruthy();</span><br><span class="line">  &#125;);</span><br><span class="line"></span><br><span class="line">  it(<span class="string">'should create'</span>, fakeAsync(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">    component.model.answer = <span class="number">5</span>;</span><br><span class="line">    component.model.answer = <span class="number">5</span>;</span><br><span class="line">    component.model.left = <span class="number">3</span>;</span><br><span class="line">    component.model.right = <span class="number">2</span>;</span><br><span class="line"></span><br><span class="line">    fixture.detectChanges();</span><br><span class="line">    tick();</span><br><span class="line">    <span class="keyword">const</span> compiled = fixture.debugElement.nativeElement;</span><br><span class="line">    expect(compiled.querySelector(<span class="string">'[data-autom=answer]'</span>).value).toBe(component.model.answer.toString());</span><br><span class="line">    expect(compiled.querySelector(<span class="string">'[data-autom=left]'</span>).value).toBe(component.model.left.toString());</span><br><span class="line">    expect(compiled.querySelector(<span class="string">'[data-autom=right]'</span>).value).toBe(component.model.right.toString());</span><br><span class="line">  &#125;));</span><br><span class="line">&#125;);</span><br><span class="line">describe(<span class="string">'MathComponent'</span>, () =&gt; &#123;</span><br><span class="line">  it(<span class="string">'should add up two numbers'</span>, () =&gt; &#123;</span><br><span class="line">    <span class="keyword">const</span> component = <span class="keyword">new</span> MathComponent();</span><br><span class="line">    component.model.left = <span class="number">1</span>;</span><br><span class="line">    component.model.right = <span class="number">2</span>;</span><br><span class="line">    component.update();</span><br><span class="line">    expect(component.model.answer).toBe(<span class="number">3</span>);</span><br><span class="line">  &#125;);</span><br><span class="line"></span><br><span class="line">  it(<span class="string">'should set answer to Value too small if answer &lt; 0'</span>, () =&gt; &#123;</span><br><span class="line">    <span class="keyword">const</span> component = <span class="keyword">new</span> MathComponent();</span><br><span class="line">    component.model.left = <span class="number">1</span>;</span><br><span class="line">    component.model.right = <span class="number">-2</span>;</span><br><span class="line">    component.update();</span><br><span class="line">    expect(component.model.answer).toBe(<span class="string">'Value too small'</span>);</span><br><span class="line">  &#125;);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>The advantage here is that the tests are simpler and run faster. We also don’t have to worry about fiddling with fake async or ticks.</p><p>In the next article we’ll visit how we can use Observables, which are pretty popular in angular, as a seam to help write tests. </p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;Spec files are automatically generated by Angular 5’s CLI but most projects leave them empty. Why not actually write some tests? This post covers some useful patterns to make the whole process as painless as possible.&lt;/p&gt;
    
    </summary>
    
      <category term="Development" scheme="http://aspnetmonsters.com/categories/Development/"/>
    
    
      <category term="Testing" scheme="http://aspnetmonsters.com/tags/Testing/"/>
    
      <category term="Angular" scheme="http://aspnetmonsters.com/tags/Angular/"/>
    
  </entry>
  
  <entry>
    <title>Authorize Resource Tag Helper for ASP.NET Core</title>
    <link href="http://aspnetmonsters.com/2017/11/2017-11-28-authorize-resource-tag-helper/"/>
    <id>http://aspnetmonsters.com/2017/11/2017-11-28-authorize-resource-tag-helper/</id>
    <published>2017-11-29T02:30:00.000Z</published>
    <updated>2019-04-27T15:03:14.918Z</updated>
    
    <content type="html"><![CDATA[<p>In my previous blog post, I wrote an <a href="https://www.davepaquette.com/archive/2017/11/05/authorize-tag-helper.aspx" target="_blank" rel="noopener">Authorize tag helper</a> that made it simple to use role and policy based authorization in Razor Views. In this blog post, we will take this one step further and build a tag helper for resource-based authorization.</p><h1 id="Resource-Based-Authorization"><a href="#Resource-Based-Authorization" class="headerlink" title="Resource-Based Authorization"></a>Resource-Based Authorization</h1><p>Using the <code>IAuthorizationService</code> in ASP.NET Core, it is easy to implement an authorization strategy that depends not only on properties of the User but also depends on the resource being accessed. To learn how resource-based authorization works, take a look at the well written <a href="https://docs.microsoft.com/en-us/aspnet/core/security/authorization/resourcebased?tabs=aspnetcore2x" target="_blank" rel="noopener">offical documentation</a>.</p><p>Once you have defined your authorization handlers and setup any policies in <code>Startup.ConfigureServices</code>, applying resource-based authorization is a matter of calling one of two overloads of the <code>AuthorizeAsync</code> method on the <code>IAuthorizationService</code>.</p><figure class="highlight csharp"><table><tr><td class="code"><pre><span class="line"><span class="function">Task&lt;AuthorizationResult&gt; <span class="title">AuthorizeAsync</span>(<span class="params">ClaimsPrincipal user,</span></span></span><br><span class="line"><span class="function"><span class="params">                          <span class="keyword">object</span> resource,</span></span></span><br><span class="line"><span class="function"><span class="params">                          <span class="keyword">string</span> policyName</span>)</span>;</span><br><span class="line"></span><br><span class="line"><span class="function">Task&lt;AuthorizationResult&gt; <span class="title">AuthorizeAsync</span>(<span class="params">ClaimsPrincipal user,</span></span></span><br><span class="line"><span class="function"><span class="params">                          <span class="keyword">object</span> resource,</span></span></span><br><span class="line"><span class="function"><span class="params">                          IAuthorizationRequirement requirements</span>)</span>;</span><br></pre></td></tr></table></figure>                          <p>One method takes in a policy name while the other takes in an <code>IAuthorizationRequirement</code>. The resulting <code>AuthorizationResult</code> has a <code>Succeeded</code> boolean that indicates whether or not the user meets the requirements for the specified policy. Using the <code>IAuthorizationService</code> in a controller is easy enough. Simply inject the service into the controller, call the method you want to call and then check the result.</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line"> </span><br><span class="line">public async Task&lt;IActionResult&gt; Edit(int id)</span><br><span class="line">&#123;</span><br><span class="line">    var document = _documentContext.Find(documentId);</span><br><span class="line"></span><br><span class="line">    var authorizationResult = await _authorizationService.AuthorizeAsync(User, Document, &quot;EditDocument&quot;);</span><br><span class="line"></span><br><span class="line">    if (authorizationResult.Succeeded)</span><br><span class="line">    &#123;</span><br><span class="line">        return View(document);</span><br><span class="line">    &#125;    </span><br><span class="line">    else</span><br><span class="line">    &#123;</span><br><span class="line">        return new ChallengeResult();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Using this approach, we can easily restrict which users can edit specific documents as defined by our EditDocument policy. For example, we might limit editing to only users who originally created the document. </p><p>Where things start to get a little ugly is if we want to render a UI element based on resource-based authorization. For example, we might only want to render the edit button for a document if the current user is actually authorized to edit that document. Out of the box, this would require us to inject the <code>IAuthorizationService</code> in the Razor view and use it like we did in the controller action. The approach works, but the Razor code will get ugly really fast.</p><h1 id="Authorize-Resource-Tag-Helper"><a href="#Authorize-Resource-Tag-Helper" class="headerlink" title="Authorize Resource Tag Helper"></a>Authorize Resource Tag Helper</h1><p>Similar to the Authorize Tag Helper from the last blog post, this Authorize Resource Tag Helper will make it easy to show or hide blocks of HTML by evaluating authorization rules.</p><h2 id="Resource-Based-Policy-Authorization"><a href="#Resource-Based-Policy-Authorization" class="headerlink" title="Resource-Based Policy Authorization"></a>Resource-Based Policy Authorization</h2><p>Let’s assume we have a named “EditDocument” that requires a user to be the original author of a <code>Document</code> in order to edit the document. With the authorize resource tag helper, specify the resource instance using the <code>asp-authorize-resource</code> attribute and the policy name using the <code>asp-policy</code> attribute. Here is an example where <code>Model</code> is an instance of a <code>Document</code></p><figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">a</span> <span class="attr">href</span>=<span class="string">"#"</span> <span class="attr">asp-authorize-resource</span>=<span class="string">"Model"</span> </span></span><br><span class="line"><span class="tag">    <span class="attr">asp-policy</span>=<span class="string">"EditDocument"</span> <span class="attr">class</span>=<span class="string">"glyphicon glyphicon-pencil"</span>&gt;</span><span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br></pre></td></tr></table></figure><p>If the user meets the requirments for the “EditDocument” policy and the specified resource, then the block of HTML will be sent to the browser. If the requirements are not met, the tag helper will suppress the output of that block of HTML. The tag helper can be applied to any HTML element.</p><h2 id="Resource-Based-Requirement-Authorization"><a href="#Resource-Based-Requirement-Authorization" class="headerlink" title="Resource-Based Requirement Authorization"></a>Resource-Based Requirement Authorization</h2><p>Instead of specifying a policy name, authorization can be evaluated by specifying an instance of an <code>IAuthorizationRequirement</code>. When using requirements directly instead of policies, specify the requirement using the <code>asp-requirement</code> attribute.</p><figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">a</span> <span class="attr">href</span>=<span class="string">"#"</span> <span class="attr">asp-authorize-resource</span>=<span class="string">"document"</span></span></span><br><span class="line"><span class="tag">            <span class="attr">asp-requirement</span>=<span class="string">"Operations.Delete"</span> </span></span><br><span class="line"><span class="tag">            <span class="attr">class</span>=<span class="string">"glyphicon glyphicon-trash text-danger"</span>&gt;</span>                            </span><br><span class="line"><span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br></pre></td></tr></table></figure><p>If the user meets <code>Operations.Delete</code> requirement for the specified resource, then the block of HTML will be sent to the browser. If the requirement is not met, the tag helper will suppress the output of that block of HTML. The tag helper can be applied to any HTML element.</p><h2 id="Implementation-Details"><a href="#Implementation-Details" class="headerlink" title="Implementation Details"></a>Implementation Details</h2><p>The authorize resource tag helper itself is fairly simple. The implementation will likely evolve after this blog post so you can check out the latest version <a href="https://github.com/dpaquette/TagHelperSamples/blob/master/TagHelperSamples/src/TagHelperSamples.Authorization/AuthorizeResourceTagHelper.cs" target="_blank" rel="noopener">here</a>.</p><p>The tag helper needs an instance of the <code>IHttpContextAccessor</code> to get access to the current user and an instance of the <code>IAuthorizationService</code>. These are injected into the constructor. In the <code>ProcessAsync</code> method, either the specified <code>Policy</code> or the specified <code>Requirement</code> are passed in to the <code>IAuthorizationService</code> along with the resource.</p><figure class="highlight csharp"><table><tr><td class="code"><pre><span class="line">[<span class="meta">HtmlTargetElement(Attributes = <span class="meta-string">"asp-authorize-resource,asp-policy"</span>)</span>]</span><br><span class="line">[<span class="meta">HtmlTargetElement(Attributes = <span class="meta-string">"asp-authorize-resource,asp-requirement"</span>)</span>]</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title">AuthorizeResourceTagHelper</span> : <span class="title">TagHelper</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">readonly</span> IAuthorizationService _authorizationService;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">readonly</span> IHttpContextAccessor _httpContextAccessor;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">AuthorizeResourceTagHelper</span>(<span class="params">IHttpContextAccessor httpContextAccessor, IAuthorizationService authorizationService</span>)</span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        _httpContextAccessor = httpContextAccessor;</span><br><span class="line">        _authorizationService = authorizationService;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment"><span class="doctag">///</span> <span class="doctag">&lt;summary&gt;</span></span></span><br><span class="line">    <span class="comment"><span class="doctag">///</span> Gets or sets the policy name that determines access to the HTML block.</span></span><br><span class="line">    <span class="comment"><span class="doctag">///</span> <span class="doctag">&lt;/summary&gt;</span></span></span><br><span class="line">    [<span class="meta">HtmlAttributeName(<span class="meta-string">"asp-policy"</span>)</span>]</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">string</span> Policy &#123; <span class="keyword">get</span>; <span class="keyword">set</span>; &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment"><span class="doctag">///</span> <span class="doctag">&lt;summary&gt;</span></span></span><br><span class="line">    <span class="comment"><span class="doctag">///</span> Gets or sets a comma delimited list of roles that are allowed to access the HTML  block.</span></span><br><span class="line">    <span class="comment"><span class="doctag">///</span> <span class="doctag">&lt;/summary&gt;</span></span></span><br><span class="line">    [<span class="meta">HtmlAttributeName(<span class="meta-string">"asp-requirement"</span>)</span>]</span><br><span class="line">    <span class="keyword">public</span> IAuthorizationRequirement Requirement &#123; <span class="keyword">get</span>; <span class="keyword">set</span>; &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment"><span class="doctag">///</span> <span class="doctag">&lt;summary&gt;</span></span></span><br><span class="line">    <span class="comment"><span class="doctag">///</span> Gets or sets the resource to be authorized against a particular policy</span></span><br><span class="line">    <span class="comment"><span class="doctag">///</span> <span class="doctag">&lt;/summary&gt;</span></span></span><br><span class="line">    [<span class="meta">HtmlAttributeName(<span class="meta-string">"asp-authorize-resource"</span>)</span>]</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">object</span> Resource &#123; <span class="keyword">get</span>; <span class="keyword">set</span>; &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">override</span> <span class="keyword">async</span> Task <span class="title">ProcessAsync</span>(<span class="params">TagHelperContext context, TagHelperOutput output</span>)</span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (Resource == <span class="literal">null</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> ArgumentException(<span class="string">"Resource cannot be null"</span>);                </span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (<span class="keyword">string</span>.IsNullOrWhiteSpace(Policy) &amp;&amp; Requirement == <span class="literal">null</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> ArgumentException(<span class="string">"Either Policy or Requirement must be specified"</span>);</span><br><span class="line">                </span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (!<span class="keyword">string</span>.IsNullOrWhiteSpace(Policy) &amp;&amp; Requirement != <span class="literal">null</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> ArgumentException(<span class="string">"Policy and Requirement cannot be specified at the same time"</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        AuthorizationResult authorizeResult;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (!<span class="keyword">string</span>.IsNullOrWhiteSpace(Policy))</span><br><span class="line">        &#123;</span><br><span class="line">            authorizeResult = <span class="keyword">await</span> _authorizationService.AuthorizeAsync(_httpContextAccessor.HttpContext.User, Resource, Policy);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span> <span class="keyword">if</span> (Requirement != <span class="literal">null</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            authorizeResult =</span><br><span class="line">                <span class="keyword">await</span> _authorizationService.AuthorizeAsync(_httpContextAccessor.HttpContext.User, Resource,</span><br><span class="line">                    Requirement);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span></span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> ArgumentException(<span class="string">"Either Policy or Requirement must be specified"</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (!authorizeResult.Succeeded)</span><br><span class="line">        &#123;</span><br><span class="line">            output.SuppressOutput();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure> <p>Note that either a policy or a requirement must be specified along with a resource, but you can’t specify both a policy AND a requirement. Most of the code in the <code>ProcessAsync</code> method is checking the argument values to make sure a valid combination was used.</p><h1 id="Try-it-out"><a href="#Try-it-out" class="headerlink" title="Try it out"></a>Try it out</h1><p>You can see the authorize resource tag helper in action on my tag helper samples site <a href="http://taghelpersamples.azurewebsites.net/Samples/Authorize" target="_blank" rel="noopener">here</a>. The sample site contains the examples listed in this blog post and also provides a way to log in as different users to test different scenarios.</p><p>The authorize resource tag helper is also available on <a href="https://www.nuget.org/packages/TagHelperSamples.Authorization/" target="_blank" rel="noopener">NuGet</a> so you can use it in your own ASP.NET Core application.</p><figure class="highlight ada"><table><tr><td class="code"><pre><span class="line">dotnet add <span class="keyword">package</span> <span class="title">TagHelperSamples.Authorization</span></span><br></pre></td></tr></table></figure><p>Let me know what you think. Would you like to see this tag helper including in the next release of ASP.NET Core?</p><p><em>NOTE:</em> If you choose to use the authorize resource tag helper in your application, you should remember that hiding a section of HTML is not enough to fully secure your application. You also need to make sure that resource-based authorization is applied to any related controllers and action methods.</p><h1 id="What’s-Next"><a href="#What’s-Next" class="headerlink" title="What’s Next?"></a>What’s Next?</h1><p>There is one more authorization scenario related to supporting different authorization schemes that I hope to cover. Watch out for that in a future blog post. Also, this tag helper project is all open source so feel free to jump in on <a href="https://github.com/dpaquette/TagHelperSamples" target="_blank" rel="noopener">GitHub</a>.</p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;In my previous blog post, I wrote an &lt;a href=&quot;https://www.davepaquette.com/archive/2017/11/05/authorize-tag-helper.aspx&quot; target=&quot;_blank&quot; 
      
    
    </summary>
    
      <category term="Development" scheme="http://aspnetmonsters.com/categories/Development/"/>
    
    
      <category term="ASP.NET Core" scheme="http://aspnetmonsters.com/tags/ASP-NET-Core/"/>
    
      <category term="Tag Helpers" scheme="http://aspnetmonsters.com/tags/Tag-Helpers/"/>
    
      <category term="MVC" scheme="http://aspnetmonsters.com/tags/MVC/"/>
    
      <category term="Authorization" scheme="http://aspnetmonsters.com/tags/Authorization/"/>
    
  </entry>
  
  <entry>
    <title>The Monsters Weekly - Episode  112 -  Migrating Knockout to React</title>
    <link href="http://aspnetmonsters.com/2017/11/monsters-weekly%5Cep%20112/"/>
    <id>http://aspnetmonsters.com/2017/11/monsters-weekly\ep 112/</id>
    <published>2017-11-21T08:15:00.000Z</published>
    <updated>2019-04-27T15:03:14.949Z</updated>
    
    <content type="html"><![CDATA[<p>The AllReady project has grown over the years and in order to keep it fresh, we’d like to try moving from Knockout to React for our client-side components. In this episode, Simon takes us through replacing a small Knockout component with an equivalent React component</p><p>&nbsp;</p><p><a class="twitter-follow-button" href="https://twitter.com/aspnetmonsters" target="_blank" rel="noopener">Follow @aspnetmonsters</a></p> <a id="more"></a><iframe src="https://channel9.msdn.com/Series/aspnetmonsters/ASPNET-Monsters--112-Migrating-Knockout-to-React/player" width="640" height="360" allowfullscreen frameborder="0"></iframe>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;The AllReady project has grown over the years and in order to keep it fresh, we’d like to try moving from Knockout to React for our client-side components. In this episode, Simon takes us through replacing a small Knockout component with an equivalent React component&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;a class=&quot;twitter-follow-button&quot; href=&quot;https://twitter.com/aspnetmonsters&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Follow @aspnetmonsters&lt;/a&gt;&lt;/p&gt;
    
    </summary>
    
      <category term="Monsters Weekly" scheme="http://aspnetmonsters.com/categories/Monsters-Weekly/"/>
    
    
      <category term="ASP.NET Core" scheme="http://aspnetmonsters.com/tags/ASP-NET-Core/"/>
    
  </entry>
  
  <entry>
    <title>The Monsters Weekly - Episode 111 -  Authorize Tag Helper</title>
    <link href="http://aspnetmonsters.com/2017/11/monsters-weekly%5Cep111/"/>
    <id>http://aspnetmonsters.com/2017/11/monsters-weekly\ep111/</id>
    <published>2017-11-14T12:20:38.000Z</published>
    <updated>2019-04-27T15:03:14.949Z</updated>
    
    <content type="html"><![CDATA[<p>In this episode, Monster Dave builds a new tag helper that makes it easy to control access to any block HTML in a Razor view. Join us for a tour of the Authorize tag helper</p><p><strong>Related Links:<br></strong>Tag Helper Samples Reop - <a href="https://github.com/dpaquette/TagHelperSamples" target="_blank">https://github.com/dpaquette/TagHelperSamples</a><strong><br></strong>GitHub Issue for MVC Core&nbsp; - <a href="https://github.com/aspnet/Mvc/issues/3785" target="_blank">https://github.com/aspnet/Mvc/issues/3785</a><strong><br></strong>Blog Post Deep Dive -<a href="https://www.davepaquette.com/archive/2017/11/05/authorize-tag-helper.aspx" target="_blank"> https://www.davepaquette.com/archive/2017/11/05/authorize-tag-helper.aspx</a></p><p>&nbsp;</p><p><a class="twitter-follow-button" href="https://twitter.com/aspnetmonsters" target="_blank" rel="noopener">Follow @aspnetmonsters</a></p> <a id="more"></a><iframe src="https://channel9.msdn.com/Series/aspnetmonsters/ASPNET-Monsters-111-Authorize-Tag-Helper/player" width="640" height="360" allowfullscreen frameborder="0"></iframe>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;In this episode, Monster Dave builds a new tag helper that makes it easy to control access to any block HTML in a Razor view. Join us for a tour of the Authorize tag helper&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Related Links:&lt;br&gt;&lt;/strong&gt;Tag Helper Samples Reop - &lt;a href=&quot;https://github.com/dpaquette/TagHelperSamples&quot; target=&quot;_blank&quot;&gt;https://github.com/dpaquette/TagHelperSamples&lt;/a&gt;&lt;strong&gt;&lt;br&gt;&lt;/strong&gt;GitHub Issue for MVC Core&amp;nbsp; - &lt;a href=&quot;https://github.com/aspnet/Mvc/issues/3785&quot; target=&quot;_blank&quot;&gt;https://github.com/aspnet/Mvc/issues/3785&lt;/a&gt;&lt;strong&gt;&lt;br&gt;&lt;/strong&gt;Blog Post Deep Dive -&lt;a href=&quot;https://www.davepaquette.com/archive/2017/11/05/authorize-tag-helper.aspx&quot; target=&quot;_blank&quot;&gt; https://www.davepaquette.com/archive/2017/11/05/authorize-tag-helper.aspx&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;a class=&quot;twitter-follow-button&quot; href=&quot;https://twitter.com/aspnetmonsters&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Follow @aspnetmonsters&lt;/a&gt;&lt;/p&gt;
    
    </summary>
    
      <category term="Monsters Weekly" scheme="http://aspnetmonsters.com/categories/Monsters-Weekly/"/>
    
    
      <category term="ASP.NET Core" scheme="http://aspnetmonsters.com/tags/ASP-NET-Core/"/>
    
  </entry>
  
  <entry>
    <title>The Monsters Weekly - Episode 110 -  Live Unit Testing</title>
    <link href="http://aspnetmonsters.com/2017/11/monsters-weekly%5Cep110/"/>
    <id>http://aspnetmonsters.com/2017/11/monsters-weekly\ep110/</id>
    <published>2017-11-06T09:29:52.000Z</published>
    <updated>2019-04-27T15:03:14.949Z</updated>
    
    <content type="html"><![CDATA[<p>The new live unit testing capabilities of Visual Studio 2017 are a real timesaver. In this video, we take a poke around at them.</p> <a id="more"></a><iframe src="https://channel9.msdn.com/Series/aspnetmonsters/ASPNET-Monsters-110-Live-Unit-Testing/player" width="640" height="360" allowfullscreen frameborder="0"></iframe>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;The new live unit testing capabilities of Visual Studio 2017 are a real timesaver. In this video, we take a poke around at them.&lt;/p&gt;
    
    </summary>
    
      <category term="Monsters Weekly" scheme="http://aspnetmonsters.com/categories/Monsters-Weekly/"/>
    
    
      <category term="ASP.NET Core" scheme="http://aspnetmonsters.com/tags/ASP-NET-Core/"/>
    
  </entry>
  
  <entry>
    <title>Authorize Tag Helper for ASP.NET Core</title>
    <link href="http://aspnetmonsters.com/2017/11/2017-11-05-authorize-tag-helper/"/>
    <id>http://aspnetmonsters.com/2017/11/2017-11-05-authorize-tag-helper/</id>
    <published>2017-11-05T20:38:30.000Z</published>
    <updated>2019-04-27T15:03:14.918Z</updated>
    
    <content type="html"><![CDATA[<p>In ASP.NET Core, it’s easy to control access to Controllers and Action Methods using the <code>[Authorize]</code> attribute. This attribute provides a simple way to ensure only authorized users are able to access certain parts of your application. While the <code>[Authorize]</code> attribute makes it easy to control authorization for an entire page, the mechanism for controlling access to a section of a page is <a href="https://docs.microsoft.com/en-us/aspnet/core/security/authorization/views?tabs=aspnetcore2x" target="_blank" rel="noopener">a little clumsy</a>, involving the use of a the <code>IAuthorizationService</code> and writing C# based <code>if</code> blocks in your Razor code.</p><p>In this blog post, we build an Authorize tag helper that makes it easy to control access to any block HTML in a Razor view.</p><h1 id="Authorize-Tag-Helper"><a href="#Authorize-Tag-Helper" class="headerlink" title="Authorize Tag Helper"></a>Authorize Tag Helper</h1><p>The basic idea of this tag helper is to provide similar functionality to the <code>[Authorize]</code> attribute and it’s associated action filter in ASP.NET Core MVC. The authorize tag helper will provide the same options as the <code>[Authorize]</code> attribute and the implementation will be based on the authorize filter. In the MVC framework, the <code>[Authorize]</code> attribute provides data such as the names of roles and policies while the authorize filter contains the logic to check for roles and policies as part of the request pipeline. Let’s walk through the most common scenarios.</p><h2 id="Simple-Authorization"><a href="#Simple-Authorization" class="headerlink" title="Simple Authorization"></a>Simple Authorization</h2><p>In it’s <a href="https://docs.microsoft.com/en-us/aspnet/core/security/authorization/simple" target="_blank" rel="noopener">simplest form</a>, adding the <code>[Authorize]</code> attribute to a controller or action method will limit access to that controller or action method to users who are authenticated. That is, only users who are logged in will be able to access those controllers or action methods.</p><p>With the Authorize tag helper, we will implement a similar behaviour. Adding the <code>asp-authorize</code> attribute to any HTML element will ensure that only authenticated users can see that that block of HTML. </p><figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">asp-authorize</span> <span class="attr">class</span>=<span class="string">"panel panel-default"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"panel-heading"</span>&gt;</span>Welcome !!<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"panel-body"</span>&gt;</span></span><br><span class="line">        If you're logged in, you can see this section</span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure><p>If a user is not authenticated, the tag helper will suppress the output of that entire block of HTML. That section of HTML will not be sent to the browser.</p><h2 id="Role-Based-Authorization"><a href="#Role-Based-Authorization" class="headerlink" title="Role Based Authorization"></a>Role Based Authorization</h2><p>The <code>[Authorize]</code> attribute provides an option to specify the role that a user must belong to in order to access a controller or action method. For example, if a user must belong to the <em>Admin</em> role, we would add the <code>[Authorize]</code> attribute and specify the <code>Roles</code> property as follows:</p><figure class="highlight csharp"><table><tr><td class="code"><pre><span class="line">[<span class="meta">Authorize(Roles = <span class="meta-string">"Admin"</span>)</span>]</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title">AdminController</span> : <span class="title">Controller</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="comment">//Action methods here</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>The equivalent using the Authorize tag helper would be to add the <code>asp-authorize</code> attribute to an HTML element and then also add the <code>asp-roles</code> attribute specifying the require role.</p><figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">asp-authorize</span> <span class="attr">asp-roles</span>=<span class="string">"Admin"</span> <span class="attr">class</span>=<span class="string">"panel panel-default"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"panel-heading"</span>&gt;</span>Admin Section<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"panel-body"</span>&gt;</span></span><br><span class="line">        Only admin users can see this section. Top secret admin things go here.</span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure><p>You can also specify a comma separated list of roles, in which case the HTML would be rendered if the user was a member of any of the roles specified.</p><h2 id="Policy-Based-Authorization"><a href="#Policy-Based-Authorization" class="headerlink" title="Policy Based Authorization"></a>Policy Based Authorization</h2><p>The <code>[Authorize]</code> attribe also provides an option to authorize users based on the requirements specified in a Policy. You can learn more about the specifics of this approach by reading the offical docs on <a href="https://docs.microsoft.com/en-us/aspnet/core/security/authorization/claims" target="_blank" rel="noopener">Claims-Based Authorization</a> and <a href="https://docs.microsoft.com/en-us/aspnet/core/security/authorization/policies" target="_blank" rel="noopener">Custom-Policy Based Authorization</a>. Policy based authorization is applied by specifying <code>Policy</code> property for the <code>[Authorize]</code> attribute as follows:</p><figure class="highlight csharp"><table><tr><td class="code"><pre><span class="line">[<span class="meta">Authorize(Policy = <span class="meta-string">"Seniors"</span>)</span>]</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title">AdminController</span> : <span class="title">Controller</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="comment">//action methods here</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>This assumes a policy named <em>Seniors</em> was defined at startup. For example:</p><figure class="highlight csharp"><table><tr><td class="code"><pre><span class="line">services.AddAuthorization(o =&gt;</span><br><span class="line">    &#123;</span><br><span class="line">        o.AddPolicy(<span class="string">"Seniors"</span>, p =&gt;</span><br><span class="line">        &#123;</span><br><span class="line">            p.RequireAssertion(context =&gt;</span><br><span class="line">            &#123;</span><br><span class="line">                <span class="keyword">return</span> context.User.Claims</span><br><span class="line">                      .Any(c =&gt; c.Type == <span class="string">"Age"</span> &amp;&amp; Int32.Parse(c.Value) &gt;= <span class="number">65</span>);</span><br><span class="line">            &#125;);</span><br><span class="line">        &#125;);</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">);</span><br></pre></td></tr></table></figure><p>The equivalent using the Authorize tag helper would be to add the <code>asp-authorize</code> attribute to an HTML element and then also add the <code>asp-policy</code> attribute specifying the policy name.</p><figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">asp-authorize</span> <span class="attr">asp-policy</span>=<span class="string">"Seniors"</span> <span class="attr">class</span>=<span class="string">"panel panel-default"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"panel-heading"</span>&gt;</span>Seniors Only<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"panel-body"</span>&gt;</span></span><br><span class="line">        Only users age 65 or older can see this section. Early bird dinner coupons go here. </span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure><h2 id="Combining-Role-and-Policy-Based-Authorization"><a href="#Combining-Role-and-Policy-Based-Authorization" class="headerlink" title="Combining Role and Policy Based Authorization"></a>Combining Role and Policy Based Authorization</h2><p>You can combine the role based and policy based approaches by specifying both the <code>asp-roles</code> and <code>asp-policy</code> attributes. This has the effect of requiring that the user meets the requiremnts for both the role and the policy. For example, the following would require that the usere were both a member of the Admin role and meets the requirements defined in the Seniors policy.</p><figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">asp-authorize</span> <span class="attr">asp-roles</span>=<span class="string">"Admin"</span> <span class="attr">asp-policy</span>=<span class="string">"Seniors"</span> <span class="attr">class</span>=<span class="string">"panel panel-default"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"panel-heading"</span>&gt;</span>Admin Seniors Only<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"panel-body"</span>&gt;</span></span><br><span class="line">        Only users who have both the Admin role AND are age 65 or older can see this section.</span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure><h2 id="Implementation-Details"><a href="#Implementation-Details" class="headerlink" title="Implementation Details"></a>Implementation Details</h2><p>The Authorize tag helper itself is fairly simple. The implementation will likely evolve after this blog post so you can check out the latest version <a href="https://github.com/dpaquette/TagHelperSamples/blob/master/TagHelperSamples/src/TagHelperSamples.Authorization/AuthorizeTagHelper.cs" target="_blank" rel="noopener">here</a>.</p><p>The tag helper implements the <code>IAuthorizeData</code> interface. This is the interface implemented by the <a href="https://github.com/aspnet/Security/blob/dev/src/Microsoft.AspNetCore.Authorization/AuthorizeAttribute.cs" target="_blank" rel="noopener">Authorize</a> attribute in ASP.NET Core. In the <code>ProcessAsync</code> method, the properties of <code>IAuthorizeData</code> are used to create an effective policy that is then evaluated against the current <code>HttpContext</code>. If the policy does not succeed, then the output of the tag helper is supressed. Remember that supressing the output of a tag helper means that the HTML for that element, including it’s children, will be NOT sent to the client.</p><figure class="highlight csharp"><table><tr><td class="code"><pre><span class="line">[<span class="meta">HtmlTargetElement(Attributes = <span class="meta-string">"asp-authorize"</span>)</span>]</span><br><span class="line">[<span class="meta">HtmlTargetElement(Attributes = <span class="meta-string">"asp-authorize,asp-policy"</span>)</span>]</span><br><span class="line">[<span class="meta">HtmlTargetElement(Attributes = <span class="meta-string">"asp-authorize,asp-roles"</span>)</span>]</span><br><span class="line">[<span class="meta">HtmlTargetElement(Attributes = <span class="meta-string">"asp-authorize,asp-authentication-schemes"</span>)</span>]</span><br><span class="line">public class AuthorizationPolicyTagHelper : TagHelper, IAuthorizeData</span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">readonly</span> IAuthorizationPolicyProvider _policyProvider;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">readonly</span> IPolicyEvaluator _policyEvaluator;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">readonly</span> IHttpContextAccessor _httpContextAccessor;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">AuthorizationPolicyTagHelper</span>(<span class="params">IHttpContextAccessor httpContextAccessor, IAuthorizationPolicyProvider policyProvider, IPolicyEvaluator policyEvaluator</span>)</span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        _httpContextAccessor = httpContextAccessor;</span><br><span class="line">        _policyProvider = policyProvider;</span><br><span class="line">        _policyEvaluator = policyEvaluator;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment"><span class="doctag">///</span> <span class="doctag">&lt;summary&gt;</span></span></span><br><span class="line">    <span class="comment"><span class="doctag">///</span> Gets or sets the policy name that determines access to the HTML block.</span></span><br><span class="line">    <span class="comment"><span class="doctag">///</span> <span class="doctag">&lt;/summary&gt;</span></span></span><br><span class="line">    [<span class="meta">HtmlAttributeName(<span class="meta-string">"asp-policy"</span>)</span>]</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">string</span> Policy &#123; <span class="keyword">get</span>; <span class="keyword">set</span>; &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment"><span class="doctag">///</span> <span class="doctag">&lt;summary&gt;</span></span></span><br><span class="line">    <span class="comment"><span class="doctag">///</span> Gets or sets a comma delimited list of roles that are allowed to access the HTML  block.</span></span><br><span class="line">    <span class="comment"><span class="doctag">///</span> <span class="doctag">&lt;/summary&gt;</span></span></span><br><span class="line">    [<span class="meta">HtmlAttributeName(<span class="meta-string">"asp-roles"</span>)</span>]</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">string</span> Roles &#123; <span class="keyword">get</span>; <span class="keyword">set</span>; &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment"><span class="doctag">///</span> <span class="doctag">&lt;summary&gt;</span></span></span><br><span class="line">    <span class="comment"><span class="doctag">///</span> Gets or sets a comma delimited list of schemes from which user information is constructed.</span></span><br><span class="line">    <span class="comment"><span class="doctag">///</span> <span class="doctag">&lt;/summary&gt;</span></span></span><br><span class="line">    [<span class="meta">HtmlAttributeName(<span class="meta-string">"asp-authentication-schemes"</span>)</span>]</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">string</span> AuthenticationSchemes &#123; <span class="keyword">get</span>; <span class="keyword">set</span>; &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">override</span> <span class="keyword">async</span> Task <span class="title">ProcessAsync</span>(<span class="params">TagHelperContext context, TagHelperOutput output</span>)</span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">var</span> policy = <span class="keyword">await</span> AuthorizationPolicy.CombineAsync(_policyProvider, <span class="keyword">new</span>[] &#123; <span class="keyword">this</span> &#125;);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">var</span> authenticateResult = <span class="keyword">await</span> _policyEvaluator.AuthenticateAsync(policy, _httpContextAccessor.HttpContext);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">var</span> authorizeResult = <span class="keyword">await</span> _policyEvaluator.AuthorizeAsync(policy, authenticateResult, _httpContextAccessor.HttpContext, <span class="literal">null</span>);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (!authorizeResult.Succeeded)</span><br><span class="line">        &#123;</span><br><span class="line">            output.SuppressOutput();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure> <p>The code in the <code>ProcessAsync</code> method is based on the <a href="https://github.com/aspnet/Mvc/blob/dev/src/Microsoft.AspNetCore.Mvc.Core/Authorization/AuthorizeFilter.cs" target="_blank" rel="noopener">AuthorizeFilter</a> from ASP.NET Core MVC.</p><h1 id="Try-it-out"><a href="#Try-it-out" class="headerlink" title="Try it out"></a>Try it out</h1><p>You can see the Authorize tag helper in action on my tag helper samples site <a href="http://taghelpersamples.azurewebsites.net/Samples/Authorize" target="_blank" rel="noopener">here</a>. The sample site contains the examples listed in this blog post and also provides a way to log in as different users to test different scenarios.</p><p>The Authorize tag helper is also available on <a href="https://www.nuget.org/packages/TagHelperSamples.Authorization/" target="_blank" rel="noopener">NuGet</a> so you can use it in your own ASP.NET Core application.</p><figure class="highlight ada"><table><tr><td class="code"><pre><span class="line">dotnet add <span class="keyword">package</span> <span class="title">TagHelperSamples.Authorization</span></span><br></pre></td></tr></table></figure><p>Let me know what you think. Would you like to see this tag helper included in the next release of ASP.NET Core?</p><h1 id="What’s-Next"><a href="#What’s-Next" class="headerlink" title="What’s Next?"></a>What’s Next?</h1><p>If you choose to use the Authorize tag helper in your application, you should remember that hiding a section of HTML is not enough to fully secure your application. You also need to make sure that authorization is applied to any related controllers and action methods. The Authorize tag helper is meant to be used in conjugtion with the <code>[Authorize]</code> attribute, not as a replacement for it.</p><p>There are a couple more scenarios I would like to go through and I will address those in a future post. One of those is supporting different Authorization Schemes and the other resource based authorization. Of course, this project is all open source so feel free to jump in on <a href="https://github.com/dpaquette/TagHelperSamples" target="_blank" rel="noopener">GitHub</a>.</p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;In ASP.NET Core, it’s easy to control access to Controllers and Action Methods using the &lt;code&gt;[Authorize]&lt;/code&gt; attribute. This attribu
      
    
    </summary>
    
      <category term="Development" scheme="http://aspnetmonsters.com/categories/Development/"/>
    
    
      <category term="ASP.NET Core" scheme="http://aspnetmonsters.com/tags/ASP-NET-Core/"/>
    
      <category term="Tag Helpers" scheme="http://aspnetmonsters.com/tags/Tag-Helpers/"/>
    
      <category term="MVC" scheme="http://aspnetmonsters.com/tags/MVC/"/>
    
      <category term="Authorization" scheme="http://aspnetmonsters.com/tags/Authorization/"/>
    
  </entry>
  
  <entry>
    <title>The Monsters Weekly - Episode 109 -  DbContext Pooling in Entity Framework Core 2.0</title>
    <link href="http://aspnetmonsters.com/2017/10/monsters-weekly%5Cep109/"/>
    <id>http://aspnetmonsters.com/2017/10/monsters-weekly\ep109/</id>
    <published>2017-10-24T06:00:00.000Z</published>
    <updated>2019-04-27T15:03:14.949Z</updated>
    
    <content type="html"><![CDATA[<p><a href="https://blogs.msdn.microsoft.com/dotnet/2017/08/14/announcing-entity-framework-core-2-0/" target="_blank">Entity Framework Core 2</a>&nbsp;was released recently. In today’s episode we explore a new feature called DbContext Pooling. See how enabling DbContext Pooling might magically make your ASP.NET Core application faster!</p><p><strong>Related Links:<br></strong>GitHub Repo - <a href="https://github.com/AspNetMonsters/EP109-EFDbContextPooling" target="_blank" rel="noopener">https://github.com/AspNetMonsters/EP109-EFDbContextPooling</a><strong><br></strong>Netling Load Testing Tool - <a href="https://github.com/hallatore/Netling" target="_blank">https://github.com/hallatore/Netling</a><strong><br></strong>.NET Conf Video - What’s new in EF Core 2.0 - <a href="https://channel9.msdn.com/Events/dotnetConf/2017/T221" target="_blank">https://channel9.msdn.com/Events/dotnetConf/2017/T221</a></p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; (Section on DbContext Pooling starts at 10:55s)<strong><br></strong></p><p>&nbsp;</p><p><a class="twitter-follow-button" href="https://twitter.com/aspnetmonsters" target="_blank" rel="noopener">Follow @aspnetmonsters</a></p> <a id="more"></a><iframe src="https://channel9.msdn.com/Series/aspnetmonsters/ASPNET-Monsters-109-DbContext-Pooling-in-Entity-Framework-Core-20/player" width="640" height="360" allowfullscreen frameborder="0"></iframe>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;&lt;a href=&quot;https://blogs.msdn.microsoft.com/dotnet/2017/08/14/announcing-entity-framework-core-2-0/&quot; target=&quot;_blank&quot;&gt;Entity Framework Core 2&lt;/a&gt;&amp;nbsp;was released recently. In today’s episode we explore a new feature called DbContext Pooling. See how enabling DbContext Pooling might magically make your ASP.NET Core application faster!&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Related Links:&lt;br&gt;&lt;/strong&gt;GitHub Repo - &lt;a href=&quot;https://github.com/AspNetMonsters/EP109-EFDbContextPooling&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/AspNetMonsters/EP109-EFDbContextPooling&lt;/a&gt;&lt;strong&gt;&lt;br&gt;&lt;/strong&gt;Netling Load Testing Tool - &lt;a href=&quot;https://github.com/hallatore/Netling&quot; target=&quot;_blank&quot;&gt;https://github.com/hallatore/Netling&lt;/a&gt;&lt;strong&gt;&lt;br&gt;&lt;/strong&gt;.NET Conf Video - What’s new in EF Core 2.0 - &lt;a href=&quot;https://channel9.msdn.com/Events/dotnetConf/2017/T221&quot; target=&quot;_blank&quot;&gt;https://channel9.msdn.com/Events/dotnetConf/2017/T221&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; (Section on DbContext Pooling starts at 10:55s)&lt;strong&gt;&lt;br&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;a class=&quot;twitter-follow-button&quot; href=&quot;https://twitter.com/aspnetmonsters&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Follow @aspnetmonsters&lt;/a&gt;&lt;/p&gt;
    
    </summary>
    
      <category term="Monsters Weekly" scheme="http://aspnetmonsters.com/categories/Monsters-Weekly/"/>
    
    
      <category term="ASP.NET Core" scheme="http://aspnetmonsters.com/tags/ASP-NET-Core/"/>
    
  </entry>
  
</feed>
