<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:series="http://organizeseries.com/"
	>

<channel>
	<title>Gunnar Peipman &#8211;  Programming Blog</title>
	<atom:link href="https://gunnarpeipman.com/feed/" rel="self" type="application/rss+xml" />
	<link>https://gunnarpeipman.com/</link>
	<description>ASP.NET Core, Blazor, .NET, Azure, SharePoint, IoT</description>
	<lastBuildDate>Fri, 11 Nov 2022 07:30:10 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://gunnarpeipman.com/wp-content/uploads/2018/05/cropped-gunnar-sinine-sinergija-512bw-32x32.jpg</url>
	<title>Gunnar Peipman &#8211;  Programming Blog</title>
	<link>https://gunnarpeipman.com/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>SQL Server database backup to Azure Blob Storage</title>
		<link>https://gunnarpeipman.com/mssql-backup-to-azure-blob-storage/</link>
					<comments>https://gunnarpeipman.com/mssql-backup-to-azure-blob-storage/#comments</comments>
		
		<dc:creator><![CDATA[Gunnar Peipman]]></dc:creator>
		<pubDate>Fri, 11 Nov 2022 05:30:00 +0000</pubDate>
				<category><![CDATA[Azure]]></category>
		<category><![CDATA[Data platform]]></category>
		<guid isPermaLink="false">https://gunnarpeipman.com/?p=6473</guid>

					<description><![CDATA[<p>SQL Server supports exporting data-tier applications (BACPAC). It means that database is packaged to one file with schema and data. It’s not same as SQL Server backups but to backup smaller databases it works pretty well. Those who don’t want to mess with local backup storage can use cloud services like Azure Blob Storage to keep database backups. Here’s the example how I automated backup of one not so big database using free tools SqlPackage and AzCopy.</p>
<p>The post <a href="https://gunnarpeipman.com/mssql-backup-to-azure-blob-storage/">SQL Server database backup to Azure Blob Storage</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>SQL Server supports exporting data-tier applications (BACPAC). It means that database is packaged to one file with schema and data. It’s not same as SQL Server backups but to backup smaller databases it works pretty well. Those who don’t want to mess with local backup storage can use cloud services like Azure Blob Storage to keep database backups. Here’s the example how I automated backup of one not so big database using free tools SqlPackage and AzCopy.</p>
<p><span id="more-6473"></span></p>
<h2>Tools</h2>
<p>To make data-tier application or BACPAC style backup of database and upload it to Azure Blob Storage we need two utilities:</p>
<ul>
<li><a title="Download and install SqlPackage" href="https://learn.microsoft.com/en-us/sql/tools/sqlpackage/sqlpackage-download?view=sql-server-ver16" target="_blank" rel="noopener">SqlPackage</a> – create BACPAC file of given database.</li>
<li><a title="Get started with AzCopy" href="https://learn.microsoft.com/en-us/azure/storage/common/storage-use-azcopy-v10" target="_blank" rel="noopener">AzCopy</a> – command-line utility to manage Azure Blob Storage</li>
</ul>
<blockquote>
<p>To keep things simple and minimalistic I downloaded both utilities as zip-files so I can keep all stuff in one folder. To update utilities I don’t have to uninstall them first – I just download newer zip-files and write files over.</p>
</blockquote>
<p>Here’s how I organized files on disk.</p>
<p align="center"><img fetchpriority="high" decoding="async" width="802" height="263" title="Backup folder on SQL Server system disk" style="margin: 0px 0px 18px; border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="Backup folder on SQL Server system disk" src="https://static.gunnarpeipman.com/wp-content/uploads/2022/11/mssql-backup-sqlpackage-azcopy.png" border="0"></p>
<p>As SqlPackage comes with number of files I put it in separate directory so I don’t have any mess in my backup scripts directory.</p>
<h2>Backup script</h2>
<p>We will use simple DOS batch file to get work done. This is what our backup script will do:</p>
<ol>
<li>Define variables for:</li>
<ol>
<li>Azure Blob Storage container URL</li>
<li>Storage container Shared Access Signature (SAS) token. If you don’t know how to generate SAS token then here’s the official guide by Microsoft: <a title="Manage blob containers using the Azure portal" href="https://learn.microsoft.com/en-us/azure/storage/blobs/blob-containers-portal" target="_blank" rel="noopener">Manage blob containers using the Azure portal</a> (a little bit before middle part of page).</li>
<li>Date based name for backup.</li>
<li>Database connection string.</li>
</ol>
<li>Bump database to local BACPAC file.</li>
<li>Upload file to Azure Blob Storage container.</li>
<li>Delete local BACPAC file.</li>
</ol>
<p>Here’s the script with explaining comments. The only tricky part is getting the date right.</p>
<pre style="background: white; color: black; font-family: consolas; font-size: 15px;"><span style="color: green;">REM Define variables for connection string, storage URL and SAS token</span><br><span style="color: blue;">set</span>&nbsp;<span style="color: rgb(163, 21, 21);">"CONNSTR=Server=tcp:localhost,1433;Database=db;User ID=X;Password=X;Trusted_Connection=False;Encrypt=False"</span><br><span style="color: blue;">set</span> STORAGE=https://my.blob.core.windows.net/container<br><span style="color: blue;">set</span>&nbsp;<span style="color: rgb(163, 21, 21);">"SAS=YOUR_SAS_TOKEN_HERE"</span><br> <br><span style="color: green;">REM Create date based file name</span><br><span style="color: green;">REM ~6,4 means from sixth character take next four</span><br><span style="color: green;">REM Correct date parts depend on date format in your system</span><br><span style="color: blue;">set</span> CUR_YYYY=%date:~6,4%<br><span style="color: blue;">set</span> CUR_MM=%date:~3,2%<br><span style="color: blue;">set</span> CUR_DD=%date:~0,2%<br><span style="color: blue;">set</span> FILENAME=%CUR_YYYY%%CUR_MM%%CUR_DD%.bacpac<br> <br><span style="color: green;">REM Bump database to BACPAC file</span><br>SqlPackage\sqlpackage.exe /TargetFile:%FILENAME% /Action:Export /SourceConnectionString:%CONNSTR%<br> <br><span style="color: green;">REM Copy BACPAC to Azure Blob Storage</span><br>Azcopy <span style="color: blue;">copy</span> %FILENAME% <span style="color: rgb(163, 21, 21);">"%STORAGE%?%SAS%"</span><br> <br><span style="color: green;">REM Delete local BACPAC file</span><br><span style="color: blue;">del</span> %FILENAME% /Q</pre>
<p>You can take this script with copy and paste, replace values and make it run before heading to next step.</p>
<h2>Backup task on Task Scheduler</h2>
<p>We can leave this our script on disk and run it manually but usually we want to run it automatically. One of the most classic options is Windows Task Scheduler. If you know what is SQL Server and what is Windows Task Scheduler you probably don’t need tutorial for scheduled tasks.</p>
<p>There’s one important thing. Make sure you set directory for script. It’s Start in field on the following dialog.</p>
<p align="center"><img decoding="async" width="452" height="498" title="Setting running directory for MSSQL backup script" style="margin: 0px 0px 18px; border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="Setting running directory for MSSQL backup script" src="https://static.gunnarpeipman.com/wp-content/uploads/2022/11/mssql-backup-scheduled-task.png" border="0"></p>
<p>Now it’s time to run the script as scheduled task and make sure it runs to the glory end without any errors.</p>
<h2>Wrapping up</h2>
<p>We automed MSSQL backups using SqlPackage and AzCopy. Our backups are running on Windows Task Scheduler as nightly batch. I know that using DOS batch is kind of retro approach and we also have Powershell but this time I decided to go with minimalistic set of tools. In the end we have working solution for cases when exporting data-tier application and uploading it to cloud is enough for us.</p>
<p>The post <a href="https://gunnarpeipman.com/mssql-backup-to-azure-blob-storage/">SQL Server database backup to Azure Blob Storage</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gunnarpeipman.com/mssql-backup-to-azure-blob-storage/feed/</wfw:commentRss>
			<slash:comments>1556</slash:comments>
		
		
			</item>
		<item>
		<title>Global usings in C# 10</title>
		<link>https://gunnarpeipman.com/global-usings/</link>
					<comments>https://gunnarpeipman.com/global-usings/#comments</comments>
		
		<dc:creator><![CDATA[Gunnar Peipman]]></dc:creator>
		<pubDate>Mon, 28 Feb 2022 06:30:00 +0000</pubDate>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[C#]]></category>
		<guid isPermaLink="false">https://gunnarpeipman.com/?p=6456</guid>

					<description><![CDATA[<p>One of the new features in .NET 6 is support for global using declarations. We can define using declarations as global and they work all over the project so we don’t have to define them in other files anymore. Here’s how it works.</p>
<p>The post <a href="https://gunnarpeipman.com/global-usings/">Global usings in C# 10</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>One of the new features in .NET 6 and C¤ 10 is support for global usings. We can define using declarations as global and they work all over the project so we don’t have to define them in other files anymore. Here’s how it works.</p>
<p><span id="more-6456"></span></p>
<h3>Sample project</h3>
<p><a href="https://static.gunnarpeipman.com/wp-content/uploads/2022/02/global-usings-solution.png"><img decoding="async" width="262" height="357" title="global-usings-solution" align="right" style="margin: 5px 0px 18px 10px; border-image: none; float: right; display: inline; background-image: none;" alt="global-usings-solution" src="https://static.gunnarpeipman.com/wp-content/uploads/2022/02/global-usings-solution_thumb.png" border="0"></a>I start with .NET 5.0 console application ported to .NET 6.0 so I have this normal Program.cs file with namespace and Program class. I really don’t like this new age script style stuff that comes with .NET 6.0. It’s good when teaching students to code in C# but in practice I see it as pretty useless feature.</p>
<p>Suppose we have have console program that runs on Task Scheduler and performs some nightly tasks. Screenshot of Solution Explorer on right illustrates what we have. There are some classes to access local file system and cloud storage. There are also some classes to perform import tasks.</p>
<p>Classes that move data from one place to another usually have some repeated using directives. One good example is System.Data and its child namespaces. Everytime we add new class we have to add those using directives again. This holds also true for importer classes shown on screenshot.</p>
<p>Here’s the fragment on one importer class.</p>
<pre style="background: white; color: black; font-family: cascadia mono; font-size: 14px;"><span style="color: blue;">using</span> System.Data;
<span style="color: blue;">using</span> System.Data.SqlClient;
<span style="color: blue;">using</span> ConsoleApp4.FileAccess;
 
<span style="color: blue;">namespace</span> ConsoleApp4.ImportExport;
 
<span style="color: blue;">public</span>&nbsp;<span style="color: blue;">class</span>&nbsp;<span style="color: rgb(43, 145, 175);">CustomersImporter</span>
{<br>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">private</span>&nbsp;<span style="color: blue;">readonly</span> <span style="color: rgb(43, 145, 175);">IFileClient</span> _fileClient;<br>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">private</span>&nbsp;<span style="color: blue;">readonly</span>&nbsp;<span style="color: blue;">string</span> _connectionString;<br><br>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">CustomersImporter</span>(<span style="color: rgb(43, 145, 175);">IFileClient</span> <span style="color: rgb(31, 55, 127);">fileClient</span>, <span style="color: blue;">string</span>&nbsp;<span style="color: rgb(31, 55, 127);">connectionString</span>)<br>&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _fileClient = fileClient;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _connectionString = connectionString;<br>&nbsp;&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: green;">// ...</span>
}</pre>
<p>Three using declarations – first three lines of code above – are present also in other import and export classes.</p>
<h3>Introducing global usings</h3>
<p>C# 10 introduces global usings that are effective over whole project. Let’s add new file GlobalUsings.cs to our project. In this file we define usings that must be available in every class and interface file in our project.</p>
<pre style="background: white; color: black; font-family: cascadia mono; font-size: 14px;"><span style="color: blue;">global</span>&nbsp;<span style="color: blue;">using</span> System.Data;
<span style="color: blue;">global</span>&nbsp;<span style="color: blue;">using</span> System.Data.SqlClient;
<span style="color: blue;">global</span>&nbsp;<span style="color: blue;">using</span> ConsoleApp4.FileAccess;</pre>
<p>We can remove these usings from all other files in our project.</p>
<blockquote>
<p><strong>Don’t put global usings to same file with class or interface.</strong> It’s easy to create a mess when global usings are defined in same file with classes or interfaces. Always keep global usings in separate file.</p>
</blockquote>
<h3>ASP.NET Core 6 application</h3>
<p>Global usings work also in ASP.NET Core applications. There’s _ViewImports.cs file in ASP.NET Core where we can define usings for all views in project. Here’s the example of _ViewImports.cs file after creating a new ASP.NET Core MVC project.</p>
<pre style="background: white; color: black; font-family: cascadia mono; font-size: 14px;"><span style="background: rgb(255, 255, 179);">@</span><span style="color: blue;">using</span> WebApplication1
<span style="background: rgb(255, 255, 179);">@</span><span style="color: blue;">using</span> WebApplication1.Models
<span style="background: rgb(255, 255, 179);">@</span><span style="background: rgb(255, 255, 179);">addTagHelper</span>&nbsp;<span style="color: rgb(163, 21, 21);">*, Microsoft.AspNetCore.Mvc.TagHelpers</span></pre>
<p>Global usings work also for ASP.NET Core MVC views and Razor pages. Instead of keeping usings in _ViewImports.cs file we can make them global in global usings file.</p>
<pre style="background: white; color: black; font-family: cascadia mono; font-size: 14px;"><span style="color: blue;">global</span>&nbsp;<span style="color: blue;">using</span> System.Diagnostics;
<span style="color: blue;">global</span>&nbsp;<span style="color: blue;">using</span> Microsoft.AspNetCore.Mvc;
<span style="color: blue;">global</span>&nbsp;<span style="color: blue;">using</span> Microsoft.AspNetCore.Mvc.RazorPages;</pre>
<blockquote>
<p><strong>Not so fast…</strong> Before abandoning _ViewImports.cs for using declarations think for a moment. Views can be taken as a separate context from all other code in your web application. Using declarations for views may be not needed in code files of your application. Don’t pollute your classes with using declarations you only use in views.</p>
</blockquote>
<h3>Wrapping up</h3>
<p>Global usings is useful feature introduced in C# 10. It may also come specially handy when working with code that uses (too) many namespaces. Global usings are also good feature to keep code files cleaner and define all most needed usings in same file. Luckily it works also with ASP.NET Core MVC views and Razor pages.</p>
<p>The post <a href="https://gunnarpeipman.com/global-usings/">Global usings in C# 10</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gunnarpeipman.com/global-usings/feed/</wfw:commentRss>
			<slash:comments>2353</slash:comments>
		
		
			</item>
		<item>
		<title>Cost of exceptions</title>
		<link>https://gunnarpeipman.com/cost-of-exceptions/</link>
					<comments>https://gunnarpeipman.com/cost-of-exceptions/#comments</comments>
		
		<dc:creator><![CDATA[Gunnar Peipman]]></dc:creator>
		<pubDate>Mon, 28 Jun 2021 05:15:28 +0000</pubDate>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[C#]]></category>
		<guid isPermaLink="false">https://gunnarpeipman.com/?p=6446</guid>

					<description><![CDATA[<p>Hopefully the era of leprosy and corona is over for this time and it’s time to get back to blogging. Exceptions are powerful feature of object-oriented languages as far as they are used like they are thought to use – throw exception only when something really unexpected happens. This advice should be taken seriously – here’s why.</p>
<p>The post <a href="https://gunnarpeipman.com/cost-of-exceptions/">Cost of exceptions</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Hopefully the era of leprosy and corona is over for this time and it’s time to get back to blogging. Exceptions are powerful feature of object-oriented languages as far as they are used like they are thought to use – throw exception only when something really unexpected happens. This advice should be taken seriously – here’s why.</p>
<p><span id="more-6446"></span></p>
<blockquote>
<p>Back in days when I was young and beautyful (now I’m only beautyful) I found utility application to get documents and their metadata out from SharePoint 2001. Although servers were powerful the exporting process was very slow. I took source code of utility and added bunch of sanity checks before exception handling to make sure that code doesn’t hit try-catch blocks if it can be avoided. Instead of 10 days our exports took 4.5 days after my little tweaks.</p>
</blockquote>
<p>It’s hard to notice the effect of exceptions if we measure just one exception but they can be fatal to performance when they appear in loops. Let’s dig a little bit deeper.</p>
<h3>How exceptions are handled?</h3>
<p>Those who think exceptions are just fancy way to return errors are usually surprised when they hear how complex can things be internally – somewhere deep in Common Language Runtime (CLR).</p>
<p>The excellent book <a title="Expert .NET 2.0 IL Assembler by Serge Lidin" href="/expert-net-2-0-il-assembler/">Expert .NET 2.0 IL Assembler</a> by Serge Lidin describes what goes on under the hood. </p>
<blockquote>
<p>The execution engine of the CLR processes an exception in two passes. The first pass determines which, if any, of the managed handlers will process the exception. Starting at the top of the Exception Handling (EH) table for the current method frame, the execution engine compares the address where the exception occured to the TryOffset and TryLength entries of each EH clause. If it finds that the exception happened in guarded block, the execution engine checks to see whether the handler specified in this clause will process the exception. … If none of the clauses in the EH table for the current method is suited to handling the exception, the execution engine steps up the call stack and starts checking the exception against EH tables of the method that called the method where the exception occured.<br />… <br />During the second pass, the finally and fault handlers are invoked with an empty evaluation stack. These handlers do nothing about the exception itself and work only with method arguments and local variables, so the execution engine doesn’t bother providing the exception object.</p>
</blockquote>
<p>Without any numbers there’s are two alert reds for me:</p>
<ol>
<li>Processing in two phases</li>
<li>Climbing up in method call stack and checking for exception handlers</li>
</ol>
<p>These two activities <strong>both</strong> take probably more time than “usual” things we are doing in code.</p>
<h3>Exception versus avoiding exception</h3>
<p>Let’s get into code and numbers to get better understanding about exceptions effect to performance. I’m using simple program that fills list with some strings and nulls. After this let’s ask string length for each element in list and measure how long it takes.</p>
<p>Let’s start with version where asking string length is in try-catch block.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">list</span> = <span style="color: blue;">new</span> <span style="color: rgb(43, 145, 175);">List</span>&lt;<span style="color: blue;">string</span>&gt;();<br><span style="color: rgb(143, 8, 196);">for</span> (<span style="color: blue;">int</span>&nbsp;<span style="color: rgb(31, 55, 127);">i</span> = 0; i &lt; <span style="color: rgb(43, 145, 175);">Math</span>.Pow(10, 6); i++)<br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">if</span> (i == 1 || i % 2 != 0)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list.Add(i.ToString());<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">else</span><br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list.Add(<span style="color: blue;">null</span>);<br>&nbsp;&nbsp;&nbsp; }<br>}<br> <br><span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">watch</span> = <span style="color: blue;">new</span> <span style="color: rgb(43, 145, 175);">Stopwatch</span>();<br>watch.Start();<br> <br><span style="color: rgb(143, 8, 196);">foreach</span> (var <span style="color: rgb(31, 55, 127);">s</span>&nbsp;<span style="color: rgb(143, 8, 196);">in</span> list)<br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">try</span><br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">i</span> = s.Length;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">catch</span> (<span style="color: rgb(43, 145, 175);">Exception</span> <span style="color: rgb(31, 55, 127);">ex</span>)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">e</span> = ex.Message;<br>&nbsp;&nbsp;&nbsp; }<br>}<br> <br>watch.Stop();<br><span style="color: rgb(43, 145, 175);">Console</span>.WriteLine(watch.Elapsed);</pre>
<p>On my machine this code ran through with <strong>4.58 </strong>seconds.</p>
<p>Let’s remove exception handling and replace it with null check so we don’t ask length of null-string.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">list</span> = <span style="color: blue;">new</span> <span style="color: rgb(43, 145, 175);">List</span>&lt;<span style="color: blue;">string</span>&gt;();<br><span style="color: rgb(143, 8, 196);">for</span> (<span style="color: blue;">int</span>&nbsp;<span style="color: rgb(31, 55, 127);">i</span> = 0; i &lt; <span style="color: rgb(43, 145, 175);">Math</span>.Pow(10, 6); i++)<br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">if</span> (i == 1 || i % 2 != 0)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list.Add(i.ToString());<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">else</span><br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list.Add(<span style="color: blue;">null</span>);<br>&nbsp;&nbsp;&nbsp; }<br>}<br> <br><span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">watch</span> = <span style="color: blue;">new</span> <span style="color: rgb(43, 145, 175);">Stopwatch</span>();<br>watch.Start();<br> <br><span style="color: rgb(143, 8, 196);">foreach</span>(var <span style="color: rgb(31, 55, 127);">s</span>&nbsp;<span style="color: rgb(143, 8, 196);">in</span> list)<br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">if</span>(s == <span style="color: blue;">null</span>)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">continue</span>;<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">i</span> = s.Length;<br>}<br> <br>watch.Stop();<br><span style="color: rgb(43, 145, 175);">Console</span>.WriteLine(watch.Elapsed);</pre>
<p>After this modification the code takes <strong>0.008</strong> seconds to run. It’s roughly taken <strong>570 times faster</strong> than letting code fall to exception. So, cost of exceptions can be very high.</p>
<h3>Wrapping up</h3>
<p>Exceptions are powerful feature and without exceptions we should think about our own mechanism how to organize error handling in our code. Like all other powerful features exceptions come with cost. This blog post demonstrated one aspect of it and one popular way how exceptions are abused. The code samples here went from 4.5 seconds to 0.008 seconds by avoiding exceptions. For long processes the win in time can be way bigger.</p>
<p>The post <a href="https://gunnarpeipman.com/cost-of-exceptions/">Cost of exceptions</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gunnarpeipman.com/cost-of-exceptions/feed/</wfw:commentRss>
			<slash:comments>14</slash:comments>
		
		
			</item>
		<item>
		<title>Adding claims to existing identity</title>
		<link>https://gunnarpeipman.com/aspnet-core-adding-claims-to-existing-identity/</link>
					<comments>https://gunnarpeipman.com/aspnet-core-adding-claims-to-existing-identity/#comments</comments>
		
		<dc:creator><![CDATA[Gunnar Peipman]]></dc:creator>
		<pubDate>Mon, 23 Nov 2020 06:00:00 +0000</pubDate>
				<category><![CDATA[ASP.NET]]></category>
		<guid isPermaLink="false">https://gunnarpeipman.com/?p=6440</guid>

					<description><![CDATA[<p>During moving one system from classic ASP.NET MVC to ASP.NET Core I faced an interesting challenge. Although access to system is based on Active Directory there is separate role management based on classic membership and roles providers. There are reasons why AD is not used for role management and I cannot change it. ASP.NET Core uses claims-based authentication and I needed to find a way to add role claims to authenticated identity. Here’s  the solution.</p>
<p>The post <a href="https://gunnarpeipman.com/aspnet-core-adding-claims-to-existing-identity/">Adding claims to existing identity</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>During moving one system from classic ASP.NET MVC to ASP.NET Core I faced an interesting challenge. Although access to system is based on Active Directory there is separate role management based on classic membership and roles providers. There are reasons why AD is not used for role management and I cannot change it. ASP.NET Core uses <a href="/what-is-claims-based-authentication/" title="What is claims-based authentication?">claims-based authentication</a> and I needed to find a way to add role claims to authenticated identity. Here’s&nbsp; the solution.</p>
<p><span id="more-6440"></span></p>
<h3>How things does not work</h3>
<p>Adding claims to existing identity seems like small task to accomplish. But, well, it doesn’t go so easy. We can build middleware class and try something like shown here.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: rgb(143, 8, 196);">foreach</span>(<span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">role</span>&nbsp;<span style="color: rgb(143, 8, 196);">in</span>&nbsp;<span style="color: rgb(31, 55, 127);">user</span>.Roles)<br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">claim</span> = <span style="color: blue;">new</span>&nbsp;<span style="color: rgb(43, 145, 175);">Claim</span>(<span style="color: rgb(31, 55, 127);">newIdentity</span>.RoleClaimType, <span style="color: rgb(31, 55, 127);">role</span>.Name);<br>&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">identity</span>.<span style="color: rgb(116, 83, 31);">AddClaim</span>(<span style="color: rgb(31, 55, 127);">claim</span>);<br>}</pre>
<p>But it doesn’t work with existing identity. No errors, code runs smooth but role claims are just ignored.</p>
<h3>Using claims transformation</h3>
<p>There’s correct way to edit existing identity and it’s called claims transformation. Basically we have to write a custom class that implements <a title="IClaimsTransformation Interface" href="https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.authentication.iclaimstransformation?view=aspnetcore-5.0">IClaimsTransformation interface</a>. Documentation doesn’t give much information about it but most important thing is said – we need to clone given identity.</p>
<p>In short, here’s how the process goes:</p>
<ol>
<li>Clone current user identity</li>
<li>Add custom claims</li>
<li>Return cloned identity</li>
</ol>
<p>Here’s my claims transformation that adds roles to user identity. Notice that I can use dependency injection to inject instances of service classes to my claims transformation. Remember <strong>important</strong> trick – we need a clone of current identity to make things work. </p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">class</span>&nbsp;<span style="color: rgb(43, 145, 175);">AddRolesClaimsTransformation</span> : <span style="color: rgb(43, 145, 175);">IClaimsTransformation</span><br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">private</span>&nbsp;<span style="color: blue;">readonly</span>&nbsp;<span style="color: rgb(43, 145, 175);">IUserService</span> _userService;<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">AddRolesClaimsTransformation</span>(<span style="color: rgb(43, 145, 175);">IUserService</span>&nbsp;<span style="color: rgb(31, 55, 127);">userService</span>)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _userService = <span style="color: rgb(31, 55, 127);">userService</span>;<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">async</span>&nbsp;<span style="color: rgb(43, 145, 175);">Task</span>&lt;<span style="color: rgb(43, 145, 175);">ClaimsPrincipal</span>&gt; <span style="color: rgb(116, 83, 31);">TransformAsync</span>(<span style="color: rgb(43, 145, 175);">ClaimsPrincipal</span>&nbsp;<span style="color: rgb(31, 55, 127);">principal</span>)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: green;">// Clone current identity</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">clone</span> = <span style="color: rgb(31, 55, 127);">principal</span>.<span style="color: rgb(116, 83, 31);">Clone</span>();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">newIdentity</span> = (<span style="color: rgb(43, 145, 175);">ClaimsIdentity</span>)<span style="color: rgb(31, 55, 127);">clone</span>.Identity;<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: green;">// Support AD and local accounts</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">nameId</span> = <span style="color: rgb(31, 55, 127);">principal</span>.Claims.<span style="color: rgb(116, 83, 31);">FirstOrDefault</span>(<span style="color: rgb(31, 55, 127);">c</span> =&gt; <span style="color: rgb(31, 55, 127);">c</span>.Type == <span style="color: rgb(43, 145, 175);">ClaimTypes</span>.NameIdentifier ||<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">c</span>.Type == <span style="color: rgb(43, 145, 175);">ClaimTypes</span>.Name);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">if</span> (<span style="color: rgb(31, 55, 127);">nameId</span> == <span style="color: blue;">null</span>)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">return</span>&nbsp;<span style="color: rgb(31, 55, 127);">principal</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: green;">// Get user from database</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">user</span> = <span style="color: blue;">await</span> _userService.<span style="color: rgb(116, 83, 31);">GetByUserName</span>(<span style="color: rgb(31, 55, 127);">nameId</span>.Value);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">if</span> (<span style="color: rgb(31, 55, 127);">user</span> == <span style="color: blue;">null</span>)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">return</span>&nbsp;<span style="color: rgb(31, 55, 127);">principal</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: green;">// Add role claims to cloned identity</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">foreach</span>(<span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">role</span>&nbsp;<span style="color: rgb(143, 8, 196);">in</span>&nbsp;<span style="color: rgb(31, 55, 127);">user</span>.Roles)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">claim</span> = <span style="color: blue;">new</span>&nbsp;<span style="color: rgb(43, 145, 175);">Claim</span>(<span style="color: rgb(31, 55, 127);">newIdentity</span>.RoleClaimType, <span style="color: rgb(31, 55, 127);">role</span>.Name);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">newIdentity</span>.<span style="color: rgb(116, 83, 31);">AddClaim</span>(<span style="color: rgb(31, 55, 127);">claim</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">return</span>&nbsp;<span style="color: rgb(31, 55, 127);">clone</span>;<br>&nbsp;&nbsp;&nbsp; }<br>}</pre>
<p>The final thing to do is to register claims transformation with dependency injection in ConfigureServices() method of Startup class.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: rgb(31, 55, 127);">services</span>.<span style="color: rgb(116, 83, 31);">AddScoped</span>&lt;<span style="color: rgb(43, 145, 175);">IClaimsTransformation</span>, <span style="color: rgb(43, 145, 175);">AddRolesClaimsTransformation</span>&gt;();<br></pre>
<p>Considering you have authentication already configured and it works, the registered transform will get to authentication flow.</p>
<h3>Wrapping up</h3>
<p>Although adding few claims to existing identity seems like piece of cake, it is not so easy. We cannot just add claims to existing identity and hack it. Claims transformation as custom implementation of IClaimsTransformation interface is the tool we need to use to add claims to existing identity. As we saw we don’t modify existing identity but we clone it, add claims and then return the cloned instance.</p>
<p>The post <a href="https://gunnarpeipman.com/aspnet-core-adding-claims-to-existing-identity/">Adding claims to existing identity</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gunnarpeipman.com/aspnet-core-adding-claims-to-existing-identity/feed/</wfw:commentRss>
			<slash:comments>17</slash:comments>
		
		
			</item>
		<item>
		<title>Running ASP.NET Core 5 RC applications on Azure App Service</title>
		<link>https://gunnarpeipman.com/aspnet-core-5-rc-azure-app-service/</link>
		
		<dc:creator><![CDATA[Gunnar Peipman]]></dc:creator>
		<pubDate>Sun, 04 Oct 2020 11:17:43 +0000</pubDate>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[Azure]]></category>
		<category><![CDATA[Visual Studio]]></category>
		<guid isPermaLink="false">https://gunnarpeipman.com/?p=6434</guid>

					<description><![CDATA[<p>Although .NET 5 is officially in RC and not yet officially supported on Azure cloud we can still deploy ASP.NET Core web applications built for .NET 5 to Azure App Services. I made my first ASP.NET Core 5.0 deployment to Azure App Service last week. There has been no problems on Azure side and my application is running very stable. Here’s how I did it.</p>
<p>The post <a href="https://gunnarpeipman.com/aspnet-core-5-rc-azure-app-service/">Running ASP.NET Core 5 RC applications on Azure App Service</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Although .NET 5 is officially in RC and not yet officially supported on Azure cloud we can still deploy ASP.NET Core web applications built for .NET 5 to Azure App Services. I made my first ASP.NET Core 5.0 deployment to Azure App Service this week. There has been no problems on Azure side and my application is running very stable. Here’s how I did it.</p>
<p><span id="more-6434"></span></p>
<h3>Prerequisites</h3>
<p>To try ASP.NET Core on .NET 5 and Azure App Service out you need the following things:</p>
<ul>
<li><a title="Visual Studio 2019 Preview downloads" href="https://visualstudio.microsoft.com/vs/preview/">Visual Studio 2019 Preview</a></li>
<li><a title="Download .NET 5 RC SDK" href="https://dotnet.microsoft.com/download/dotnet/5.0">.NET 5 RC SDK</a></li>
<li><a title="Azure Portal" href="https://portal.azure.com/">Account on Azure Portal</a></li>
<li>App Service Plan and one App Service</li>
</ul>
<p>For testing I strongly recommend to go with clean App Service Plan and App Service to not affect any live systems you have. After you are done with prerequisites it’s time to create test application.</p>
<h3>Creating web application</h3>
<p>Run Visual Studio 2019 Preview and create new ASP.NET Core Web Application. Here’s the screenshot with settings I used.</p>
<p align="center"><a href="https://static.gunnarpeipman.com/wp-content/uploads/2020/10/create-aspnet-core-5-app.png"><img decoding="async" width="1024" height="710" title="Create new ASP.NET Core 5 application" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="Create new ASP.NET Core 5 application" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/10/create-aspnet-core-5-app_thumb.png" border="0"></a></p>
<p>After creating web application you should see classic ASP.NET Core project structure in Visual Studio.</p>
<p align="center"><a href="https://static.gunnarpeipman.com/wp-content/uploads/2020/10/aspnet-core-5-app-in-visual-studio.png"><img decoding="async" width="982" height="741" title="Default ASP.NET Core 5 application in Visual Studio" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="Default ASP.NET Core 5 application in Visual Studio" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/10/aspnet-core-5-app-in-visual-studio_thumb.png" border="0"></a></p>
<p>Run your application to make sure there are no issues with Visual Studio 2019 Preview or .NET Core 5. You should see default ASP.NET Core application in your browser.</p>
<p align="center"><img decoding="async" width="800" height="484" title="Default ASP.NET Core 5.0 application in browser" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="Default ASP.NET Core 5.0 application in browser" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/10/default-aspnet-core-5-app.png" border="0"></p>
<p>If there were no issues with application and tooling then let’s publish it to Azure cloud.</p>
<h3>Publishing ASP.NET Core 5 application to App Service</h3>
<p>Right click on your ASP.NET Core 5 project in Visual Studio 2019 Preview and select publish. Follow these steps:</p>
<ol>
<li>Select Azure as publishing target and click Next</li>
<li>Select Azure App Service as specific target and click Next</li>
<li>From Azure app service instances list select the instance you created and click Finish</li>
</ol>
<p>Visual Studio creates publishing profile and opens it automatically.</p>
<p align="center"><img decoding="async" width="800" height="632" title="ASP.NET Core 5 publishing window" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="ASP.NET Core 5 publishing window" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/10/aspnet-core-5-publishing-form.png" border="0"></p>
<p>Click on pen icon after Deployment mode field and select Self-contained as deployment mode. By default target runtime is changed to win-x86. You can leave it like it is but you can also switch over to win-x64. Click Save when done. This is how publishing window should look like after these changes.</p>
<p align="center"><img decoding="async" width="800" height="632" title="ASP.NET Core 5 application is published as self-contained application" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="ASP.NET Core 5 application is published as self-contained application" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/10/aspnet-core-5-publishing-self-contained.png" border="0"></p>
<p>And there’s only one thing left to do – click Publish button. After publishing Visual Studio will automatically open your application in new browser window.</p>
<blockquote>
<p><strong>NB!</strong> If you once published application to App Service then next times publishing may fail. Sometimes there is error about no permissions to write over your application files. If this error comes then just restart your App Service and try again. Make sure you don’t click anywhere in browser window where your application is opened as it will load libraries again.</p>
</blockquote>
<h3>References</h3>
<ul>
<li><a title="Self-contained executable with .NET Core 3.0 on Windows, Linux and Raspberry" href="https://gunnarpeipman.com/dotnet-core-self-contained-executable/">Self-contained executable with .NET Core 3.0 on Windows, Linux and Raspberry</a></li>
<li><a title="Publishing ASP.NET Core 3.0 application as self-contained executable to Azure App Service" href="https://gunnarpeipman.com/visual-studio-publish-self-contained-aspnet-core-azure-appservice/">Publishing ASP.NET Core 3.0 application as self-contained executable to Azure App Service</a></li>
</ul>
<p>The post <a href="https://gunnarpeipman.com/aspnet-core-5-rc-azure-app-service/">Running ASP.NET Core 5 RC applications on Azure App Service</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Hosting applications on Azure B-series virtual machines</title>
		<link>https://gunnarpeipman.com/azure-b-series-virtual-machines/</link>
					<comments>https://gunnarpeipman.com/azure-b-series-virtual-machines/#comments</comments>
		
		<dc:creator><![CDATA[Gunnar Peipman]]></dc:creator>
		<pubDate>Fri, 11 Sep 2020 07:53:44 +0000</pubDate>
				<category><![CDATA[Azure]]></category>
		<category><![CDATA[Linux]]></category>
		<guid isPermaLink="false">https://gunnarpeipman.com/?p=6225</guid>

					<description><![CDATA[<p>My fellow MVP Jiří Činčura wrote a nice blog post about hosting ASP.NET Core applications on Azure B-series small virtual machines: Running ASP.NET Core app on Azure B1ls VM (penny pinching). It’s the cheapest option on Azure for small applications. In this blog post I give you some additional advice about smallest B1-series virtual machines so you can build up a little safety net for your applications to make sure they don’t run out from resources.</p>
<p>The post <a href="https://gunnarpeipman.com/azure-b-series-virtual-machines/">Hosting applications on Azure B-series virtual machines</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>My fellow MVP <a title="Jiř&iacute; Činčura - tabs over spaces" href="https://www.tabsoverspaces.com/">Jiří Činčura</a> wrote a nice blog post about hosting ASP.NET Core applications on Azure B-series small virtual machines: <a title="Running ASP.NET Core app on Azure B1ls VM (penny pinching)" href="https://www.tabsoverspaces.com/233836-running-aspnet-core-app-on-azure-b1ls-vm-penny-pinching?utm_source=feed">Running ASP.NET Core app on Azure B1ls VM (penny pinching)</a>. It’s the cheapest option on Azure for small applications. In this blog post I give you some additional advice about smallest B1-series virtual machines so you can build up a little safety net for your applications to make sure they don’t run out from resources.</p>
<p><span id="more-6225"></span></p>
<blockquote>
<p><strong>Azure B-series virtual machines.</strong> The B-series VMs are ideal for workloads that do not need the full performance of the CPU continuously, like web servers, proof of concepts, small databases and development build environments. These workloads typically have burstable performance requirements. The B-series provides you with the ability to purchase a VM size with baseline performance and the VM instance builds up credits when it is using less than its baseline. Source: <a title="B-series burstable virtual machine sizes" href="https://docs.microsoft.com/en-us/azure/virtual-machines/sizes-b-series-burstable">B-series burstable virtual machine sizes (Microsoft)</a></p>
</blockquote>
<p>By my own experiences I agree with Jiří Činčura – B1ls VM-s are great for hosting small applications that doesn’t expect big number of visitors. Also applications hosted on those small VM-s shouldn’t be resource eaters. And it’s just 3.20 EUR/month for Linux VM that is alive 24/7.</p>
<h3>Optimizing small virtual machines</h3>
<p>Still things may get out of hand if we push it to the limits and I have some advice to build simple safety net for your application to avoid bad surprises:</p>
<ul>
<li><strong>Use SSD disk</strong> – SSD disks are more stable and reliable than regular HDD-s. </li>
<li><strong>Create swap file</strong> – if your application needs more memory then without swap file your VM will be unresponsive black hole for more than half an hour. Swap file is not magic bullet – don’t forget there’s tight IOPS limit. Also programs may need physical memory and run out of it although swap file is available with enough space.</li>
<li><strong>Keep static content on blob storage</strong> – don’t forget you have only small number of IOPS to spend. Static files like images, styles and scripts can be held on Azure blob storage if they put too much load on VM.</li>
<li><strong>Use Network Security group rules</strong> – if you know IP-s from where users come then limit access to your VM to these IP-s. You can use <a title="Network security groups" href="https://docs.microsoft.com/en-us/azure/virtual-network/security-overview">Network security group of your VM</a> to do that. This way bots and malicious scripts doesn’t hit your application and doesn’t make it consume resources.</li>
<li><strong>Disable OMS agent</strong> – OMS agent monitors your VM on guest level and sometimes it takes too much resources. I had to uninstall it from few of my small VM-s. You can do it from VM settings. Just open Extensions page from left menu. Of course, disable OMS agent only if you <strong>really</strong> need to do so.</li>
</ul>
<p>B1ls VM-s are not good choice for public web servers and reverse proxies. There are many malicious bots and nasty spammers lurking around in internet and they can be active enough to make web server run out from resources. </p>
<blockquote>
<p><strong>Keep the secret, please :)</strong> I know few public sites that use B-series VM-s. B1s enough to run WordPress behing reverse proxy and B1ms is enough to have reverse proxy with caching and security modules. It’s easy to hide WordPress from public web and make it accessible only through reverse proxy. If it seems interesting then do it only on your own responsibility.</p>
</blockquote>
<h3>Sizes of small B-series virtual machines</h3>
<p>Here’s the table with smaller B-series virtual machines and their prices. Notice that prices may differ by region.</p>
<table>
<thead>
<tr>
<th>Size</th>
<th>vCPUs</th>
<th>RAM</th>
<th>IOPS</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<tr>
<td>B1ls</td>
<td>1</td>
<td>0.5</td>
<td>160</td>
<td>3.20 EUR</td>
</tr>
<tr>
<td>B1s</td>
<td>1</td>
<td>1</td>
<td>320</td>
<td>6.40 EUR</td>
</tr>
<tr>
<td>B1ms</td>
<td>1</td>
<td>2</td>
<td>640</td>
<td>12.74 EUR</td>
</tr>
<tr>
<td>B2s</td>
<td>2</td>
<td>4</td>
<td>1280</td>
<td>25.61 EUR</td>
</tr>
<tr>
<td>B2ms</td>
<td>2</td>
<td>8</td>
<td>1920</td>
<td>51.22 EUR</td>
</tr>
<tr>
<td>B4s</td>
<td>4</td>
<td>16</td>
<td>2880</td>
<td>102.19 EUR</td>
</tr>
</tbody>
</table>
<p>If you grow out from B1ls then it’s possible to jump to B1s or B1ms. The trick is simple – always take next size and see if it works out well. Of course, it’s also clever to compare prices of other VM series to see if there’s some better option than what B-series has to offer.</p>
<blockquote>
<p><strong>Even more penny-picking.</strong> You can make VM automatically shut down at given time of day. There is setting for this in Azure portal. If you want VM to automatically wake up in the morning then you must write some script. By example, you can use <a title="az vm start" href="https://docs.microsoft.com/en-us/cli/azure/vm?view=azure-cli-latest#az_vm_start">az vm start</a> command from Azure CLI to start virtual machine. Now you even less as your VM consumes resources only when it runs.</p>
</blockquote>
<h3>Wrapping up</h3>
<p>B-series virtual machines on Azure are cheapest ones to host applications. But with low costs come also very limited resources. Running public sites on cheapest VM-s is risky business and in my experience you need a good game plan to do it. Applications with restricted access are better choice as you don’t have to consider unexpected surprises from public web. B-series VM-s allow your application to grow the cheap way as VM size next to current gives you more resources with small raise in expenses.</p>
<p>The post <a href="https://gunnarpeipman.com/azure-b-series-virtual-machines/">Hosting applications on Azure B-series virtual machines</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gunnarpeipman.com/azure-b-series-virtual-machines/feed/</wfw:commentRss>
			<slash:comments>254</slash:comments>
		
		
			</item>
		<item>
		<title>Developing software on Surface Go 2</title>
		<link>https://gunnarpeipman.com/surface-go-2-software-development/</link>
					<comments>https://gunnarpeipman.com/surface-go-2-software-development/#comments</comments>
		
		<dc:creator><![CDATA[Gunnar Peipman]]></dc:creator>
		<pubDate>Sat, 05 Sep 2020 03:50:15 +0000</pubDate>
				<category><![CDATA[Various]]></category>
		<guid isPermaLink="false">https://gunnarpeipman.com/?p=6222</guid>

					<description><![CDATA[<p>My previous post about Surface Go 2 was brief introduction based on my own experiences after one month of using it. Surface Go 2 is lightweight machine with limited hardware resources. It’s not your next portable dev machine as it’s more to the tablets world but still there are some software development options to consider before buying Surface Go 2. Here’s my advice.</p>
<p>The post <a href="https://gunnarpeipman.com/surface-go-2-software-development/">Developing software on Surface Go 2</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>My <a title="Surface Go 2 review" href="https://gunnarpeipman.com/surface-go-2/">previous post about Surface Go 2</a> was brief introduction based on my own experiences after one month of using it. Surface Go 2 is lightweight machine with limited hardware resources. It’s not your next portable dev machine as it’s more to the tablets world but still there are some software development options to consider before buying <a title="Surface Go 2" href="https://www.microsoft.com/en-us/p/surface-go-2/8pt3s2vjmdr6?activetab=pivot%3aoverviewtab">Surface Go 2</a>. Here’s my advice.</p>
<p><span id="more-6222"></span></p>
<blockquote>
<p><strong>It’s all from real life.</strong> Before and during writing this post I tried out all options described in this post. I used real ASP.NET Core project I’m writing for one of my customer and I tried to complete real tasks on Surface Go 2.</p>
</blockquote>
<h3>1. Remote Desktop to in-prem machine</h3>
<p>Maybe the easiest way to build software on Surface Go 2 is to have VPN connection to company network and use Remote Desktop to connect to main dev box. All you need to do is to set up VPN connection in your Surface Go 2 and you are good to go.</p>
<p>If you are working from home like me then probably you are interested in connection to machine located in your home network. Yes, sure, you can open Remote Desktop port in your router and redirect all traffic to your dev box but stop for a moment. It’s not secure. Depending on router and its software you can probably set up VPN right in your router. I strongly recommend you to do it to keep your machines and home network safe.</p>
<p>With RDC you can configure screen size and resolution of session to remote machine. With very low settings you should be able to have stable connection to dev box even over slow network.</p>
<p><strong>Pros</strong></p>
<ul>
<li>Energy efficient as Remote Desktop has compact protocol</li>
<li>Leaves enough resources for other applications to run</li>
</ul>
<p><strong>Cons</strong></p>
<ul>
<li>No chance for offline work</li>
<li>Not all applications scale on screen over Remote Desktop</li>
<li>Sometimes it’s not so easy to get VPN to company network</li>
<li>For home network all security is up to you</li>
</ul>
<h3>2. Remote Desktop to cloud machine</h3>
<p>If you don’t want to buy hardware for dev box and you prefer to go with what cloud environments offer then you may have your virtual dev box in cloud. On Azure you can set up different virtual machines and use Windows or Linux as operating system.</p>
<p>On Azure virtual machines have nice feature – automatic shutdown. If you leave virtual machine running when you finish your work then it still consumes resources and grows your bill. And it’s easy to forget virtual machine running. With automatic shutdown feature you can set time when virtual machine is shutdown automatically. If you vote for Azure cloud I strongly recommend to use this feature.</p>
<p>With virtual machines on Azure you have two options to get connected – Remote Desktop and SSH. If you prefer Remote Desktop then it’s practically like the first option discussed here. On Azure you can have virtual network and VPN gateway to make your dev box accessible only over VPN. But be warner – this option comes with high price tag.</p>
<p><strong>Pros</strong></p>
<ul>
<li>Energy efficient as Remote Desktop has compact protocol</li>
<li>Leaves enough resources for other applications to run</li>
<li>You can set all things up exactly like you wish</li>
</ul>
<p><strong>Cons</strong></p>
<ul>
<li>You need stable network connection to use Remote Desktop</li>
<li>No chance for offline work</li>
<li>Not all applications scale on screen over Remote Desktop</li>
<li>VPN gateway service is expensive</li>
</ul>
<h3>3. SSH to remote machine using Visual Studio Code</h3>
<p>No matter where your dev box is located, in some cases you can keeps things smaller when accessing your dev box over SSH – be it Windows or Linux machine. And what’s best – Visual Studio Code has extensions for SSH. </p>
<p>What it means? You can run Visual Studio Code straight on your Surface Go 2 and connect to your project folder in dev box using SSH. User experience is practically the same as using Visual Studio Code for local development. </p>
<p>What’s still up to you is to organize dev machine and host it somewhere – be it company network, cloud or your home network. </p>
<p><strong>Pros</strong></p>
<ul>
<li>It’s Visual Studio Code with all goodness running on your machine</li>
<li>Enough resources to run other programs too</li>
</ul>
<p><strong>Cons</strong></p>
<ul>
<li>No option for offline work</li>
<li>You need stable internet connection</li>
<li>Hosting and managing of dev box is up to you</li>
</ul>
<h3>4. Using Visual Studio Codespaces with Visual Studio Code</h3>
<p>Visual Studio Codespaces is online service by Microsoft that you can use to run virtual dev box on cloud and write code using Visual Studio Code or online code editor provided by service. </p>
<p>This option is a little bit similar to SSH to remote machine using Visual Studio Code but instead of machine set up by you there’s VM set up by Codespaces service. When configuring this machine you will specify code repository, size of machine and idle timeout. If you have not used your VM for specified amount of time then Codespaces service will shut it down to save expenses.</p>
<p><strong>Pros</strong></p>
<ul>
<li>Usual Visual Studio Code experience with all its goodness</li>
</ul>
<p><strong>Cons</strong></p>
<ul>
<li>Not an option for offline work</li>
<li>Service has only Linux boxes right now</li>
<li>Not much options to configure your VM</li>
</ul>
<h3>5. Local development with Visual Studio Code</h3>
<p>If you don’t have complex application to build then it’s also possible to build it locally on Surface Go 2. This option is perfect for more lightweight solutions like web applications, Azure Functions and console applications.</p>
<p>Some of my readers probably want to ask now – but what about database? Surface Go 2 is not for running SQL Server, even Express Edition will be overkill for this machine. </p>
<p>There are few things you can do:</p>
<ol>
<li>Connect to SQL Server hosted on some other machine. It’s not perfect choice, specially when SQL Server is located thousands of miles away. The closer you are to SQL Server the better connection you have.</li>
<li>Use SQLite on Surface Go 2. You can use SQLite as it is small and lightweight. You get something close to relational database but consider one important thing – SQLite is not SQL Server. Make sure you have unit and integration tests for your code to make sure that your LINQ-queries are translated to correct SQL Server commands. SQLite is supported by NHibernate and Entity Framework Core.</li>
<li>Use in-memory database of Entity Framework Core. In-memory database that comes with Entity Framework Core doesn’t have any files on disk. It lives only in machine memory until your program is running. When program is stopped then in-memory database is gone. Again – in-memory database is not same as SQL Server and I strongly recommend you to use tests to make sure that code you wrote works well with SQL Server too. </li>
</ol>
<p>If you are using Entity Framework Core or NHibernate as you object-relational mapper you can be sure both of them support SQLite. If you wrote your own data layer then things may get very complicated on supporting different database products and I highly recommend you to use database in some other machine.</p>
<p><strong>Pros</strong></p>
<ul>
<li>Visual Studio Code with all plugins and extensions you need</li>
<li>Work online or offline</li>
<li>It’s possible to use SQLite or in-memory database to mimic real databases</li>
</ul>
<p><strong>Cons</strong></p>
<ul>
<li>When offline you have no access to real databases like MSSQL, MySL, Postgre etc</li>
<li>Building of solution may drain the battery fast</li>
<li>When travelling it’s easy to forget to commit code changes back to repository</li>
</ul>
<h3>Conclusion</h3>
<p>Although Surface Go 2 is not for software development but targeted more to business people it is still possible to use it for coding. Sure, it will not be the main dev box but it’s excellent complement to it for days when there are meetings at customer site or you need to travel from one place to another. If you really plan to use Surface Go 2 for software development then I suggest LTE version as it’s always connected and you don’t depend on availability and stability of near-by WiFi.</p>
<p>The post <a href="https://gunnarpeipman.com/surface-go-2-software-development/">Developing software on Surface Go 2</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gunnarpeipman.com/surface-go-2-software-development/feed/</wfw:commentRss>
			<slash:comments>193</slash:comments>
		
		
			</item>
		<item>
		<title>Accessing restricted blob storage from virtual networks and Azure CDN</title>
		<link>https://gunnarpeipman.com/access-restricted-blob-storage-from-azure-cdn/</link>
					<comments>https://gunnarpeipman.com/access-restricted-blob-storage-from-azure-cdn/#comments</comments>
		
		<dc:creator><![CDATA[Gunnar Peipman]]></dc:creator>
		<pubDate>Fri, 04 Sep 2020 04:58:09 +0000</pubDate>
				<category><![CDATA[Azure]]></category>
		<guid isPermaLink="false">https://gunnarpeipman.com/?p=6219</guid>

					<description><![CDATA[<p>I decided to isolate Azure storage account behind this blog due to growing number of attacks against this little nice reading corner. I have anyway Azure CDN service enabled and it is perfect tool to get all static content of this blog as close to my dear readers as possible. Azure storage can be expensive and this is why I don’t want unbuffered traffic to land there, specially if it is generated by bunch of bots that doesn’t commit to glory of this blog anyhow. Here’s how to restrict public access to Azure storage account but keeping blob storage open for virtual machines and other Azure services.</p>
<p>The post <a href="https://gunnarpeipman.com/access-restricted-blob-storage-from-azure-cdn/">Accessing restricted blob storage from virtual networks and Azure CDN</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>I decided to isolate Azure storage account behind this blog due to growing number of attacks against this little nice reading corner. I have anyway Azure CDN service enabled and it is perfect tool to get all static content of this blog as close to my dear readers as possible. Azure storage can be expensive and this is why I don’t want unbuffered traffic to land there, specially if it is generated by bunch of bots that doesn’t commit to glory of this blog anyhow. Here’s how to restrict public access to Azure storage account but keeping blob storage open for virtual machines and other Azure services.</p>
<p><span id="more-6219"></span></p>
<h3>What we want to achieve</h3>
<p>Here’s the simple overview of architecture components involved to blob storage topic. On this diagram components are connected the way I want it to be finally.</p>
<p align="center"><img decoding="async" width="503" height="451" title="Blog components related to Azure blob storage" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="Blog components related to Azure blob storage" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/09/blog-vm-storage-cdn.png" border="0"></p>
<p>Publisher must have direct access to blob storage from specified static IP. Backend machines must also be able to access blob storage as they publish newly combined and minified CSS and JS files to blob storage automatically. It’s clear that Azure CDN must be able to access blob storage. The last accessor is blog reader from public internet. Readers access static content only through Azure CDN.</p>
<h3>Virtual network for virtual machines</h3>
<p>As my blog is hosted on virtual machines (VM) then I have virtual network where all these VM-s belong. One of them is directly visible to public internet while others are not directly accessible.</p>
<p align="center"><img decoding="async" width="676" height="643" title="My blog's virtual network" style="display: inline; background-image: none;" alt="My blog's virtual network" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/09/blog-vnet.png" border="0"></p>
<p>If I restrict access to blob storage then somehow VM-s must still have access to it and for this we need service endpoint to blob storage. This will be the link between vnet and blob storage.&nbsp; </p>
<h3>Configuring storage account</h3>
<p>The easiest way to restrict access to blob storage and create service endpoint at same time is to configure storage account. With just few moves we will get all settings in place.</p>
<p align="center"><a href="https://static.gunnarpeipman.com/wp-content/uploads/2020/09/blog-blob-storage-vnets.png"><img decoding="async" width="1233" height="823" title="Restricting access to blob storage" style="display: inline; background-image: none;" alt="Restricting access to blob storage" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/09/blog-blob-storage-vnets_thumb.png" border="0"></a></p>
<p>Here are the steps I did:</p>
<ol>
<li>Open storage account settings in Azure portal</li>
<li>Move to Firewalls and virtual networks section</li>
<li>Allow access from selected networks only</li>
<li>Select your vnet and let Azure to add service end-point there for blob storage</li>
<li>To firewall address ranges add the IP-s you use to access blob storage (static IP in office or home)</li>
<li><strong>Important!</strong> Add address range of Azure CDN service: 147.243.0.0/16</li>
<li>Make sure you have selected checkbox “Allow trusted Microsoft services to access this storage account”</li>
<li>Leave all other settings like they are and click Save.</li>
</ol>
<p>The whole process takes few minutes of time and I faced no single issue. When file is directly requested from blob storage then the result is XML with error information.</p>
<p align="center"><img decoding="async" width="602" height="262" title="Direct access to files on blob storage is not allowed" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="Direct access to files on blob storage is not allowed" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/09/blob-storage-authorization-failure.png" border="0"></p>
<h3>Wrapping up</h3>
<p>It’s great how I can control and configure services on Azure I use to host this blog. Keeping expenses under control by restricting access to blob storage may come with some small financial wins. But more important is to avoid mistakes like allowing blog to generate direct links to blob storage when Azure CDN is there to take all static content as close to reader as possible. I’m even more suspicious on aggressive bots that are trying to index things too frequently and therefore generate big amount of storage transactions.</p>
<p>The post <a href="https://gunnarpeipman.com/access-restricted-blob-storage-from-azure-cdn/">Accessing restricted blob storage from virtual networks and Azure CDN</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gunnarpeipman.com/access-restricted-blob-storage-from-azure-cdn/feed/</wfw:commentRss>
			<slash:comments>256</slash:comments>
		
		
			</item>
		<item>
		<title>Top-level programs in C# 9.0</title>
		<link>https://gunnarpeipman.com/csharp-top-level-programs/</link>
					<comments>https://gunnarpeipman.com/csharp-top-level-programs/#comments</comments>
		
		<dc:creator><![CDATA[Gunnar Peipman]]></dc:creator>
		<pubDate>Thu, 03 Sep 2020 07:02:20 +0000</pubDate>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[C#]]></category>
		<guid isPermaLink="false">https://gunnarpeipman.com/?p=6212</guid>

					<description><![CDATA[<p>C# 9.0 comes with nice new feature called top-level programs. It’s something that teachers of beginner classes will love for sure. Imagine – you start teaching C# with only two lines of code on screen. All missing code is generated by compiler. This blog post introduces top-level programs and shows some secrets of new C# compiler.</p>
<p>The post <a href="https://gunnarpeipman.com/csharp-top-level-programs/">Top-level programs in C# 9.0</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>C# 9.0 comes with nice new feature called top-level programs. It’s something that teachers of beginner classes will love for sure. Imagine – you start teaching C# with only two lines of code on screen. All missing code is generated by compiler. This blog post introduces top-level programs and shows some secrets of new C# compiler.</p>
<p><span id="more-6212"></span></p>
<h3>Classic console application</h3>
<p>Here’s the classic console application. We have seen it thousands of times and we know what it does and how it works.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">using</span> System;<br> <br><span style="color: blue;">namespace</span> ConsoleApp6<br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">class</span>&nbsp;<span style="color: rgb(43, 145, 175);">Program</span><br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">static</span>&nbsp;<span style="color: blue;">void</span> Main(<span style="color: blue;">string</span>[] args)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">Console</span>.WriteLine(<span style="color: rgb(163, 21, 21);">"Hello World!"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>}</pre>
<p>When students see this they usually have more than one question:</p>
<ol>
<li>What is doing “using System”?</li>
<li>What is “namespace”?</li>
<li>What is string “string[] args”?</li>
</ol>
<p>Besides question there’s too much noice for them and all work on whiteboard happens inside Main() method.</p>
<h3>What is top-level program?</h3>
<p>With C# 9 we can skip all the noise and use top-level programs. Same code with this new feature looks like this.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">using</span> System;<br> <br><span style="color: rgb(43, 145, 175);">Console</span>.WriteLine(<span style="color: rgb(163, 21, 21);">"Hello World!"</span>);</pre>
<p>Just two lines, no spacing and all the screen space is for my examples. Great!</p>
<p>Of course, I must have using directives but here’s the little trick to calm youngsters down.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">using</span> System; <span style="color: green;">// let's talk about it later</span><br> <br><span style="color: rgb(43, 145, 175);">Console</span>.WriteLine(<span style="color: rgb(163, 21, 21);">"Hello World!"</span>);</pre>
<blockquote>
<p><strong>Not only for teachers.</strong> Top-level programs can be used also in practice when writing real code. It is perfect when writing simple utility applications that doesn’t have much code.</p>
</blockquote>
<p>Top-level programs are C# language feature and it doesn’t come down to Common Language Runtime (CLR). C# compiler produces Program class and Main() method (almost) like it was before.</p>
<p>But what about args argument of Main() method? It’s magically here and available in top-level programs. Here’s how to write out all arguments of program.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">for</span>(<span style="color: blue;">var</span> i = 0; i &lt; args.Length; i++)<br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">Console</span>.Write(i);<br>&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">Console</span>.Write(<span style="color: rgb(163, 21, 21);">" "</span>);<br>&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">Console</span>.WriteLine(args[i]);<br>}</pre>
<h3>Using methods in top-level programs</h3>
<p>We can write methods too. Notice that methods in top-level programs must be static. </p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">using</span> System; <span style="color: green;">// let's talk about it later</span><br> <br><span style="color: rgb(43, 145, 175);">Console</span>.WriteLine(SayHello(<span style="color: rgb(163, 21, 21);">"students"</span>));<br> <br><span style="color: blue;">static</span>&nbsp;<span style="color: blue;">string</span> SayHello(<span style="color: blue;">string</span> name)<br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">return</span>&nbsp;<span style="color: rgb(163, 21, 21);">"Hello, "</span> + name;<br>}</pre>
<p>It’s interesting to see how methods in top-level programs look like functions in functional languages.</p>
<h3>Using classes in top-level programs</h3>
<p>We can also use classes and other things like structures, enums etc. The next code sample demonstrates primitive greeter class.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">using</span> System; <span style="color: green;">// let's talk about it later</span><br> <br><span style="color: blue;">var</span> greeter = <span style="color: blue;">new</span>&nbsp;<span style="color: rgb(43, 145, 175);">Greeter</span>();<br> <br><span style="color: blue;">var</span> helloTeacher = greeter.Greet(<span style="color: rgb(163, 21, 21);">"teacher"</span>);<br><span style="color: blue;">var</span> helloStudents = SayHello(<span style="color: rgb(163, 21, 21);">"students"</span>);<br> <br><span style="color: rgb(43, 145, 175);">Console</span>.WriteLine(helloTeacher);<br><span style="color: rgb(43, 145, 175);">Console</span>.WriteLine(helloStudents);<br> <br><span style="color: blue;">static</span>&nbsp;<span style="color: blue;">string</span> SayHello(<span style="color: blue;">string</span> name)<br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">return</span>&nbsp;<span style="color: rgb(163, 21, 21);">"Hello, "</span> + name;<br>}<br> <br><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">class</span>&nbsp;<span style="color: rgb(43, 145, 175);">Greeter</span><br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">string</span> Greet(<span style="color: blue;">string</span> name)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">return</span>&nbsp;<span style="color: rgb(163, 21, 21);">"Hello, "</span> + name;<br>&nbsp;&nbsp;&nbsp; }<br>}</pre>
<p>In this point things may get a little bit messy as there are methods and classes coming one after another.</p>
<blockquote>
<p><strong>Order matters!</strong> In top-level programs type definitions must come after top-level statements. It means after everything that goes to Program class.</p>
</blockquote>
<h3>Top-level programs after compiling</h3>
<p>Classes in top-level programs are not particularly interesting as they are compiled like usual. But things get interesting with Program class and Main() method. Here’s the decompiled code of sample with greeter class. </p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">using</span> System;<br><span style="color: blue;">using</span> System.Runtime.CompilerServices;<br> <br>[<span style="color: rgb(43, 145, 175);">CompilerGenerated</span>]<br><span style="color: blue;">internal</span>&nbsp;<span style="color: blue;">static</span>&nbsp;<span style="color: blue;">class</span> &lt;<span style="color: rgb(43, 145, 175);">Program</span>&gt;$<br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">private</span>&nbsp;<span style="color: blue;">static</span>&nbsp;<span style="color: blue;">void</span> &lt;<span style="color: rgb(43, 145, 175);">Main</span>&gt;$(<span style="color: blue;">string</span>[] args)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">string</span> str1 = <span style="color: blue;">new</span> Greeter().Greet(<span style="color: rgb(163, 21, 21);">"teacher"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">string</span> str2 = &lt;Program&gt;$.&lt;&lt;<span style="color: rgb(43, 145, 175);">Main</span>&gt;$&gt;g__SayHello|0_0(<span style="color: rgb(163, 21, 21);">"students"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">Console</span>.WriteLine(str1);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">Console</span>.WriteLine(str2);<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">internal</span>&nbsp;<span style="color: blue;">static</span>&nbsp;<span style="color: blue;">string</span> &lt;&lt;Main&gt;$&gt;g__SayHello|0_0(<span style="color: blue;">string</span> name)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">return</span>&nbsp;<span style="color: rgb(163, 21, 21);">"Hello, "</span> + name;<br>&nbsp;&nbsp;&nbsp; }<br>}</pre>
<p>Important things to notice:</p>
<ul>
<li>Program class has CompilerGenerated attribute</li>
<li>Program class, Main() method and SayHello() method have obfuscated names that make it impossible to refer to them in .NET languages.</li>
<li>All top-level code members are in private or internal scope and invisible to other libraries.</li>
</ul>
<p>Of course, it doesn’t stop us using obfuscated names if we use reflection. But I really don’t see any use case where we would need it and where we really cannot use some other approach.</p>
<h3>Wrapping up</h3>
<p>Top-level programs is nice C# language feature that cleans up Main() method of Program class by generating class and method automatically. All we have to do is to write the code and build it. Top-level programs have different Program class and Main() method as these are compiler generated. These two are not directly accessible from other libraries although we can do everything we want with reflection. Practical use cases for top-level programs are teaching coding to beginners and writing simple utility applications.</p>
<p>The post <a href="https://gunnarpeipman.com/csharp-top-level-programs/">Top-level programs in C# 9.0</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gunnarpeipman.com/csharp-top-level-programs/feed/</wfw:commentRss>
			<slash:comments>170</slash:comments>
		
		
			</item>
		<item>
		<title>Translating NHibernate LINQ query to SQL</title>
		<link>https://gunnarpeipman.com/nhibernate-linq-tosql/</link>
					<comments>https://gunnarpeipman.com/nhibernate-linq-tosql/#comments</comments>
		
		<dc:creator><![CDATA[Gunnar Peipman]]></dc:creator>
		<pubDate>Tue, 01 Sep 2020 04:25:09 +0000</pubDate>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[Data platform]]></category>
		<guid isPermaLink="false">https://gunnarpeipman.com/?p=6201</guid>

					<description><![CDATA[<p>When working with stateless sessions in NHibernate we need some way to see generated SQL but we cannot use simple tricks as custom NHibernate interceptor to log SQL queries. As I’m using mostly NHibernate LINQ these days I was interested in how to get SQL out from LINQ query without actually executing it. Here’s my solution.</p>
<p>The post <a href="https://gunnarpeipman.com/nhibernate-linq-tosql/">Translating NHibernate LINQ query to SQL</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>When working with stateless sessions in NHibernate we need some way to see generated SQL but we cannot use simple tricks as <a title="How to log NHibernate SQL to ASP.NET Core loggers" href="https://gunnarpeipman.com/aspnet-core-nhibernate-log-sql/">custom NHibernate interceptor to log SQL queries</a>. As I’m using mostly NHibernate LINQ these days I was interested in how to get SQL out from LINQ query without actually executing it. Here’s my solution.</p>
<p><span id="more-6201"></span></p>
<h3>ToSql() extension method</h3>
<p>I wrote simple ToSql() extension method for IQueryable generated by NHibernate LINQ. It also writes out parameters.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">static</span>&nbsp;<span style="color: blue;">class</span>&nbsp;<span style="color: rgb(43, 145, 175);">NHibernateExtensions</span><br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">static</span>&nbsp;<span style="color: blue;">string</span> ToSql(<span style="color: blue;">this</span>&nbsp;<span style="color: rgb(43, 145, 175);">IQueryable</span> query)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span> provider = query.Provider <span style="color: blue;">as</span>&nbsp;<span style="color: rgb(43, 145, 175);">DefaultQueryProvider</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">if</span>(provider == <span style="color: blue;">null</span>)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">return</span>&nbsp;<span style="color: blue;">null</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span> sessionImpl = provider.Session;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span> factory = sessionImpl.Factory;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span> linqExpression = <span style="color: blue;">new</span>&nbsp;<span style="color: rgb(43, 145, 175);">NhLinqExpression</span>(query.Expression, factory);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span> translatorFactory = <span style="color: blue;">new</span>&nbsp;<span style="color: rgb(43, 145, 175);">ASTQueryTranslatorFactory</span>();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span> translator = translatorFactory.CreateQueryTranslators(linqExpression, <span style="color: blue;">null</span>, <span style="color: blue;">false</span>, sessionImpl.EnabledFilters, factory).First();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span> parameters = linqExpression.ParameterValuesByName.ToDictionary(x =&gt; x.Key, x =&gt; x.Value.Item1);<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span> result = translator.SQLString;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">foreach</span> (<span style="color: blue;">var</span> parameter <span style="color: blue;">in</span> parameters)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result += <span style="color: rgb(163, 21, 21);">"</span><span style="color: rgb(183, 118, 251);">\r\n</span><span style="color: rgb(163, 21, 21);">"</span> + parameter.Key + <span style="color: rgb(163, 21, 21);">": "</span> + parameter.Value;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">return</span> result.Trim();<br>&nbsp;&nbsp;&nbsp; }<br>}</pre>
<p>ToSql() extension method uses only classes needed to translate LINQ expression tree to SQL. </p>
<h3>Using ToSql() extension method</h3>
<p>The following piece of code shows how to use ToSql() extension method. To find out more about my IDataMapper interface that mimics DbContext of Entity Framework Core, please read my blog post <a title="NHibernate on ASP.NET Core" href="https://gunnarpeipman.com/aspnet-core-nhibernate/">NHibernate on ASP.NET Core</a>.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">var</span> projectQuery = _dataMapper.AsNoTracking()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Projects<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Fetch(c =&gt; c.Customer)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Fetch(c =&gt; c.Mediator)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Where(p =&gt; p.Id == id);<br> <br><span style="color: blue;">var</span> projectSql = projectQuery.ToSql();<br><span style="color: blue;">var</span> projects = <span style="color: blue;">await</span> projectQuery.FirstOrDefaultAsync();</pre>
<p>When projectSql variable is evaluated the query is not executed. It is only translated to SQL. Query is executed when projects variable is evaluated as then data is actually asked from projectQuery.</p>
<p>Here’s the result of ToSql() extension method. </p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">select</span>&nbsp;<br>&nbsp;&nbsp;&nbsp; project0_<span style="color: gray;">.</span>Id <span style="color: blue;">as</span> id1_2_0_<span style="color: gray;">,</span>&nbsp;<br>&nbsp;&nbsp;&nbsp; customer1_<span style="color: gray;">.</span>Id <span style="color: blue;">as</span> id1_1_1_<span style="color: gray;">,</span>&nbsp;<br>&nbsp;&nbsp;&nbsp; customer2_<span style="color: gray;">.</span>Id <span style="color: blue;">as</span> id1_1_2_<span style="color: gray;">,</span>&nbsp;<br>&nbsp;&nbsp;&nbsp; project0_<span style="color: gray;">.</span>Title <span style="color: blue;">as</span> title2_2_0_<span style="color: gray;">,</span>&nbsp;<br>&nbsp;&nbsp;&nbsp; project0_<span style="color: gray;">.</span>ProjectKey <span style="color: blue;">as</span> projectkey3_2_0_<span style="color: gray;">,</span>&nbsp;<br>&nbsp;&nbsp;&nbsp; project0_<span style="color: gray;">.</span>IsActive <span style="color: blue;">as</span> isactive4_2_0_<span style="color: gray;">,</span>&nbsp;<br>&nbsp;&nbsp;&nbsp; project0_<span style="color: gray;">.</span>CustomerId <span style="color: blue;">as</span> customerid5_2_0_<span style="color: gray;">,</span>&nbsp;<br>&nbsp;&nbsp;&nbsp; project0_<span style="color: gray;">.</span>MediatorId <span style="color: blue;">as</span> mediatorid6_2_0_<span style="color: gray;">,</span>&nbsp;<br>&nbsp;&nbsp;&nbsp; project0_<span style="color: gray;">.</span>Deadline <span style="color: blue;">as</span> deadline7_2_0_<span style="color: gray;">,</span>&nbsp;<br>&nbsp;&nbsp;&nbsp; project0_<span style="color: gray;">.</span><span style="color: blue;">Description</span>&nbsp;<span style="color: blue;">as</span> description8_2_0_<span style="color: gray;">,</span>&nbsp;<br>&nbsp;&nbsp;&nbsp; customer1_<span style="color: gray;">.</span><span style="color: blue;">Name</span>&nbsp;<span style="color: blue;">as</span> name2_1_1_<span style="color: gray;">,</span>&nbsp;<br>&nbsp;&nbsp;&nbsp; customer2_<span style="color: gray;">.</span><span style="color: blue;">Name</span>&nbsp;<span style="color: blue;">as</span> name2_1_2_ <br><span style="color: blue;">from</span>&nbsp;<br>&nbsp;&nbsp;&nbsp; Projects project0_ <br>&nbsp;&nbsp;&nbsp; <span style="color: gray;">left</span>&nbsp;<span style="color: gray;">outer</span>&nbsp;<span style="color: gray;">join</span> Customers customer1_ <span style="color: blue;">on</span>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; project0_<span style="color: gray;">.</span>CustomerId<span style="color: gray;">=</span>customer1_<span style="color: gray;">.</span>Id <br>&nbsp;&nbsp;&nbsp; <span style="color: gray;">left</span>&nbsp;<span style="color: gray;">outer</span>&nbsp;<span style="color: gray;">join</span> Customers customer2_ <span style="color: blue;">on</span>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; project0_<span style="color: gray;">.</span>MediatorId<span style="color: gray;">=</span>customer2_<span style="color: gray;">.</span>Id <br><span style="color: blue;">where</span>&nbsp;<br>&nbsp;&nbsp;&nbsp; project0_<span style="color: gray;">.</span>Id<span style="color: gray;">=</span>?<br> <br><span style="color: blue;">p1:</span> d9571e6b<span style="color: gray;">-</span>fa73<span style="color: gray;">-</span>4553<span style="color: gray;">-</span>9c90<span style="color: gray;">-</span>57aa7c050298</pre>
<blockquote>
<p><strong>NB!</strong> ToSql() extension method doesn’t give formatted SQL. It gives it like it is for executing. You can use <a title="Poor Man&rsquo;s T-SQL Formatter service" href="http://poorsql.com/">Poor Man’s T-SQL Formatter service</a> to format queries returned by ToSql() extension method.</p>
</blockquote>
<h3>Wrapping up</h3>
<p>Translating NHibernate LINQ expression tree to SQL without executing query against database server is trick we can use to investigate generated SQL when writing complex queries. I’m using ToSql() extension method also when optimizing slow queries to find out what was actually generated by NHibernate. For more serious work I recomment using advanced tools to monitor NHibernate.</p>
<p>The post <a href="https://gunnarpeipman.com/nhibernate-linq-tosql/">Translating NHibernate LINQ query to SQL</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gunnarpeipman.com/nhibernate-linq-tosql/feed/</wfw:commentRss>
			<slash:comments>174</slash:comments>
		
		
			</item>
		<item>
		<title>How to log NHibernate SQL to ASP.NET Core loggers</title>
		<link>https://gunnarpeipman.com/aspnet-core-nhibernate-log-sql/</link>
					<comments>https://gunnarpeipman.com/aspnet-core-nhibernate-log-sql/#comments</comments>
		
		<dc:creator><![CDATA[Gunnar Peipman]]></dc:creator>
		<pubDate>Thu, 20 Aug 2020 04:01:50 +0000</pubDate>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[Data platform]]></category>
		<guid isPermaLink="false">https://gunnarpeipman.com/?p=6195</guid>

					<description><![CDATA[<p>Logging SQL created by NHibernate ORM is useful when debugging new features of application. SQL logging in NHibernate is a little bit tricky and not so straightforward as it is with Entity Framework Core. This blog post demonstrates how to write SQL created by NHibernate to ASP.NET Core loggers using NHibernate interceptor.</p>
<p>The post <a href="https://gunnarpeipman.com/aspnet-core-nhibernate-log-sql/">How to log NHibernate SQL to ASP.NET Core loggers</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Logging down SQL created by ORM is useful when debugging new features of application. SQL logging in NHibernate is a little bit tricky and not so straightforward as it is with Entity Framework Core. This blog post demonstrates how to log SQL created by NHibernate to ASP.NET Core logger using NHibernate interceptor.</p>
<p><span id="more-6195"></span></p>
<blockquote>
<p><strong>NB! </strong>In this post I will extend some parts of code shown in my blog post <a title="NHibernate on ASP.NET Core" href="https://gunnarpeipman.com/aspnet-core-nhibernate/">NHibernate on ASP.NET Core</a>. Although I copied some code from this post here I suggest you to take time Myand see my previous work.</p>
</blockquote>
<h3>Getting NHibernate to ASP.NET Core</h3>
<p>I defined IMapperSession interface that follows semantics of DbContext from Entity Framework Core. It’s similar but more general. We can use it with NHibernate, Entity Framework Core, Dapper, etc.</p>
<p><pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">interface</span>&nbsp;<span style="color: rgb(43, 145, 175);">IMapperSession</span><br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">void</span>&nbsp;<span style="color: rgb(116, 83, 31);">BeginTransaction</span>();<br>&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">Task</span>&nbsp;<span style="color: rgb(116, 83, 31);">Commit</span>();<br>&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">Task</span>&nbsp;<span style="color: rgb(116, 83, 31);">Rollback</span>();<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">void</span>&nbsp;<span style="color: rgb(116, 83, 31);">CloseTransaction</span>();<br>&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">Task</span>&nbsp;<span style="color: rgb(116, 83, 31);">Save</span>(<span style="color: rgb(43, 145, 175);">Book</span>&nbsp;<span style="color: rgb(31, 55, 127);">entity</span>);<br>&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">Task</span>&nbsp;<span style="color: rgb(116, 83, 31);">Delete</span>(<span style="color: rgb(43, 145, 175);">Book</span>&nbsp;<span style="color: rgb(31, 55, 127);">entity</span>);<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">IQueryable</span>&lt;<span style="color: rgb(43, 145, 175);">Book</span>&gt; Books { <span style="color: blue;">get</span>; }<br>}</pre>
<p>I also implemented this interface for NHibernate. Here’s my demo code that is short and not very fool-proof.</p>
<p><pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">class</span>&nbsp;<span style="color: rgb(43, 145, 175);">NHibernateMapperSession</span> : <span style="color: rgb(43, 145, 175);">IMapperSession</span><br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">private</span>&nbsp;<span style="color: blue;">readonly</span>&nbsp;<span style="color: rgb(43, 145, 175);">ISession</span> _session;<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">private</span>&nbsp;<span style="color: rgb(43, 145, 175);">ITransaction</span> _transaction;<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">NHibernateMapperSession</span>(<span style="color: rgb(43, 145, 175);">ISession</span>&nbsp;<span style="color: rgb(31, 55, 127);">session</span>)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _session = <span style="color: rgb(31, 55, 127);">session</span>;<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">IQueryable</span>&lt;<span style="color: rgb(43, 145, 175);">Book</span>&gt; Books =&gt; _session.<span style="color: rgb(116, 83, 31);">Query</span>&lt;<span style="color: rgb(43, 145, 175);">Book</span>&gt;();<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">void</span>&nbsp;<span style="color: rgb(116, 83, 31);">BeginTransaction</span>()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _transaction = _session.<span style="color: rgb(116, 83, 31);">BeginTransaction</span>();<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">async</span>&nbsp;<span style="color: rgb(43, 145, 175);">Task</span>&nbsp;<span style="color: rgb(116, 83, 31);">Commit</span>()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">await</span> _transaction.<span style="color: rgb(116, 83, 31);">CommitAsync</span>();<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">async</span>&nbsp;<span style="color: rgb(43, 145, 175);">Task</span>&nbsp;<span style="color: rgb(116, 83, 31);">Rollback</span>()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">await</span> _transaction.<span style="color: rgb(116, 83, 31);">RollbackAsync</span>();<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">void</span>&nbsp;<span style="color: rgb(116, 83, 31);">CloseTransaction</span>()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">if</span>(_transaction != <span style="color: blue;">null</span>)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _transaction.<span style="color: rgb(116, 83, 31);">Dispose</span>();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _transaction = <span style="color: blue;">null</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">async</span>&nbsp;<span style="color: rgb(43, 145, 175);">Task</span>&nbsp;<span style="color: rgb(116, 83, 31);">Save</span>(<span style="color: rgb(43, 145, 175);">Book</span>&nbsp;<span style="color: rgb(31, 55, 127);">entity</span>)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">await</span> _session.<span style="color: rgb(116, 83, 31);">SaveOrUpdateAsync</span>(<span style="color: rgb(31, 55, 127);">entity</span>);<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">async</span>&nbsp;<span style="color: rgb(43, 145, 175);">Task</span>&nbsp;<span style="color: rgb(116, 83, 31);">Delete</span>(<span style="color: rgb(43, 145, 175);">Book</span>&nbsp;<span style="color: rgb(31, 55, 127);">entity</span>)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">await</span> _session.<span style="color: rgb(116, 83, 31);">DeleteAsync</span>(<span style="color: rgb(31, 55, 127);">entity</span>);<br>&nbsp;&nbsp;&nbsp; }<br>}</pre>
<p>I also provided solution for adding NHibernate to services collection in application Startup class.</p>
<p><pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">void</span>&nbsp;<span style="color: rgb(116, 83, 31);">ConfigureServices</span>(<span style="color: rgb(43, 145, 175);">IServiceCollection</span>&nbsp;<span style="color: rgb(31, 55, 127);">services</span>)<br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">connStr</span> = Configuration.<span style="color: rgb(116, 83, 31);">GetConnectionString</span>(<span style="color: rgb(163, 21, 21);">"DefaultConnection"</span>);<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">services</span>.<span style="color: rgb(116, 83, 31);">AddNHibernate</span>(<span style="color: rgb(31, 55, 127);">connStr</span>);<br>&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">services</span>.<span style="color: rgb(116, 83, 31);">AddControllersWithViews</span>();<br>}</pre>
<blockquote>
<p><strong>Not excellent but works!</strong> It would be more polite and perfect to use options approach for getting NHibernate settings from application configuration to AddNHibernate() extension method. I don’t focus in it here but leave it as a topic for one of my future posts about NHibernate.</p>
</blockquote>
<p>Here is AddNHibernate() extension method from my previous post.</p>
<p><pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">static</span>&nbsp;<span style="color: blue;">class</span>&nbsp;<span style="color: rgb(43, 145, 175);">NHibernateExtensions</span><br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">static</span>&nbsp;<span style="color: rgb(43, 145, 175);">IServiceCollection</span>&nbsp;<span style="color: rgb(116, 83, 31);">AddNHibernate</span>(<span style="color: blue;">this</span>&nbsp;<span style="color: rgb(43, 145, 175);">IServiceCollection</span>&nbsp;<span style="color: rgb(31, 55, 127);">services</span>, <span style="color: blue;">string</span>&nbsp;<span style="color: rgb(31, 55, 127);">connectionString</span>)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">mapper</span> = <span style="color: blue;">new</span>&nbsp;<span style="color: rgb(43, 145, 175);">ModelMapper</span>();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">mapper</span>.<span style="color: rgb(116, 83, 31);">AddMappings</span>(<span style="color: blue;">typeof</span>(<span style="color: rgb(43, 145, 175);">NHibernateExtensions</span>).Assembly.ExportedTypes);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">HbmMapping</span>&nbsp;<span style="color: rgb(31, 55, 127);">domainMapping</span> = <span style="color: rgb(31, 55, 127);">mapper</span>.<span style="color: rgb(116, 83, 31);">CompileMappingForAllExplicitlyAddedEntities</span>();<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">configuration</span> = <span style="color: blue;">new</span>&nbsp;<span style="color: rgb(43, 145, 175);">Configuration</span>();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">configuration</span>.<span style="color: rgb(116, 83, 31);">DataBaseIntegration</span>(<span style="color: rgb(31, 55, 127);">c</span> =&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">c</span>.<span style="color: rgb(116, 83, 31);">Dialect</span>&lt;<span style="color: rgb(43, 145, 175);">MsSql2012Dialect</span>&gt;();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">c</span>.ConnectionString = <span style="color: rgb(31, 55, 127);">connectionString</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">c</span>.KeywordsAutoImport = <span style="color: rgb(43, 145, 175);">Hbm2DDLKeyWords</span>.AutoQuote;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">c</span>.SchemaAction = <span style="color: rgb(43, 145, 175);">SchemaAutoAction</span>.Validate;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">c</span>.LogFormattedSql = <span style="color: blue;">true</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; });<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">configuration</span>.<span style="color: rgb(116, 83, 31);">AddMapping</span>(<span style="color: rgb(31, 55, 127);">domainMapping</span>);<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">sessionFactory</span> = <span style="color: rgb(31, 55, 127);">configuration</span>.<span style="color: rgb(116, 83, 31);">BuildSessionFactory</span>();<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">services</span>.<span style="color: rgb(116, 83, 31);">AddSingleton</span>(<span style="color: rgb(31, 55, 127);">sessionFactory</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">services</span>.<span style="color: rgb(116, 83, 31);">AddScoped</span>(<span style="color: rgb(31, 55, 127);">factory</span> =&gt; <span style="color: rgb(31, 55, 127);">sessionFactory</span>.<span style="color: rgb(116, 83, 31);">OpenSession</span>());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">services</span>.<span style="color: rgb(116, 83, 31);">AddScoped</span>&lt;<span style="color: rgb(43, 145, 175);">IMapperSession</span>, <span style="color: rgb(43, 145, 175);">NHibernateMapperSession</span>&gt;();<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">return</span>&nbsp;<span style="color: rgb(31, 55, 127);">services</span>;<br>&nbsp;&nbsp;&nbsp; }<br>}</pre>
<p>There’s actually no SQL logging when this solution is used.</p>
<h3>Logging SQL to debug window</h3>
<p>NHibernate sessions may have interceptor that give us access to some internals of NHibernate query execution. Bad thing is there can be only one interceptor set for NHibernate session. If we have more things to do through interceptor then we have to add code to our existing interceptor. We can use custom interceptor to log SQL.</p>
<p>My previous blog post about <a title="Logging NHibernate SQL commands to debug" href="https://gunnarpeipman.com/nhibernate-log-sql-debug-window/">SQL logging in NHibernate</a> demonstrated simple SQL logging interceptor that logged SQL to debug window.</p>
<p><pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">class</span>&nbsp;<span style="color: rgb(43, 145, 175);">SqlDebugOutputInterceptor</span> : <span style="color: rgb(43, 145, 175);">EmptyInterceptor</span><br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">override</span>&nbsp;<span style="color: rgb(43, 145, 175);">SqlString</span>&nbsp;<span style="color: rgb(116, 83, 31);">OnPrepareStatement</span>(<span style="color: rgb(43, 145, 175);">SqlString</span>&nbsp;<span style="color: rgb(31, 55, 127);">sql</span>)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">Debug</span>.<span style="color: rgb(116, 83, 31);">Write</span>(<span style="color: rgb(163, 21, 21);">"NHibernate: "</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">Debug</span>.<span style="color: rgb(116, 83, 31);">WriteLine</span>(<span style="color: rgb(31, 55, 127);">sql</span>);<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">return</span>&nbsp;<span style="color: blue;">base</span>.<span style="color: rgb(116, 83, 31);">OnPrepareStatement</span>(<span style="color: rgb(31, 55, 127);">sql</span>);<br>&nbsp;&nbsp;&nbsp; }<br>}</pre>
<p>Although NHibernate has IInterceptor interface defined it’s better to use EmptyInterceptor as base class so we don’t have to implement methods we don’t need.</p>
<h3>Logging SQL to ASP.NET Core logger</h3>
<p>We can use logger interceptor above to log SQL also to ASP.NET Core logger. For this we have to extend interceptor a little bit. Interceptor needs instance of ASP.NET Core logger and we will provide it through dependency injection. I also rename this interceptor to SqlLoggingInterceptor. Here’s the code.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">class</span>&nbsp;<span style="color: rgb(43, 145, 175);">SqlLoggingInterceptor</span> : <span style="color: rgb(43, 145, 175);">EmptyInterceptor</span><br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">private</span>&nbsp;<span style="color: blue;">readonly</span>&nbsp;<span style="color: rgb(43, 145, 175);">ILogger</span>&lt;<span style="color: rgb(43, 145, 175);">IMapperSession</span>&gt; _logger;<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">SqlLoggingInterceptor</span>(<span style="color: rgb(43, 145, 175);">ILogger</span>&lt;<span style="color: rgb(43, 145, 175);">IMapperSession</span>&gt; logger)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _logger = logger;<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">override</span>&nbsp;<span style="color: rgb(43, 145, 175);">SqlString</span> OnPrepareStatement(<span style="color: rgb(43, 145, 175);">SqlString</span> sql)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">if</span> (_logger != <span style="color: blue;">null</span>)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _logger.LogDebug(sql.ToString());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">return</span>&nbsp;<span style="color: blue;">base</span>.OnPrepareStatement(sql);<br>&nbsp;&nbsp;&nbsp; }<br>}</pre>
<p>In ConfigureServices() method of Startup class we can add our interceptor to dependency injection like shown here.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: gray;">#if</span> (DEBUG)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; services.AddScoped&lt;<span style="color: rgb(43, 145, 175);">IInterceptor</span>, <span style="color: rgb(43, 145, 175);">SqlLoggingInterceptor</span>&gt;();<br><span style="color: gray;">#endif</span></pre>
<p>If application is released then SQL queries will not be logged.</p>
<p>Now we have to use SqlLoggingInterceptor in AddNHibernate() extension method. We can use services collection when creating new ISession to get interceptor if it is available. Here is the dependencies block from AddNHibernate() extension method.</p>
<pre style="background: white; color: black; font-family: consolas;">services.AddSingleton(sessionFactory);<br>services.AddScoped(serviceProvider =&gt; <br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span> interceptor = serviceProvider.GetService&lt;<span style="color: rgb(43, 145, 175);">IInterceptor</span>&gt;();<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">return</span> sessionFactory.OpenSession()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .SessionWithOptions()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Interceptor(interceptor)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .OpenSession();<br>});<br>services.AddScoped&lt;<span style="color: rgb(43, 145, 175);">IMapperSession</span>, <span style="color: rgb(43, 145, 175);">NHibernateMapperSession</span>&gt;();</pre>
<p>All log providers that log debug level messages will get generated SQL when it is written to log by interceptor.</p>
<blockquote>
<p><strong>NB!</strong> This solution doesn’t work with stateless sessions as stateless sessions doesn’t support interceptors. For stateless sessions we need some other approach and I will cover this topic in near future here in this blog.</p>
</blockquote>
<h3>What to do with stateless sessions?</h3>
<p>Stateless sessions in NHibernate are great for reading data but they don’t support interceptors. It’s possible to hook to underlying connection and monitor it but it means building up a custom solution that may turn to be complex one. </p>
<p>If you are in hurry then the easiest thing to do is to offer few bucks and use <a title="Azure Monitor - Full observability into your applications, infrastructure, and network" href="https://azure.microsoft.com/en-us/services/monitor/">Azure Monitor</a>/Application Insights service. It is able to monitor external dependencies automatically and one of those dependencies is SQL database. You can run your ASP.NET Core application on your dev box and see SQL logs in Azure Portal. </p>
<h3>Wrapping up</h3>
<p>Using custom interceptor to log SQL queries in NHibernate to ASP.NET Core logger is simple but a little bit limited. It works with ISession that is stateful but not with IStatelessSession that doesn’t have state and therefore doesn’t support interceptors. As long as stateful sessions are used the logging interceptor logs all SQL that NHibernate sends out. It doesn’t matter what querying API is used – is it ICriteria, QueryOver or LINQ – all SQL will be written to logs.</p>
<p>The post <a href="https://gunnarpeipman.com/aspnet-core-nhibernate-log-sql/">How to log NHibernate SQL to ASP.NET Core loggers</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gunnarpeipman.com/aspnet-core-nhibernate-log-sql/feed/</wfw:commentRss>
			<slash:comments>56</slash:comments>
		
		
			</item>
		<item>
		<title>Using Structuremap in legacy ASP.NET MVC applications</title>
		<link>https://gunnarpeipman.com/aspnet-mvc-structuremap-dependency-injection/</link>
					<comments>https://gunnarpeipman.com/aspnet-mvc-structuremap-dependency-injection/#comments</comments>
		
		<dc:creator><![CDATA[Gunnar Peipman]]></dc:creator>
		<pubDate>Tue, 18 Aug 2020 06:23:01 +0000</pubDate>
				<category><![CDATA[Architecture/Design/Patterns]]></category>
		<category><![CDATA[ASP.NET]]></category>
		<guid isPermaLink="false">https://gunnarpeipman.com/?p=6191</guid>

					<description><![CDATA[<p>Dependency Injection (DI) was also supported by classic ASP.NET MVC but there was no framework-level dependency injection like in ASP.NET Core. In this blog post I will show how to use Structuremap for dependency injection in ASP.NET MVC applications and how to resolve dependencies using built-in components in classes that doesn’t support dependency injection.</p>
<p>The post <a href="https://gunnarpeipman.com/aspnet-mvc-structuremap-dependency-injection/">Using Structuremap in legacy ASP.NET MVC applications</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p><a title="Dependency injection @ Wikipedia" href="https://en.wikipedia.org/wiki/Dependency_injection">Dependency Injection</a> (DI) was also supported by classic ASP.NET MVC but there was no <a title="ASP.NET Core dependency injection" href="https://gunnarpeipman.com/aspnet-core-dependency-injection/">framework-level dependency injection</a> like in ASP.NET Core. In this blog post I will show how to use <a title="Structuremap" href="https://structuremap.github.io/">Structuremap</a> for dependency injection in ASP.NET MVC applications and how to resolve dependencies using built-in components in classes that doesn’t support dependency injection.</p>
<p><span id="more-6191"></span></p>
<blockquote>
<p><strong>Legacy warning!</strong> The code here and solutions are for classic ASP.NET MVC. If you are working on legacy application written on it and you need to introduce dependency injection there or you need to get rid of ObjectFactory class of old Structuremap then this post is for you. In this post I stay in context of legacy app I’m working on and I don’t want to introduce any big changes to code base.</p>
</blockquote>
<p>As long as we work in Application class or controllers things are quiet easy. At application class we create DI container, configure it and then set up controller factory that we introduce to ASP.NET MVC. </p>
<p>But there are ASP.NET and ASP.NET MVC components that doesn’t support dependency injection. Some examples:</p>
<ul>
<li>layout pages and views</li>
<li>membership and roles providers</li>
<li>controller attributes</li>
</ul>
<p>There’s no straightforward way to make those things use dependency injection like we want. There was ObjectFactory class in Structuremap but it is deprecated. As a last option we can use Service Locator pattern (once pattern but now anti-pattern). It provides us with static instance that resolves dependencies for us.</p>
<p>But let’s get to dependency injection step by step.</p>
<h3>Using Structuremap for dependency injection</h3>
<p>I am long time user of Structuremap. It is DI/IoC container that supports assembly scanning and dependency definition registries. Registries are simple classes where containers are configured. </p>
<p>Here’s the primitive example of Structuremap registry.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">class</span>&nbsp;<span style="color: rgb(43, 145, 175);">MyRegistry</span> : <span style="color: rgb(43, 145, 175);">Registry</span><br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">MyRegistry</span>()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; For&lt;<span style="color: rgb(43, 145, 175);">IDataMapper</span>&gt;().Use&lt;<span style="color: rgb(43, 145, 175);">NHibernateMapperSession</span>&gt;()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .LifecycleIs&lt;<span style="color: rgb(43, 145, 175);">ThreadLocalStorageLifecycle</span>&gt;();<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; For&lt;<span style="color: rgb(43, 145, 175);">ILogger</span>&gt;().Use&lt;<span style="color: rgb(43, 145, 175);">NLogWrapper</span>&gt;()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .LifecycleIs&lt;<span style="color: rgb(43, 145, 175);">ThreadLocalStorageLifecycle</span>&gt;();<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; For&lt;<span style="color: rgb(43, 145, 175);">IInvoiceGenerator</span>&gt;().Use&lt;<span style="color: rgb(43, 145, 175);">InvoiceGenerator</span>&gt;()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .LifecycleIs&lt;<span style="color: rgb(43, 145, 175);">ThreadLocalStorageLifecycle</span>&gt;();<br>&nbsp;&nbsp;&nbsp; }<br>}</pre>
<p>And here’s how Structuremap containers are configured (scanning is also possible).</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">var</span> container = <span style="color: blue;">new</span>&nbsp;<span style="color: rgb(43, 145, 175);">Container</span>(x =&gt;<br>{<br>&nbsp;&nbsp;&nbsp; x.AddRegistry&lt;<span style="color: rgb(43, 145, 175);">MyRegistry</span>&gt;();<br>&nbsp;&nbsp;&nbsp; x.AddRegistry&lt;<span style="color: rgb(43, 145, 175);">SomeOtherRegistry</span>&gt;();<br>});</pre>
<p>If instance is needed then it’s easy to get it from container.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">var</span> logger = container.GetInstance&lt;<span style="color: rgb(43, 145, 175);">ILogger</span>&gt;();<br></pre>
<p>It’s all nice but it’s not enough to get dependency injection to classic ASP.NET MVC. We need some more pieces.</p>
<h3>Building controller factory</h3>
<p>Controller factory is MVC component that builds controller instances when framework needs one. We need <a title="Structuremap controller factory" href="https://gunnarpeipman.com/asp-net-how-to-avoid-argumentnullexception-in-structuremap-controller-factory/">custom controller factory for Structuremap</a> to get dependencies resolved and controller instance built when request comes in.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">class</span>&nbsp;<span style="color: rgb(43, 145, 175);">StructuremapControllerFactory</span> : <span style="color: rgb(43, 145, 175);">DefaultControllerFactory</span><br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">private</span>&nbsp;<span style="color: blue;">readonly</span>&nbsp;<span style="color: rgb(43, 145, 175);">Container</span> _container;<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">StructuremapControllerFactory</span>(<span style="color: rgb(43, 145, 175);">Container</span> container)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _container = container;<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">protected</span>&nbsp;<span style="color: blue;">override</span>&nbsp;<span style="color: rgb(43, 145, 175);">IController</span> GetControllerInstance(<span style="color: rgb(43, 145, 175);">RequestContext</span> requestContext, <span style="color: rgb(43, 145, 175);">Type</span> controllerType)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">if</span> (controllerType == <span style="color: blue;">null</span>)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">return</span>&nbsp;<span style="color: blue;">null</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">return</span> _container.GetInstance(controllerType) <span style="color: blue;">as</span>&nbsp;<span style="color: rgb(43, 145, 175);">Controller</span>;<br>&nbsp;&nbsp;&nbsp; }<br>}</pre>
<p>We have to introduce out controller factory to MVC when web application starts.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">var</span> factory = <span style="color: blue;">new</span>&nbsp;<span style="color: rgb(43, 145, 175);">StructuremapControllerFactory</span>(container);<br><span style="color: rgb(43, 145, 175);">ControllerBuilder</span>.Current.SetControllerFactory(factory);&nbsp;&nbsp; </pre>
<p>Notice that previously initialized Structuremap container is provided to controller factory.</p>
<p>Now we can write controllers like we are doing it right now in ASP.NET Core MVC using framework-level dependency injection. </p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">class</span>&nbsp;<span style="color: rgb(43, 145, 175);">MyDemoController</span> : <span style="color: rgb(43, 145, 175);">Controller</span><br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">private</span>&nbsp;<span style="color: blue;">readonly</span>&nbsp;<span style="color: rgb(43, 145, 175);">ILogger</span> _logger;<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">private</span>&nbsp;<span style="color: blue;">readonly</span>&nbsp;<span style="color: rgb(43, 145, 175);">IAlertService</span> _alertService;<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">MyDemoController</span>(<span style="color: rgb(43, 145, 175);">ILogger</span> logger, <span style="color: rgb(43, 145, 175);">IAlertService</span> alertService)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _logger = logger;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _alertService = alertService;<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: green;">// Controller actions follow</span><br>}</pre>
<p>But this not the end of the show – we have some famous components that doesn’t go through dependency injection.</p>
<h3>Using built-in service locator</h3>
<p>Now let’s focus on our old friends like role provider, membership providers and others that don’t support dependency injection. For these components we have to go with built-in service locator.</p>
<p>[See võiks ehk sinine olla?] Service locator is static class we can use everywhere in our code to resolve dependencies. I don’t like this pattern much because resolving of dependencies happens inside class that needs these and therefore class has one more responsibility. </p>
<p>ASP.NET MVC provides us with DependencyResolver class. By it&#8217;s nature it is typical service locator. Here’s how we can use it to return list of roles in classic ASP.NET roles provider.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">class</span>&nbsp;<span style="color: rgb(43, 145, 175);">MyRoleProvider</span> : <span style="color: rgb(43, 145, 175);">RoleProvider</span><br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: green;">// ...</span><br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">override</span>&nbsp;<span style="color: blue;">string</span>[] GetAllRoles()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span> repo = <span style="color: rgb(43, 145, 175);">DependencyResolver</span>.Current.GetService&lt;<span style="color: rgb(43, 145, 175);">IRoleRepository</span>&gt;();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span> roles = <span style="color: blue;">from</span> r <span style="color: blue;">in</span> repo.ListAll()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">select</span> r.Name;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">return</span> roles.ToArray();<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: green;">// ...</span><br>}</pre>
<p>No constructor injection, no property injection – just a primitive call to static scope. </p>
<p>Getting DependencyResolver work with Structuremap is a little bit tricky. We have to write Structuremap based dependency resolver that DependencyResolver can internally use when detecting instances. We don’t have to invent the wheel as there’s excellent blog post <a title="Configuring MVC 4 with StructureMap" href="http://biasecurities.com/2012/06/configuring-mvc-4-with-structuremap/">Configuring MVC 4 with StructureMap</a> by <a title="Bia Securities blog" href="http://biasecurities.com/">Bia Securities blog</a>. We need StructureMapDependencyResolver and StructureMapDependencyScope classes.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">class</span>&nbsp;<span style="color: rgb(43, 145, 175);">StructureMapDependencyResolver</span> : <span style="color: rgb(43, 145, 175);">StructureMapDependencyScope</span>, <span style="color: rgb(43, 145, 175);">IDependencyResolver</span><br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">StructureMapDependencyResolver</span>(<span style="color: rgb(43, 145, 175);">IContainer</span> container) : <span style="color: blue;">base</span>(container)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">IDependencyScope</span> BeginScope()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span> child = Container.GetNestedContainer();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">return</span>&nbsp;<span style="color: blue;">new</span>&nbsp;<span style="color: rgb(43, 145, 175);">StructureMapDependencyResolver</span>(child);<br>&nbsp;&nbsp;&nbsp; }<br>}<br> <br><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">class</span>&nbsp;<span style="color: rgb(43, 145, 175);">StructureMapDependencyScope</span> : <span style="color: rgb(43, 145, 175);">ServiceLocatorImplBase</span>, <span style="color: rgb(43, 145, 175);">IDependencyScope</span><br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">protected</span>&nbsp;<span style="color: blue;">readonly</span>&nbsp;<span style="color: rgb(43, 145, 175);">IContainer</span> Container;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">StructureMapDependencyScope</span>(<span style="color: rgb(43, 145, 175);">IContainer</span> container)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">if</span> (container == <span style="color: blue;">null</span>)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">throw</span>&nbsp;<span style="color: blue;">new</span>&nbsp;<span style="color: rgb(43, 145, 175);">ArgumentNullException</span>(<span style="color: blue;">nameof</span>(container));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Container = container;<br>&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">override</span>&nbsp;<span style="color: blue;">object</span> GetService(<span style="color: rgb(43, 145, 175);">Type</span> serviceType)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">if</span> (serviceType == <span style="color: blue;">null</span>)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">return</span>&nbsp;<span style="color: blue;">null</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">return</span> serviceType.IsAbstract || serviceType.IsInterface<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ? Container.TryGetInstance(serviceType)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : Container.GetInstance(serviceType);<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">IEnumerable</span>&lt;<span style="color: blue;">object</span>&gt; GetServices(<span style="color: rgb(43, 145, 175);">Type</span> serviceType)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">return</span> Container.GetAllInstances(serviceType).Cast&lt;<span style="color: blue;">object</span>&gt;();<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">protected</span>&nbsp;<span style="color: blue;">override</span>&nbsp;<span style="color: rgb(43, 145, 175);">IEnumerable</span>&lt;<span style="color: blue;">object</span>&gt; DoGetAllInstances(<span style="color: rgb(43, 145, 175);">Type</span> serviceType)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">return</span> Container.GetAllInstances(serviceType).Cast&lt;<span style="color: blue;">object</span>&gt;();<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">protected</span>&nbsp;<span style="color: blue;">override</span>&nbsp;<span style="color: blue;">object</span> DoGetInstance(<span style="color: rgb(43, 145, 175);">Type</span> serviceType, <span style="color: blue;">string</span> key)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">if</span> (<span style="color: blue;">string</span>.IsNullOrEmpty(key))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">return</span> serviceType.IsAbstract || serviceType.IsInterface<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ? Container.TryGetInstance(serviceType)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : Container.GetInstance(serviceType);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">return</span> Container.GetInstance(serviceType, key);<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">private</span>&nbsp;<span style="color: blue;">bool</span> disposedValue;<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">protected</span>&nbsp;<span style="color: blue;">virtual</span>&nbsp;<span style="color: blue;">void</span> Dispose(<span style="color: blue;">bool</span> disposing)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">if</span> (!disposedValue)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">if</span> (disposing)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">if</span>(Container != <span style="color: blue;">null</span>)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Container.Dispose();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; disposedValue = <span style="color: blue;">true</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">void</span> Dispose()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Dispose(disposing: <span style="color: blue;">true</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">GC</span>.SuppressFinalize(<span style="color: blue;">this</span>);<br>&nbsp;&nbsp;&nbsp; }<br>}</pre>
<p>Finally we have to introduce our custom dependency resolver to ASP.NET MVC. We will do it in Application_Start method of Application class.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">var</span> mvcDependencyResolver = <span style="color: blue;">new</span>&nbsp;<span style="color: rgb(43, 145, 175);">StructureMapDependencyResolver</span>(_container);<br><span style="color: rgb(43, 145, 175);">DependencyResolver</span>.SetResolver(mvcDependencyResolver);<br> <br><span style="color: blue;">var</span> factory = <span style="color: blue;">new</span>&nbsp;<span style="color: rgb(43, 145, 175);">StructuremapControllerFactory</span>(_container);<br><span style="color: rgb(43, 145, 175);">ControllerBuilder</span>.Current.SetControllerFactory(factory); </pre>
<p>Now we have dependencies available also in components that doesn’t support dependency injection. </p>
<h3>Conclusion</h3>
<p>Although I don’t like service locator much it’s sometimes the only option in classic ASP.NET MVC to resolve dependencies in components that doesn’t support dependency injection. Good thing is that we can still use DI/IoC container we like and some containers come with special libraries or extension methods that attach them automatically to ASP.NET MVC components. Making sure that dependency injection is done properly is mandatory step before moving system over to ASP.NET Core.</p>
<p>The post <a href="https://gunnarpeipman.com/aspnet-mvc-structuremap-dependency-injection/">Using Structuremap in legacy ASP.NET MVC applications</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gunnarpeipman.com/aspnet-mvc-structuremap-dependency-injection/feed/</wfw:commentRss>
			<slash:comments>66</slash:comments>
		
		
			</item>
		<item>
		<title>Building ASP.NET Core applications on Visual Studio Codespaces and Visual Studio Code</title>
		<link>https://gunnarpeipman.com/aspnet-core-visual-studio-codespaces/</link>
					<comments>https://gunnarpeipman.com/aspnet-core-visual-studio-codespaces/#comments</comments>
		
		<dc:creator><![CDATA[Gunnar Peipman]]></dc:creator>
		<pubDate>Fri, 07 Aug 2020 07:20:08 +0000</pubDate>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[Azure]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Visual Studio]]></category>
		<guid isPermaLink="false">https://gunnarpeipman.com/?p=6189</guid>

					<description><![CDATA[<p>On the search for running development environments on cloud I stumbled upon service calles Visual Studio Codespaces. It’s nice service that moves development and debugging workloads to cloud and it makes it possible to use lightweight machines like tablets and hybrids for development. Here’s my overview of how to build ASP.NET Core web applications on codespaces and Visual Studio Code.</p>
<p>The post <a href="https://gunnarpeipman.com/aspnet-core-visual-studio-codespaces/">Building ASP.NET Core applications on Visual Studio Codespaces and Visual Studio Code</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>On the search for running development environments on cloud I stumbled upon service calles Visual Studio Codespaces. It’s nice service that moves development and debugging workloads to cloud and it makes it possible to use lightweight machines like tablets and hybrids for development. Here’s my overview of how to build ASP.NET Core web applications on codespaces and Visual Studio Code.</p>
<p><span id="more-6189"></span></p>
<p>Visual Studio Codespaces (previously known as Visual Studio Online) is online IDE for building and running applications on cloud. It seems to be excellent choice for those who want development environment hosted in cloud. It’s accessible over internet and it doesn’t need powerful machine. </p>
<p>On tooling side there are three options:</p>
<ol>
<li><strong>Online editor</strong> – imitation of Visual Studio Code running in browser</li>
<li><strong>Visual Studio</strong> – there’s experimental support for codespaces in Visual Studio 2019</li>
<li><strong>Visual Studio Code</strong> – there’s extension available to work with codespaces</li>
</ol>
<p>Although I’m focusing here on Visual Studio Code as it is cross-platform and doesn’t have high demands on hardware, I still show you how online editor looks like. Maybe some of my readers find it to be enough for development works they do.</p>
<p align="center"><a href="https://static.gunnarpeipman.com/wp-content/uploads/2020/08/visual-studio-codespaces-online-editor.png"><img decoding="async" width="1598" height="758" title="Online editor of Visual Studio Codespaces" style="display: inline; background-image: none;" alt="Online editor of Visual Studio Codespaces" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/08/visual-studio-codespaces-online-editor_thumb.png" border="0"></a></p>
<p>I tried to set up Visual Studio Codespaces for building ASP.NET Core web applications using Visual Studio Code on my <a title="Surface Go 2 review" href="https://gunnarpeipman.com/surface-go-2/">Surface Go 2</a>.</p>
<h3>Creating Codespace</h3>
<p>Creating a codespace through browser was not possible. UI found only one Azure subscription for my account and sadly it was one of those where I cannot use any services without confirmation by subscription owner. I didn’t found any option to get rid of this issue.</p>
<p>I managed to create Codespace using Visual Studio Code and it was possible there to select correct Azure subscription, resource group etc. I got few errors but on second attempt my codespace was created successfully. </p>
<p>Here are the steps in glance:</p>
<ol>
<li>Have a Git repository accessible from internet</li>
<li>Create Azure subscription if you don’t have one</li>
<li>Install Visual Studio Code if you don’t have it</li>
<li>Install <a title="Visual Studio Codespaces extension for VS Code" href="https://marketplace.visualstudio.com/items?itemName=MS-vsonline.vsonline">Codespaces</a> and <a title="Azure Account extension for VS Code" href="https://marketplace.visualstudio.com/items?itemName=ms-vscode.azure-account">Azure Account</a> extensions</li>
<li>Open Remote Explorer and click on “Create new Codespace…”</li>
<li>You are asked for the following information:</li>
<ul>
<li>Azure subscription</li>
<li>Resource group name</li>
<li>Region</li>
<li>Codespaces plan name</li>
<li>Default instance type</li>
<li>Source code repository URL</li>
<li>Auto-suspend Setting</li>
</ul>
<li>Visual Studio Code will create codespace and connect to it</li>
<li>Use dotnet new command to create application if your repository is empty</li>
</ol>
<blockquote>
<p><strong>Full guide</strong> to set up codespaces support in Visual Studio Code is provided in Microsoft document <a title="Visual Studio Codespaces VS Code How-to" href="https://docs.microsoft.com/en-us/visualstudio/codespaces/how-to/vscode">Visual Studio Codespaces VS Code How-to</a>.</p>
</blockquote>
<p>If you started with empty repository then you need also .gitignore file. For this you can install <a title=".gitignore Generator extension for VS Code" href="https://marketplace.visualstudio.com/items?itemName=piotrpalarz.vscode-gitignore-generator">.gitignore Generator extension by Piotr Palarz</a>. Open command palette and launch the following command: Generate .gitignore File. .gitignore file is automatically added to root folder of your project.</p>
<p>If everything went well then you should see your new codespace in browser too – there’s new card on Visual Studio Codespaces page.</p>
<p align="center"><a href="https://static.gunnarpeipman.com/wp-content/uploads/2020/08/visual-studio-codespaces-card.png"><img decoding="async" width="658" height="427" title="Codespace card in Visual Studio Codespaces" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="Codespace card in Visual Studio Codespaces" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/08/visual-studio-codespaces-card_thumb.png" border="0"></a></p>
<p>Before getting to ASP.NET Core there few things to configure. </p>
<h3>Configuring codespaces</h3>
<p>Codespaces have two important settings that affect billing:</p>
<ol>
<li><strong>Instance type</strong> – how much resources has the environment that runs your application</li>
<li><strong>Suspend – </strong>how long is the idle time after what codespace is suspended</li>
</ol>
<p>Here is the selection of instance types today (2020-08-07).</p>
<table border="1" cellspacing="0" cellpadding="2">
<tbody>
<tr>
<td valign="top"><strong>Type</strong></td>
<td valign="top"><strong>Resources</strong></td>
<td valign="top"><strong>Hour (€)</strong></td>
<td valign="top"><strong>Month* (€)</strong></td>
</tr>
<tr>
<td valign="top">Basic (Linux)</td>
<td>2 cores,  4 GB RAM</td>
<td valign="top">0.072</td>
<td valign="top">11.52 ~12</td>
<td valign="top"></td>
</tr>
<tr>
<td valign="top">Standard (Linux)</td>
<td valign="top">4 cores, 8 GB RAM</td>
<td valign="top">0.143</td>
<td valign="top">22.88 ~23</td>
</tr>
<tr>
<td valign="top">Premium (Linux)</td>
<td valign="top">8 cores, 16 GB RAM</td>
<td valign="top">0.286</td>
<td valign="top">45.76 ~46</td>
</tr>
</tbody>
</table>
<p>* – Month is defined here as working month or 160 hours. To make calculations easier I rounded monthly numbers up. </p>
<p>Good thing is that resources are provided by Azure environment and we don’t have to care about how hardware is updated over time. </p>
<p><strong>Suspending</strong> is important thing. I know some people who develop mainly on cloud hosted virtual machines and their constant fear was forgetting virtual machine running in the end of the working day. Virtual machine that is running has resources assigned to it and it means that billing is ticking all the time. Currently it is possible to set time of day when virtual machine is automatically shut down. Suspend in Visual Studio Codespaces is similar feature but implemented different way. 30 minutes should be good enbough suspend timeout. If there has been no action for 30 minutes then codespace is suspended and it doesn’t consume resources anymore.</p>
<h3>Building ASP.NET Core applications</h3>
<p>Although I wasn’t yet able to set things up the way I want I was still able to get something done and this something seems right now good enough to build some simpler applications. </p>
<p>It’s possible to use dotnet utility to create projects, add controllers, views etc. Also it’s possible to use Visual Studio Code and create these files from scratch. In both cases it takes some time to get used with it if you are heavy user of Visual Studio. But it’s not a lot of suffer – few hours and things will go smooth.</p>
<p>Here are some issues I ran into:</p>
<ul>
<li>I didn’t found a way to run ASP.NET Core application on debugger through Visual Studio Code. I was able to run my web application through terminal using dotnet run command.</li>
<li>Very often port forwarding is not set up by Visual Studio Code automatically.</li>
</ul>
<p><a href="https://static.gunnarpeipman.com/wp-content/uploads/2020/08/visual-studio-codespaces-aspnet-core-webapp.png"><img decoding="async" width="1026" height="770" title="ASP.NET Core web application running on Visual Studio Codespaces" style="border: 0px currentcolor; border-image: none; margin-right: auto; margin-left: auto; float: none; display: block; background-image: none;" alt="ASP.NET Core web application running on Visual Studio Codespaces" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/08/visual-studio-codespaces-aspnet-core-webapp_thumb.png" border="0"></a></p>
<p><strong>Port forwarding</strong> means that if application you are running on codespace uses ports then these ports are forwarded to your machine where Visual Studio Code runs. For web application it means you can use forwarded port to see web application running in browser on your local machine.</p>
<p>If port forwarding doesn’t work then you can add forwarded ports manually:</p>
<ol>
<li>Go to Remote Explorer in Visual Studio Code</li>
<li>In Codespace details section right click on “Forwarded Ports”</li>
<li>Select “Forward Port”</li>
<li>Write port number (NB! Field for port number is opened in upper part of windows) and press Enter</li>
<li>Repeat this procedure for all ports you want to be forwarded</li>
</ol>
<p>When port forwarding is set up then it’s time to open browser and connect to web application.</p>
<p align="center"><a href="https://static.gunnarpeipman.com/wp-content/uploads/2020/08/visual-studio-codespaces-aspnet-core-browser.png"><img decoding="async" width="715" height="488" title="Opening web application running on Visual Studio Codespaces from local machine" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="Opening web application running on Visual Studio Codespaces from local machine" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/08/visual-studio-codespaces-aspnet-core-browser_thumb.png" border="0"></a></p>
<p>Web application runs on Visual Studio Codespaces and port forwarding makes it available for local machine. Nice!</p>
<h3>Conclusion</h3>
<p>Visual Studio Codespaces is nice service for building applications on cloud hosted service. It’s accessible though browser but those who want can also connect to codespaces using Visual Studio or Visual Studio code. Running applications on cloud means that codespaces can be used also from machines with limited resources like tablets. Port forwarding makes it possible to run web applications on codespaces and use these with browser running on local machine. Although tooling seems a little bit raw it still works. I think it’s time to start experimenting with Visual Studio Codespaces to see how it fits to everyday’s coding life.</p>
<h3>References</h3>
<ul>
<li><a title="Visual Studio Codespaces" href="https://visualstudio.microsoft.com/services/visual-studio-codespaces/">Visual Studio Codespaces</a></li>
<li><a title="Visual Studio Codespaces dashboard" href="https://online.visualstudio.com/environments">Visual Studio Codespaces dashboard</a></li>
<li><a title="Visual Studio Codespaces pricing" href="https://azure.microsoft.com/en-us/pricing/details/visual-studio-online/">Pricing</a></li>
<li><a title="Visual Studio Codespaces documentation" href="https://docs.microsoft.com/en-us/visualstudio/codespaces/overview/what-is-vsonline">Documentation</a></li>
<li></li>
</ul>
<p>The post <a href="https://gunnarpeipman.com/aspnet-core-visual-studio-codespaces/">Building ASP.NET Core applications on Visual Studio Codespaces and Visual Studio Code</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gunnarpeipman.com/aspnet-core-visual-studio-codespaces/feed/</wfw:commentRss>
			<slash:comments>77</slash:comments>
		
		
			</item>
		<item>
		<title>Surface Go 2 review</title>
		<link>https://gunnarpeipman.com/surface-go-2/</link>
					<comments>https://gunnarpeipman.com/surface-go-2/#comments</comments>
		
		<dc:creator><![CDATA[Gunnar Peipman]]></dc:creator>
		<pubDate>Mon, 03 Aug 2020 20:30:02 +0000</pubDate>
				<category><![CDATA[Various]]></category>
		<guid isPermaLink="false">https://gunnarpeipman.com/?p=6171</guid>

					<description><![CDATA[<p>Recently I bought Surface Go 2 tablet with Intel M3 CPU and LTE. Surface Go 2 is hybrid device being either tablet or small laptop. It is lightweight and therefore not the option for resource demanding workloads. Consider it more as an complementary device that is hyper-portable and supports you well if you are moving around. But Surface Go 2 is not yet another tablet – it’s more. Different from competiting offers it is not running limited or mobile edition of operating system but full Windows 10. I found Surface Go 2 to be killer device supporting my daily activities – be it work or private life.</p>
<p>The post <a href="https://gunnarpeipman.com/surface-go-2/">Surface Go 2 review</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p><p>Recently I bought <a title="Surface Go 2" href="https://www.microsoft.com/en-us/p/surface-go-2/8pt3s2vjmdr6?activetab=pivot%3aoverviewtab">Surface Go 2 tablet with Intel M3 CPU and LTE</a>. Surface Go 2 is hybrid device being either tablet or small laptop. It is lightweight and therefore not the option for resource demanding workloads. Consider it more as an complementary device that is hyper-portable and supports you well if you are moving around. But Surface Go 2 is not yet another tablet – it’s more. Different from competiting offers it is not running limited or mobile edition of operating system but full Windows 10. I found Surface Go 2 to be killer device supporting my daily activities – be it work or private life.</p>
<p><span id="more-6171"></span></p>
<h3>Why Surface Go 2?</h3>
<p>I found Surface Go 2 to be excellent device for days when I have to move around and participate in meetings. The device is kind of small but it weights only ~500g. It’s easy to take it out from bag and open it. After logging in by face recognition everything is ready for work or fun.</p>
<p>Don’t expect it to be your next dev box – it just doesn’t have enough resources to carry out these duties although some simpler stuff you can probably do on it. I plan separate blkog post for developers to explain how to write code on Surface Go 2.</p>
<p>There are some things I really like about Surface Go 2. First is the always connected concept.</p>
<blockquote>
<p><strong>Always connected.</strong> With latest microprocessors together with high performance modem technology initiative from Qualcomm and Microsoft offers always on and always connected PCs and devices. In this concept, a laptop or device running on Microsoft operating system works like a Smartphone. Instead of standby mode in the conventional PCs for power management, these devices will be active (connected standby mode) all the time and connected to a wireless network.</p>
<p><a title="What is always on always connected PC" href="https://www.rfpage.com/what-is-always-on-always-connected-pc/">What is always on always connected PC</a>, RF Page</p>
</blockquote>
<p>I open machine, log in and it’s ready for action. I don’t even think about internet connection availability anymore. I just open machine and I’m connected.</p>
<p>Another cool thing is switching between tablet and laptop mode. It’s smooth – just attach keyboard and the machine is like small laptop. Detach keyboard and it’s tablet. As a tablet it is more convenient than Surface Book. Surface Book has bigger screen but it’s not so convenient to keep in hand if you want to chill on sofa and chat with friends.</p>
<blockquote>
<p><strong>Switch to full Windows 10.</strong> By default Surface Go 2 comes with Window 10 S. It means you can only install and run Windows Store applications. You can turn off S-mode and then it will be regular Windows 10 Home edition. You can upgrade it to Windows 10 Pro for few bucks.</p>
</blockquote>
<h3>Participating in meetings</h3>
<p>I’m long time user of OneNote and it plays very well with touch display and Surface Pen. I can write notes, take screenshots, draw on screen etc. I can also tools like Microsoft Whiteboard to illustrate my ideas by making temporary drawings using Surface Pen.</p>
<p>As it’s full Windows I have whole Microsoft Office installed and if needed I can also make presentations using PowerPoint. Nice thing is that OneNote syncs meeting notes automatically to cloud and when I’m later back at my dev box all meeting notes are already there waiting for me.</p>
<p>Of course, Teams and Skype work also very well on Surface Go 2. Front camera is good enough for meetings and picture is very clear. </p>
<h3></h3>
<h3>Office classics</h3>
<p>It’s perhaps the most repeated usage of Surface Go 2 and other similar devices but let’s repeat it over. What I’m doing between meetings? I usually read news, reply to e-mails, have a chat and work with documents, spreadsheets and presentations. This is what I call office classics.</p>
<p>Again small weight and small dimensions make things comfortable for me. I order coffee, open Surface Go 2 and continue with whatever I worked on during previous pause. </p>
<p>The device is always connected, e-mails come and go, documents synchronize to cloud and I don’t even think about if there’s free WiFi available in coffee.</p>
<blockquote>
<p><strong>You need keyboard for work!</strong> Although Windows 10 supports touch experiences it’s still kind of limited and not fully ready for serious work. I bought also keyboard for my Surface Go 2 and it was right decision. If touch featues fail then I connect keyboard to Surface Go 2 and work goes on.</p>
</blockquote>
<p>Word, Excel, PowerPoint, OneNote – main office programs I use – work all fine on Surface Go 2. They can be inconvenient to use with on-screen keyboard because on-screen keyboard takes also some screen space and on 10&#8243; screen every pixel matters. As long as you are using physical keyboard all Office apps work very well.</p>
<blockquote>
<p><strong>Do I need desktop editions?</strong> Not necessarily. If you don’t use any features of Office applications that are only available with desktop editions you can go with online edition of Office. Remember – you are always connected. But if you need to edit Office files in your machine you need desktop edition of Office.</p>
</blockquote>
<h3 align="center"><img decoding="async" width="2155" height="1383" title="Excel Web Application" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="Excel Web Application" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/08/excel-web-app-1.png" border="0"></h3>
<h3>Travelling with Surface Go 2</h3>
<p>I also had one trip where I used Surface Go 2 as trip advisor. Two important things I used on my trip:</p>
<ol>
<li><strong>OneNote</strong> – I prepared notebook with important information about sites and landmarks I planned to visit. One page for each attraction.</li>
<li><strong>Google My Maps</strong> – It’s service to create your own maps based on Google Maps. You can add pinpoints on map, define layers etc. It’s really useful if you need to stay at same city for some days.</li>
</ol>
<p align="center"><img decoding="async" width="1902" height="996" title="Munich attractions in Google My Maps" style="display: inline; background-image: none;" alt="Munich attractions in Google My Maps" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/08/google-mymaps-munich-1.png" border="0"></p>
<p>Before leaving home I opened my OneNote notebook and Google My Maps in Surface Go 2. The machine was ready to support my wanderings. Whenever I need to find out how to go somewhere I can just take Surface Go 2 out from my lightweight backbag, turn it on and check where to go and which way to go. It takes just few seconds on touch screen to find this information out.</p>
<p>OneNote has served me as a travel planner and travel guide for many years. So far, so good. You can find out more about it from my post series <a title="OneNote as personal travel guide" href="https://gunnarpeipman.com/series/onenote-travel-guide/">OneNote as personal travel guide</a>.</p>
<p align="center"><img decoding="async" title="OneNote as personal travel guide" alt="OneNote as personal travel guide" src="https://static.gunnarpeipman.com/wp-content/uploads/2013/07/onenote-sedlec-ossuary_thumb.png"></p>
<p></p>
<blockquote>
<p><strong>Tip for beginner travelers.</strong> Roaming prices can be extremely high and it usually depends on where you are coming from and where are you going. If roaming is expensive (for me when I leave European Union) then I usually buy local SIM card with enough data transfer limits as it comes way cheaper that paying ~10 EUR/MB.</p>
</blockquote>
<p>Of course, you can also vote for offline mode. In this case try out at home if OneNote has all pages downloaded and your maps solution – whatever it is – also works with no internet connection.</p>
<h3>Kids will love this tablet</h3>
<p>Although tablets space is mostly dominated by Apple and Android, there’s no point to underestimate Windows 10 tablets. Although Windows 10 store has not so many games available as competing stores you can still find games they like – some of them are even free.</p>
<p>My kid loves puzzles and Candy Crush games.</p>
<p align="center"><img decoding="async" width="1402" height="877" title="candi-crush-saga" style="display: inline; background-image: none;" alt="candi-crush-saga" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/08/candi-crush-saga-1.jpg" border="0"></p>
<p>But gaming is not everything. There’s actually more.</p>
<p>I bought fast microSD card (128MB) to have some media with me if kid wants to watch cartoons or kids movies. As a metal head who respects the scene I also have some metal videos and songs with me that my kid loves. You can make just copy of media files to have them available offline but if you don’t afraid of making hands dirty with some IT-stuff, then you can also use some media server like <a title="Plex Media Server" href="https://www.plex.tv/">Plex</a>.</p>
<p align="center"><img decoding="async" width="1922" height="1212" title="Kids Movies on Plex Server" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="Kids Movies on Plex Server" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/08/plex-kids-movies.png" border="0"></p>
<p>Kids love cartoons, but it’s passive entertainment. Let’s add some real action too. </p>
<p>It’s time to open my bag again and take out the next miracle – <a title="Surface Pen" href="https://www.microsoft.com/en-us/p/surface-pen/8zl5c82qmg6b">Surface Pen</a>. Again there’s not many programs supporting screen pens but those we have are actually almost perfect. There are Fresh Paint, <a title="Microsoft Whiteboard" href="https://www.microsoft.com/en-us/microsoft-365/microsoft-whiteboard/digital-whiteboard-app">Microsoft Whiteboard</a> and <a title="OneNote" href="https://www.microsoft.com/en-us/microsoft-365/onenote/digital-note-taking-app">OneNote</a> that I mainly use with Surface Pen. But there are also other programs by third-parties you may like.</p>
<p align="center"><img decoding="async" width="3602" height="2402" title="Surface Pen" style="display: inline; background-image: none;" alt="Surface Pen" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/08/surface-pen-onenote-1.jpg" border="0"></p>
<p>Let’s take <a title="Fresh Paint" href="https://www.microsoft.com/en-us/p/fresh-paint/9wzdncrfjb13?activetab=pivot:overviewtab">Fresh Paint</a>. My kid loves this program. It’s like advanced version of Paint targeting touch screens and also Surface Pen. Of course, you can also draw without Surface Pen using fingers.</p>
<p align="center"><img decoding="async" width="1401" height="789" title="Fresh Paint" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="Fresh Paint" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/08/fresh-paint-tiger.jpg" border="0"></p>
<p>It’s easy to use for kids and they usually get started with it fast. Some things to do with kids on Fresh Paint:</p>
<ol>
<li><strong>Draw pictures</strong> – this is what Fresh Paint is created for. It’s a little harder than using paper and pencils but it’s cool. You can dry the paint immediately or undo changes. These are things that doesn’t happen with second in real world.</li>
<li><strong>Color pictures</strong> – there are tons of coloring pictures available at internet for free. You can download the ones your kids like and then import these to Fresh Paint.</li>
<li><strong>Draw together</strong> – my kid loves to draw with me. I have to come out with interesting ideas and then the action can start. Sometimes time flies fast even for me.</li>
<li><strong>Easier to hold and share</strong> – if you save your kids best drawings to OneDrive or some similar cloud storage then the drawings are safely backed up and it’s easy to share those drawings with other family members.</li>
</ol>
<p>There’s more to talk about kids and having fun with computers but let’s stop here as this topic needs separate blog posts.</p>
<h3>Connecting other hardware</h3>
<p>If you need to use other hardware with Surface Go 2 there are three options:</p>
<ol>
<li>Connect it directly to machine (USB-C, headphones)</li>
<li>Use Bluetooth</li>
<li>Use USB-C hub</li>
</ol>
<p>As much as possible I try to go with Bluetooth as it means no additional wires. Imagine wires and wires and wires when trying to work in first class wagon of train. It’s easy to find earphones with bluetooth support these days, Microsoft also sells Surface Mouse with bluetooth support and there are many other peripherals that support it.</p>
<p>But not everything is easy to do over Bluetooth. If I want to watch movies or metal lives at hotel then I want to connect my Surface Go 2 to TV. Often hotels let turn off all wireless features that TV set has. So, here we are… we need some cabling. Also there are peripherals that come only with USB connection. </p>
<p>For USB devices and HDMI screens I bought USB-C hub similar to <a title="Satechi USB-C Slim Multi-Port with Ethernet Adapter" href="https://www.amazon.com/Satechi-USB-C-Multi-Port-Ethernet-Adapter/dp/B083XCLQWP/ref=sr_1_3?dchild=1&amp;keywords=satechi+usb-c+hub+hdmi&amp;qid=1596458230&amp;sr=8-3">Satechi USB-C Slim Multi-Port with Ethernet Adapter</a>.</p>
<p align="center"><img decoding="async" width="1383" height="1500" title="Satechi USB-C Hub" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="Satechi USB-C Hub" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/08/satechi-usb-c-hub-1.jpg" border="0"></p>
<p>You can find also more powerful ones with more different ports. Some hubs come even with LAN cable port. Using USB-C hub I can connect smart card reader to Surface Go 2 and use Estonian ID-card to authenticate myself at official sites or give digital signatures to documents.</p>
<h3>Developing software on Surface Go 2</h3>
<p>As I mentioned before – Surface Go 2 is not your next portable powerhouse machine. It’s still possible to do something and you actually have some options like Remote Desktop to some more powerful machine, using VS Code to code on remote machine or building something smaller on Surface Go 2 with locally installed tooling. Forget about Visual Studio, of course.</p>
<p>For short, the options are:</p>
<ol>
<li>Simple apps can be developed on Surface Go 2 without any remoting</li>
<li>For more complex apps you can remote over SSH to some more powerful dev box running on Azure or in your in-prem environment</li>
<li>If your company allows then you can also have VPN connection to work network and use Remote Desktop to connect to your dev box</li>
</ol>
<p>I don’t stop on development issues longer as I plan another post to introduce developing options on Surface Go 2. </p>
<h3>Should I buy Surface Go 2</h3>
<blockquote>
<p>Before giving my advice I want to emphasize that my review covers <strong>only</strong> Surface Go 2 with Intel M3 CPU and LTE. I don’t have any idea how other Surface Go 2 devices would work for me as I have never used them. So, be warned!</p>
</blockquote>
<p>As a software architect my answer is boring and not useful – it depends. If you can live without it and you don’t miss any of the positive features it has or you don’t want to deal with negative ones then go with what you currently have. You loose absolutely nothing.</p>
<p>If you found some of scenarios here interesting and mandatory to have then, of course, consider buying one tablet. I warn you about one thing – it takes a week to get used with so limited hardware resources and small battery but after a week you should feel like home with this device. For now it’s one month for me to move around with Surface Go 2 and I have only few times missed my main dev machine.</p>
<h3>Where to buy?</h3>
<p>If you have some good local hardware shop near you then you can check there. But you can also order it from some of Amazons across the globe. Here are few links that my biggest reader base can find useful:</p>
<ul>
<li><a title="Surface Go 2 @ Amazon.de" href="https://amzn.to/2BRX3yq">Surface Go 2 @ Amazon.de</a></li>
<li><a title="Surface Go 2 @ Amazon.com (US)" href="https://www.amazon.com/dp/B086QM6KM6/ref=twister_B088B84TN9?_encoding=UTF8&amp;psc=1">Surface Go 2 @ Amazon.com (US)</a></li>
</ul>
<p>The post <a href="https://gunnarpeipman.com/surface-go-2/">Surface Go 2 review</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gunnarpeipman.com/surface-go-2/feed/</wfw:commentRss>
			<slash:comments>72</slash:comments>
		
		
			</item>
		<item>
		<title>IIS Express error: Failed to register URL for site. The process cannot access the file because it is being used by another process.</title>
		<link>https://gunnarpeipman.com/failed-to-register-url-for-site/</link>
					<comments>https://gunnarpeipman.com/failed-to-register-url-for-site/#comments</comments>
		
		<dc:creator><![CDATA[Gunnar Peipman]]></dc:creator>
		<pubDate>Sat, 01 Aug 2020 05:50:11 +0000</pubDate>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[IIS]]></category>
		<guid isPermaLink="false">https://gunnarpeipman.com/?p=6155</guid>

					<description><![CDATA[<p>A little surprise during COVID-19 time coding. I cloned repo to my dev box, opened it in Visual Studio and hit F5. IIS Express starts and browser opens but it shows just error about site to be unreachable. After almost getting grey hair I found out what’s wrong. Here’s the solution.</p>
<p>The post <a href="https://gunnarpeipman.com/failed-to-register-url-for-site/">IIS Express error: Failed to register URL for site. The process cannot access the file because it is being used by another process.</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>A little surprise during COVID-19 time coding. I cloned repo to my dev box, opened it in Visual Studio and hit F5. IIS Express starts and browser opens but it shows just error about site to be unreachable. After almost getting grey hair I found out what’s wrong. Here’s the solution.</p>
<p><span id="more-6155"></span></p>
<p>It wasn’t any of the classic problems. Classic ones have one of these solutions:</p>
<ol>
<li>Open solution in Windows Explorer, close Visual Studio and delete .vs folder.</li>
<li>Close IIS Express. Go to user folder in Windows Explorer and delete IIS Express subfolder.</li>
<li>Open command prompt, type netstat -aof | findstr :&lt;application port here&gt;</li>
</ol>
<p>If you have virtualization components enabled like it is in my dev box then make sure your application doesn’t try to use some reserved port. </p>
<p>Open command prompt and run the following command:</p>
<pre style="background: white; color: black; font-family: consolas;">netsh interface ipv4 show excludedportrange protocol=tcp<br></pre>
<p>On my dev box I got the following long list of port ranges:</p>
<p align="center"><img decoding="async" width="602" height="432" title="Find exluded port ranges on Windows 10" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="Find exluded port ranges on Windows 10" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/08/excluded-port-ranges.png" border="0"></p>
<p>Web application I tried to run was using port 56442 and it fell into one of port exclusion ranges.</p>
<h3>Solution</h3>
<p>Open properties page of your web application and make it use some available port that is not in port exclusion range.</p>
<p align="center"><a href="https://static.gunnarpeipman.com/wp-content/uploads/2020/08/aspnet-set-application-port.png"><img decoding="async" width="1002" height="608" title="Set port for ASP.NET application" style="display: inline; background-image: none;" alt="Set port for ASP.NET application" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/08/aspnet-set-application-port_thumb.png" border="0"></a></p>
<p>After changing port click also on Create Virtual Directory button.</p>
<p>Now you are good to go. No need to restart IIS Express or Visual Studio. Just change port, let IIS Express create new virtual directory and run your application.</p>
<p>The post <a href="https://gunnarpeipman.com/failed-to-register-url-for-site/">IIS Express error: Failed to register URL for site. The process cannot access the file because it is being used by another process.</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gunnarpeipman.com/failed-to-register-url-for-site/feed/</wfw:commentRss>
			<slash:comments>426</slash:comments>
		
		
			</item>
		<item>
		<title>Logging to Notepad window from ASP.NET Core</title>
		<link>https://gunnarpeipman.com/aspnet-core-notepad-logger/</link>
					<comments>https://gunnarpeipman.com/aspnet-core-notepad-logger/#comments</comments>
		
		<dc:creator><![CDATA[Gunnar Peipman]]></dc:creator>
		<pubDate>Fri, 22 May 2020 03:53:31 +0000</pubDate>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[ASP.NET]]></category>
		<guid isPermaLink="false">https://gunnarpeipman.com/?p=6143</guid>

					<description><![CDATA[<p>Something funny to end this week. When checking my Twitter feeds I found a kinky tweet about logging .NET Core messages to Notepad window. Yes, you heard right – .NET Core logger for Notepad. It’s not real, you want to say, but it is. And here’s how it works :)</p>
<p>The post <a href="https://gunnarpeipman.com/aspnet-core-notepad-logger/">Logging to Notepad window from ASP.NET Core</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Something funny to end this week. When checking my Twitter feeds I found a kinky tweet about logging .NET Core messages to Notepad window. Yes, you heard right – .NET Core logger for Notepad. It’s not real, you want to say, but it is. And here’s how it works :)</p>
<p><span id="more-6143"></span></p>
<h3>The story of Notepad.Extensions.Logging</h3>
<p>When checking Twitter I found a <a title="ok so... I implemented this as a full logging provider for .NET  / ASPNET Core." href="https://twitter.com/yaakov_h/status/1263267987928182784">funny tweet</a> by <a title="@yaakov_h @ Twitter" href="https://twitter.com/yaakov_h/">@yaakov_h</a> where he announced NuGet package for .NET Core logger that targets Notepad. He got inspiration for this from <a href="https://twitter.com/steveklabnik/status/1263190719721766918">tweet by @steveklabnik</a>.</p>
<p align="center"><img decoding="async" width="536" height="629" title="notepad.extensions.logging-tweet" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="notepad.extensions.logging-tweet" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/05/notepad.extensions.logging-tweet.png" border="0"></p>
<p>And guess what? Besides <a title="Notepad.Extensions.Logging @ GitHub" href="https://github.com/yaakov-h/Notepad.Extensions.Logging">GitHub repository for Notepad.Extensions.Logging</a> there’s also <a title="Notepad.Extensions.Logging NuGet package" href="https://www.nuget.org/packages/Notepad.Extensions.Logging/1.0.0/">NuGet package available</a>!</p>
<p align="center"><img decoding="async" width="385" height="130" title="notepad.extensions.logging-nuget" style="display: inline; background-image: none;" alt="notepad.extensions.logging-nuget" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/05/notepad.extensions.logging-nuget.png" border="0"></p>
<p>It’s a real deal – version 1.0.0, you see? :)</p>
<h3>Notepad logger in action</h3>
<p>Let’s get hands dirty with this little piece of art. Just create new ASP.NET Core web application and add Notepad.Extensions.Logging NuGet package. After this modify ConfigureServices() method in Startup like in following code fragment.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">void</span> ConfigureServices(<span style="color: rgb(43, 145, 175);">IServiceCollection</span> services)<br>{<br>&nbsp;&nbsp;&nbsp; services.AddControllersWithViews();<br> <br>&nbsp;&nbsp;&nbsp; services.AddLogging(lb =&gt; lb.AddNotepad());<br>}</pre>
<p>To try things out I made my HomeController log some messages.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">class</span>&nbsp;<span style="color: rgb(43, 145, 175);">HomeController</span> : <span style="color: rgb(43, 145, 175);">Controller</span><br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">private</span>&nbsp;<span style="color: blue;">readonly</span>&nbsp;<span style="color: rgb(43, 145, 175);">ILogger</span>&lt;<span style="color: rgb(43, 145, 175);">HomeController</span>&gt; _logger;<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">HomeController</span>(<span style="color: rgb(43, 145, 175);">ILogger</span>&lt;<span style="color: rgb(43, 145, 175);">HomeController</span>&gt; logger)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _logger = logger;<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">IActionResult</span> Index()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _logger.LogInformation(<span style="color: rgb(163, 21, 21);">"Home.Index opened"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">return</span> View();<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">IActionResult</span> Privacy()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _logger.LogInformation(<span style="color: rgb(163, 21, 21);">"Home.Privacy opened"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">return</span> View();<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">override</span>&nbsp;<span style="color: blue;">void</span> OnActionExecuted(<span style="color: rgb(43, 145, 175);">ActionExecutedContext</span> context)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">base</span>.OnActionExecuted(context);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _logger.LogInformation(<span style="color: rgb(163, 21, 21);">"Action executed"</span>);<br>&nbsp;&nbsp;&nbsp; }<br>}</pre>
<p>I didn&#8217;t made it work with NuGet package for some reason. I had to clone <a title="Notepad.Extensions.Logging @ GitHub" href="https://github.com/yaakov-h/Notepad.Extensions.Logging">Notepad.Extensions.Logging repository</a> to my machine and add it as project reference to web application. Then after few runs messages started appear to Notepad. Here&#8217;s the short video I made of this experiment.</p>
<p style="text-align: center"><div style="width: 800px;" class="wp-video"><!--[if lt IE 9]><script>document.createElement('video');</script><![endif]-->
<video class="wp-video-shortcode" id="video-6143-1" width="800" height="450" preload="metadata" controls="controls"><source type="video/mp4" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/05/notepad.extensions.logging.mp4?_=1" /><a href="https://static.gunnarpeipman.com/wp-content/uploads/2020/05/notepad.extensions.logging.mp4">https://static.gunnarpeipman.com/wp-content/uploads/2020/05/notepad.extensions.logging.mp4</a></video></div></p>
<p>So, it works after all! </p>
<h3>Should I really use it?</h3>
<p>Although this solution is funny it may still come handy when debugging something and there are things to dig out from logs frequently. It’s possible to disable all other log targets for debugging and skip logging related disk I/O as communication with Notepad goes directly through memory.</p>
<p>After using Notepad.Logging.Extensions few hours I actually started to like it. It’s weird but feels somehow convenient. Is Notepad the best choice for text editor? Who knows. But it&#8217;s not very hard to extend Notepad.Logging.Extensions to use some more advanced text editor.</p>
<p>Anyway, happy weekend and cheers!</p>
<p>The post <a href="https://gunnarpeipman.com/aspnet-core-notepad-logger/">Logging to Notepad window from ASP.NET Core</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gunnarpeipman.com/aspnet-core-notepad-logger/feed/</wfw:commentRss>
			<slash:comments>62</slash:comments>
		
		<enclosure url="https://static.gunnarpeipman.com/wp-content/uploads/2020/05/notepad.extensions.logging.mp4" length="406646" type="video/mp4" />

			</item>
		<item>
		<title>Introducing Azure Static Web App service</title>
		<link>https://gunnarpeipman.com/azure-static-web-app/</link>
					<comments>https://gunnarpeipman.com/azure-static-web-app/#comments</comments>
		
		<dc:creator><![CDATA[Gunnar Peipman]]></dc:creator>
		<pubDate>Thu, 21 May 2020 04:57:15 +0000</pubDate>
				<category><![CDATA[Azure]]></category>
		<category><![CDATA[JavaScript]]></category>
		<guid isPermaLink="false">https://gunnarpeipman.com/?p=6137</guid>

					<description><![CDATA[<p>During Build 2020 Microsoft announced preview of Azure Static Web App service - app hosting offering for static web applications built on JavaScript. Automatic deployments to production and staging environments are implemented as GitHub integrations. Although currently in public preview this service is easy to set up and getting started. It will probably be one of developers favorite service in near future.</p>
<p>The post <a href="https://gunnarpeipman.com/azure-static-web-app/">Introducing Azure Static Web App service</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>During Build 2020 Microsoft announced preview of Azure Static Web App service &#8211; app hosting offering for static web applications built on JavaScript. Automatic deployments to production and staging environments are implemented as GitHub integrations. Although currently in public preview this service is easy to set up and getting started. It will probably be one of developers favorite service in near future.</p>
<p><span id="more-6137"></span></p>
<h3>What is Static Web App service?</h3>
<p>Static Web App is hosting service for static web applications built on JavaScript. It’s practically Azure App Service for static applications that is easy to set up and use.</p>
<p>Static Web App service is connected to GitHub repository where source code of web application is hosted. Using GitHub actions it builds and publishes static application either to production or staging environment. Production environment is always based on some concrete branch. Staging environment has changing URL and it is based on pull requests. Currently there’s only one active staging environment allowed at time.</p>
<p>Static Web App service works almost like regular App Service integration with Azure DevOps. Maybe bit too general the following image illustrates the new service well.</p>
<p align="center"><img decoding="async" width="1694" height="1004" title="Azure Static Web App service" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="Azure Static Web App service" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/05/azure-static-web-app.png" border="0"></p>
<p>As you may notice then Azure Functions are also supported. There’s one limitation – those functions must be written in JavaScript as this is the only type of functions supported right now.</p>
<h3>Where Static Web App fits on Azure?</h3>
<p>Nice thing is that Static Web App service fills one empty slot in row of app hosting and deploying models on Azure. </p>
<table border="1" cellspacing="0" cellpadding="2">
<tbody>
<tr>
<th valign="top">Service</th>
<th valign="top">Description</th>
</tr>
<tr>
<td valign="top"><a title="Introducing static website hosting for Azure Storage" href="https://gunnarpeipman.com/static-website/">Static Website</a> </td>
<td valign="top">Blob storage based offer for fully static sites.</td>
</tr>
<tr>
<td valign="top"><a title="Static blog with Jekyll, Azure and Azure DevOps" href="https://gunnarpeipman.com/series/jekyll-azure-devops-static-website/">Static Website vs Azure DevOps</a></td>
<td valign="top">Same as above but we can deploy from Azure DevOps</td>
</tr>
<tr>
<td valign="top">Static Web App</td>
<td valign="top"></td>
</tr>
<tr>
<td valign="top">App Service</td>
<td valign="top">Service to host apps with server-side code or binaries</td>
</tr>
<tr>
<td valign="top">App on virtual machines</td>
<td valign="top">Custom virtual machines for app hosting</td>
</tr>
</tbody>
</table>
<p>Those who remember old days on Azure probably want to remind me of compute service. I didn’t put it to table as other services are good replacement for it.</p>
<h3>Setting up Static Web App service</h3>
<p>Before creating service we need GitHub repository to what our service is connected. If you want to try things out then please create one GitHub repository before proceeding further. You will need it at next step already. After creating repository make sure that master branch is published and available.</p>
<p>We can create Static Web App service in Azure portal. At the time of writing this blog post not all Azure regions are supported as the service is in preview.</p>
<p align="center"><img decoding="async" width="742" height="698" title="Creating Static Web App service" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="Creating Static Web App service" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/05/azure-static-web-app-create-step-1.png" border="0"></p>
<p>Notice how we have to specify GitHub repository and branch. This is from where live site deployments are made.</p>
<p>Next step is to configure build parameters for static web application. API location can be left empty if web application doesn’t have Azure Functions.</p>
<p align="center"><img decoding="async" width="742" height="427" title="Creating Static Web App service" style="display: inline; background-image: none;" alt="Creating Static Web App service" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/05/azure-static-web-app-create-step-2.png" border="0"></p>
<p>Tricky thing is app artifact location. This is the folder where application puts distribution files. To talk more in ASP.NET developers language then this is the folder where application is published after build. Make sure you don’t have this folder in repository.</p>
<p>Now we can click Review + create and after few minutes we have Static Web App service set up for us. If everything went well then we will see out Static Web App service running.</p>
<p align="center"><a href="https://static.gunnarpeipman.com/wp-content/uploads/2020/05/azure-static-web-app-overview.png"><img decoding="async" width="1002" height="499" title="azure-static-web-app-overview" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="azure-static-web-app-overview" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/05/azure-static-web-app-overview_thumb.png" border="0"></a></p>
<p>Workflow file points to GitHub actions definition that was created automatically with service. If you need to change build related setting later then this can be done by modifying workflow file.</p>
<h3>Publishing static application</h3>
<p>I tried Static Web App service with Angular application. I cloned my test repository to my machine, installed Angular CLI and created new Angular 9 application.</p>
<pre>mkdir StaticWebAppTest<br>git clone https://github.com/gpeipman/MyStaticSite.git<br>npm install -g @angular/cli<br>ng new StaticWebAppTest</pre>
<p>If your connection or disk is slow then go and grab some coffee – it takes time until all those node.js modules get installed. </p>
<p>When application is created we can build it and push to repository.</p>
<pre>ng build --prod<br>git add .<br>git commit –m "default angular app"<br>git push</pre>
<p>If everything went well then it’s time to head over to GitHub and see under actions if our GitHub workflow is running. This workflow was automatically created by Static Web App service and it deploys application to production environment. After successful deployment we will see it under Environment section of service.</p>
<p align="center"><a href="https://static.gunnarpeipman.com/wp-content/uploads/2020/05/azure-static-web-app-environments-production.png"><img decoding="async" width="958" height="562" title="Static Web App service: production environment is ready" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="Static Web App service: production environment is ready" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/05/azure-static-web-app-environments-production_thumb.png" border="0"></a></p>
<p>Click on Browse link to see static application running on Azure.</p>
<p align="center"><img decoding="async" width="800" height="691" title="Static Web App service: Default angular site works" style="display: inline; background-image: none;" alt="Static Web App service: Default angular site works" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/05/azure-static-web-app-angular.png" border="0"></p>
<p>What we just did? We pushed Angular application to GitHub repository and it got automatically published to our Static Web App service. It was just a commit to repository and after this things just happened. Nice!</p>
<h3>Publishing to staging environment</h3>
<p>It’s usual that new features are merged to master branch through pull requests. For Static Web App service pull requests are staging environment deployments. There can be only one stating environment right now but it will probably change in future. </p>
<p>Let’s modify default page title in src/app/app.component.html file. I added word <strong>staging</strong> to title and created pull request. You can create new branch from master, make a change and push it to GitHub from command-line. But you can skip it too. It’s possible to modify the file directly in GitHub and create new branch with pull request there.</p>
<p>When pull request is created out Static Web App workflow runs again. Take a good look on the following screenshot. When GitHub actions are running it’s shown on pull request page. After successful build there’s link to staging environment published to pull request page as bot comment.</p>
<p align="center"><a href="https://static.gunnarpeipman.com/wp-content/uploads/2020/05/azure-static-web-app-pull-request.png"><img decoding="async" width="762" height="687" title="Static Web App service: Pull request is deployed to staging environement" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="Static Web App service: Pull request is deployed to staging environement" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/05/azure-static-web-app-pull-request_thumb.png" border="0"></a></p>
<p>We can see staging information also in Azure portal if staging environment exists.</p>
<p align="center"><a href="https://static.gunnarpeipman.com/wp-content/uploads/2020/05/azure-static-web-app-environments-staging.png"><img decoding="async" width="1053" height="555" title="Static Web App service: Staging environment is ready" style="display: inline; background-image: none;" alt="Static Web App service: Staging environment is ready" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/05/azure-static-web-app-environments-staging_thumb.png" border="0"></a></p>
<p>When we open staging environment in browser we can see a change we just made.</p>
<p align="center"><img decoding="async" width="800" height="693" title="Static Web App service: Angular app in staging environment" style="border: 0px currentcolor; border-image: none; margin-right: auto; margin-left: auto; float: none; display: block; background-image: none;" alt="Static Web App service: Angular app in staging environment" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/05/azure-static-web-app-angular-staging.png" border="0"></p>
<p>After merging pull request the staging environment is automatically removed by Azure.</p>
<h3>Configuring GitHub action</h3>
<p>To change build definiton we can open yml file shown in Static Web App overview. This file is available also in our source code repository. Example of build definition is here.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: rgb(43, 145, 175);">name:</span><span style="color: rgb(163, 21, 21);"> Azure Static Web Apps CI/CD
</span>
<span style="color: rgb(43, 145, 175);">on:</span><span style="color: rgb(163, 21, 21);">
</span>&nbsp; <span style="color: rgb(43, 145, 175);">push:</span><span style="color: rgb(163, 21, 21);">
</span>&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">branches:</span><span style="color: rgb(163, 21, 21);">
</span>&nbsp;&nbsp;&nbsp; -<span style="color: rgb(163, 21, 21);"> master
</span>&nbsp; <span style="color: rgb(43, 145, 175);">pull_request:</span><span style="color: rgb(163, 21, 21);">
</span>&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">types:</span><span style="color: rgb(163, 21, 21);">&nbsp;</span>[opened, synchronize, reopened, closed]&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">branches:</span><span style="color: rgb(163, 21, 21);">
</span>&nbsp;&nbsp;&nbsp; -<span style="color: rgb(163, 21, 21);"> master
</span>
<span style="color: rgb(43, 145, 175);">jobs:</span><span style="color: rgb(163, 21, 21);">
</span>&nbsp; <span style="color: rgb(43, 145, 175);">build_and_deploy_job:</span><span style="color: rgb(163, 21, 21);">
</span>&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">if:</span><span style="color: rgb(163, 21, 21);"> github.event_name == 'push' || (github.event_name == 'pull_request' </span>&amp;&amp; github.event.action != <span style="color: rgb(163, 21, 21);">'closed'</span>)&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">runs-on</span><span style="color: maroon;">: </span>ubuntu-<span style="color: rgb(163, 21, 21);">latest
</span>&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">name:</span><span style="color: rgb(163, 21, 21);"> Build and Deploy Job
</span>&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">steps:</span><span style="color: rgb(163, 21, 21);">
</span>&nbsp;&nbsp;&nbsp; - <span style="color: rgb(43, 145, 175);">uses:</span><span style="color: rgb(163, 21, 21);"> actions/checkout@v1
</span>&nbsp;&nbsp;&nbsp; - <span style="color: rgb(43, 145, 175);">name:</span><span style="color: rgb(163, 21, 21);"> Build And Deploy
</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">id:</span><span style="color: rgb(163, 21, 21);"> builddeploy
</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">uses:</span><span style="color: rgb(163, 21, 21);"> Azure/static-web-apps-deploy@v0.0.1-preview
</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">with:</span><span style="color: rgb(163, 21, 21);">
</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">azure_static_web_apps_api_token:</span><span style="color: rgb(163, 21, 21);"> $</span>{{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_AMBITIOUS_SMOKE_092E9AF03 }}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">repo_token:</span><span style="color: rgb(163, 21, 21);"> $</span>{{ secrets.GITHUB_TOKEN }} <span style="color: green;"># Used for Github integrations (i.e. PR comments)
</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">action:</span><span style="color: rgb(163, 21, 21);"> 'upload'
</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: green;">###### Repository/Build Configurations - These values can be configured to match you app requirements. ######
</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">app_location:</span><span style="color: rgb(163, 21, 21);"> '/' </span><span style="color: green;"># App source code path
</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">api_location:</span><span style="color: rgb(163, 21, 21);"> '' </span><span style="color: green;"># Api source code path - optional
</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">app_artifact_location:</span><span style="color: rgb(163, 21, 21);"> 'dist/MyStaticSite' </span><span style="color: green;"># Built app content directory - optional
</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: green;">###### End of Repository/Build Configurations ######
</span>&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">close_pull_request_job:</span><span style="color: rgb(163, 21, 21);">
</span>&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">if:</span><span style="color: rgb(163, 21, 21);"> github.event_name == 'pull_request' </span>&amp;&amp; github.event.action == <span style="color: rgb(163, 21, 21);">'closed'</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">runs-on</span><span style="color: maroon;">: </span>ubuntu-<span style="color: rgb(163, 21, 21);">latest
</span>&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">name:</span><span style="color: rgb(163, 21, 21);"> Close Pull Request Job
</span>&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">steps:</span><span style="color: rgb(163, 21, 21);">
</span>&nbsp;&nbsp;&nbsp; - <span style="color: rgb(43, 145, 175);">name:</span><span style="color: rgb(163, 21, 21);"> Close Pull Request
</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">id:</span><span style="color: rgb(163, 21, 21);"> closepullrequest
</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">uses:</span><span style="color: rgb(163, 21, 21);"> Azure/static-web-apps-deploy@v0.0.1-preview
</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">with:</span><span style="color: rgb(163, 21, 21);">
</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">azure_static_web_apps_api_token:</span><span style="color: rgb(163, 21, 21);"> $</span>{{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_AMBITIOUS_SMOKE_092E9AF03 }}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">action:</span><span style="color: rgb(163, 21, 21);"> 'close'
</span><br></pre>
<p>Internally Microsoft is using their <a title="Oryx @ GitHub" href="https://github.com/microsoft/Oryx">build system Oryx</a> that is created to automatically compile applications to runnable artifacts in Microsoft services. </p>
<h3>Wrapping up</h3>
<p>Azure Static Web App fits well between Azure App Service and Azure Static Website offerings. There’s integration with GitHub using GitHub actions. Production environment is based on monitoring given source code repository branch. Staging environment come and go based on creation and merge of pull requests. Static Web App is platform agnostic. It doesn’t care about operating system and code editor or IDE that developers use. If GitHub actions are able to build static web application then it’s enough for Static Web App service to work. Although there’s only one staging environment supported right now, it will probably change in future when I think about applications in active development.</p>
<h3>References</h3>
<ul>
<li><a title="Static Web Apps Home Page" href="https://azure.microsoft.com/en-us/services/app-service/static/">Azure Static Web Apps</a> (official home page)</li>
<li><a title="Azure Static Web Apps documentation" href="https://docs.microsoft.com/en-us/azure/static-web-apps/">Azure Static Web Apps documentation</a></li>
<li><a title="Microsoft Oryx @ GitHub" href="https://github.com/microsoft/Oryx">Microsoft Oryx</a> (official home page)</li>
<li><a title="(VS Code documentation)" href="https://code.visualstudio.com/docs/nodejs/angular-tutorial">Using Angular in Visual Studio Code</a> (VS Code documentation)</li>
<li><a title="Introducing App Service Static Web Apps" href="https://techcommunity.microsoft.com/t5/azure-app-service/introducing-app-service-static-web-apps/ba-p/1394451">Introducing App Service Static Web Apps</a> (Microsoft Tech Community)</li>
</ul>
<p>The post <a href="https://gunnarpeipman.com/azure-static-web-app/">Introducing Azure Static Web App service</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gunnarpeipman.com/azure-static-web-app/feed/</wfw:commentRss>
			<slash:comments>43</slash:comments>
		
		
			</item>
		<item>
		<title>Xamarin Forms turns to .NET MAUI &#8211; single project and code-base dev experience</title>
		<link>https://gunnarpeipman.com/dotnet-maui-announced/</link>
					<comments>https://gunnarpeipman.com/dotnet-maui-announced/#comments</comments>
		
		<dc:creator><![CDATA[Gunnar Peipman]]></dc:creator>
		<pubDate>Wed, 20 May 2020 03:22:15 +0000</pubDate>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Mobile]]></category>
		<category><![CDATA[UWP]]></category>
		<category><![CDATA[Visual Studio]]></category>
		<guid isPermaLink="false">https://gunnarpeipman.com/?p=6120</guid>

					<description><![CDATA[<p>Yesterday Microsoft announced .NET Multi-platform App UI (MAUI) – the effort to turn Xamarin Forms apps use single cross-platform code-base targeting multiple platforms. Demos from Build conference yesterday gave clear signal – it’s not just an experiment but real deal. They really had single project running on Windows desktop and iPhone. This blog post is short overview of what’s coming.</p>
<p>The post <a href="https://gunnarpeipman.com/dotnet-maui-announced/">Xamarin Forms turns to .NET MAUI &#8211; single project and code-base dev experience</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Yesterday Microsoft announced .NET Multi-platform App UI (MAUI) – the effort to turn Xamarin Forms apps use single cross-platform code-base targeting multiple platforms. Demos from Build conference yesterday gave clear signal – it’s not just an experiment but real deal. They really had single project running on Windows desktop and iPhone. This blog post is short overview of what’s coming.</p>
<p><span id="more-6120"></span></p>
<p align="center"><img decoding="async" width="800" height="449" title=".NET MAUI" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt=".NET MAUI" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/05/dotnet-maui-slide.png" border="0"></p>
<p>Today Xamarin applications need separate project for each target platform. .NET 5 – coming this autumn – lays excellent base for multi-targeting as .NET Core, Mono and Xamarin will all base on same base class library (BCL) and SDK toolchain. Besides desktop and mobile, .NET MAUI will support also new foldable devices like <a title="Microsoft Neo Home Page" href="https://www.microsoft.com/en-us/surface/devices/surface-neo">Microsoft Neo</a>. First previews of .NET MAUI will be available later this year when Microsoft focuses to .NET 6 that is scheduled to release with .NET MAUI at November 2021.</p>
<h3>Developing .NET MAUI applications</h3>
<p><img decoding="async" width="302" height="282" title=".NET MAUI project in Visual Studio" align="right" style="margin: 0px 0px 0px 10px; border: 0px currentcolor; border-image: none; float: right; display: inline; background-image: none;" alt=".NET MAUI project in Visual Studio" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/05/dotnet-maui-solution.png" border="0">Image of .NET MAUI solution here shows how there is one project targeting multiple platforms. There will be new Platforms folder in .NET MAUI projects and under this we can see separate subfolder for each target platform. Screenshot here shows BluetoothAdapter class that is platform dependent. There will also be support for platform specific resources.</p>
<p>Supported platforms will be defined in project file using .NET 5 monikers like net5.0-ios, net5.0 and net5.0-android.</p>
<p>As .NET MAUI is advancement of Xamarin Forms then application pages use good old XAML and C#. Besides code-behind, modern patterns like Model-View-ViewModel (MVVM) and <a title="Model-View-Update (MVU) &ndash; How Does It Work?" href="https://thomasbandt.com/model-view-update">Model-View-Update (MVU)</a> are supported too. MVU is new UI pattern enabling developers to write fluent C# UI-s on .NET MAUI.</p>
<p>Transition to .NET MAUI should be almost painless as .NET MAUI comes with controls and API-s already present in Xamarin Forms.</p>
<h3>Second front: Blazor WebAssembly</h3>
<p>Yesterday Microsoft also launched <a title="Blazor WebAssembly 3.2.0 now available" href="https://devblogs.microsoft.com/aspnet/blazor-webassembly-3-2-0-now-available/">Blazor WebAssembly</a> to general availability. At January during <a title="Announcements from .NET Conf: Focus on Blazor" href="https://gunnarpeipman.com/focus-on-blazor-announcements/">.NET Conf: Focus on Blazor</a> online conference Microsoft demonstrated some very interesting experiments with Blazor:</p>
<ul>
<li><a title="Blazor + Electron" href="https://aka.ms/blazorelectron">Blazor + Electron</a></li>
<li><a title="Blazor + WebWindow" href="https://aka.ms/webwindow">Blazor + WebWindow</a></li>
<li><a title="Mobile Blazor Bindings" href="https://aka.ms/mobileblazorbindings">Mobile Blazor Bindings</a>&nbsp;</li>
</ul>
<p>Electron and WebWindow are able to take Blazor applications across platforms and devices. Mobile bindings enable use of native API-s to Blazor WebAssembly applications. Although Blazor tooling targets web applications, these experiments show clearly that Blazor is able to jump out from its box.</p>
<p align="center"><img decoding="async" title="Blazor in WebView" alt="Blazor in WebView" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/01/blazor-hello-macos_thumb.png"></p>
<p>What makes Blazor front interesting is the fact that it may give us different tooling for multi-platform applications. .NET MAUI will be for native multi-platform applications and some Blazor multi-plaform offering will be for applications built using web technologies.</p>
<p>As there’s time a little bit over year to launch of .NET MAUI it will be interesting to see where Blazor evolves and if there will be some connection point for these two multi-platform worlds.</p>
<h3>.NET MAUI roadmap</h3>
<p>The current roadmap spans from this to next autumn.</p>
<ul>
<li><strong>Late 2020</strong> – Preview 1</li>
<li><strong>Early 2021</strong> – Preview 2 and Preview 3</li>
<li><strong>Mid 2021</strong> – Preview 4 and Preview 5</li>
<li><strong>September 2021</strong> – Release Candidate</li>
<li><strong>November 2021</strong> – General Availability</li>
</ul>
<h3>References</h3>
<ul>
<li><a title="Introducing .NET Multi-platform App UI" href="https://devblogs.microsoft.com/dotnet/introducing-net-multi-platform-app-ui/">Introducing .NET Multi-platform App UI</a> (.NET Blog)</li>
<li><a title=".NET MAUI @ GitHub" href="https://github.com/dotnet/maui">.NET MAUI @ GitHub</a></li>
<li><a title=".NET MAUI roadmap" href="https://github.com/dotnet/maui/wiki/Roadmap">.NET MAUI official roadmap</a></li>
<li><a title="Model-View-Update (MVU) &ndash; How Does It Work?" href="https://thomasbandt.com/model-view-update">Model-View-Update (MVU) – How Does It Work?</a> (Thomas Bandt)</li>
<li><a title="The Journey to One .NET" href="https://mybuild.microsoft.com/sessions/b7e27509-c56c-42ad-9ce2-34270ecb0a38">Build session: The Journey to One .NET</a> (Scott Hanselman, Scott Hunter)</li>
</ul>
<p>The post <a href="https://gunnarpeipman.com/dotnet-maui-announced/">Xamarin Forms turns to .NET MAUI &#8211; single project and code-base dev experience</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gunnarpeipman.com/dotnet-maui-announced/feed/</wfw:commentRss>
			<slash:comments>45</slash:comments>
		
		
			</item>
		<item>
		<title>Hosting WordPress behind Azure Front Door</title>
		<link>https://gunnarpeipman.com/wordpress-azure-front-door/</link>
					<comments>https://gunnarpeipman.com/wordpress-azure-front-door/#comments</comments>
		
		<dc:creator><![CDATA[Gunnar Peipman]]></dc:creator>
		<pubDate>Tue, 19 May 2020 04:34:08 +0000</pubDate>
				<category><![CDATA[Azure]]></category>
		<category><![CDATA[Linux]]></category>
		<guid isPermaLink="false">https://gunnarpeipman.com/?p=6115</guid>

					<description><![CDATA[<p>During lockdown I tried out how Azure Front Door works. It is another member of Azure load balancers and traffic routers world but it is global and designed for web applications. My only interest was to see how it works and if it is just for commercial sites or does it also fit for private WordPress blogs like I have. It was interesting journey full of of surprises and here’s the overview of what I did and how things worked out.</p>
<p>The post <a href="https://gunnarpeipman.com/wordpress-azure-front-door/">Hosting WordPress behind Azure Front Door</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>During lockdown I tried out how Azure Front Door works. It is another member of Azure load balancers and traffic routers world but it is global and designed for web applications. My only interest was to see how it works and if it is just for commercial sites or does it also fit for private WordPress blogs like I have. It was interesting journey full of of surprises and here’s the overview of what I did and how things worked out.</p>
<p><span id="more-6115"></span></p>
<h3>What is Azure Front Door?</h3>
<p>To understand what is Azure Front Door let’s <a title="What is Azure Front Door?" href="https://docs.microsoft.com/en-us/azure/frontdoor/front-door-overview">jump to documentation</a>. Azure Front Door enables you to define, manage, and monitor the global routing for your web traffic by optimizing for best performance and instant global failover for high availability. With Front Door, you can transform your global (multi-region) consumer and enterprise applications into robust, high-performance personalized modern applications, APIs, and content that reaches a global audience with Azure.</p>
<p>Azure Front Door is Layer 7 network service having the following nice features:</p>
<ul>
<li>SSL offload and application acceleration at the edge close to end users</li>
<li>Global HTTP load balancing with instant failover</li>
<li>Actionable insights about your users and back ends</li>
<li>Web Application Firewall (WAF) and DDoS Protection</li>
<li>Central control plane for traffic orchestration</li>
</ul>
<p>Important thing to understand is the fact that Azure Front Door is not bound to any specific region. By example, Azure Front Door service can be used for high-availability across multiple Azure regions like shown on the following diagram.</p>
<p align="center"><a href="https://static.gunnarpeipman.com/wp-content/uploads/2020/05/multi-region-web-app-diagram.png"><img decoding="async" width="800" height="413" title="Azure Front Door: Multi-region web application" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="Azure Front Door: Multi-region web application" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/05/multi-region-web-app-diagram_thumb.png" border="0"></a><em>This image is taken from Azure Front Door documentation page<br /> <a title="Run a web application in multiple Azure regions for high availability" href="https://docs.microsoft.com/en-us/azure/architecture/reference-architectures/app-service-web-app/multi-region">Run a web application in multiple Azure regions for high availability</a>.</em></p>
<p>One interesting thing is that Azure Front Door works similar to Azure CDN. It uses same Point-of-Presence (PoP) servers as Azure CDN meaning that your content will be close to visitors all over the world.</p>
<h3>Hosting WordPress behind Azure Front Door</h3>
<p>When it comes to hosting WordPress on Azure there are some options to consider.</p>
<ul>
<li><strong>Azure App Service</strong> – together with Azure SQL for MySQL it can come pretty expensive. Still you have to understand that these services are stable and highly scalable. Azure engineers are the ones who keep those services alive and you don’t need any task force on your side.</li>
<li><strong>Virtual Machines</strong> – if you want to control almost everything and keep costs down then you can go with small Linux virtual machines on Azure. It means more work for you as virtual machines are your own responsibility. Also you are in judge on managing all other services around them.</li>
</ul>
<p>Azure App Service with database is very straight-forward to understand if we are talking about getting things running. Virtual machines are different story. Here’s one possible idea how VM-s can be set up. </p>
<p align="center"><img decoding="async" width="395" height="430" title="WordPress on Azure virtual machines" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="WordPress on Azure virtual machines" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/05/wordpress-vms.png" border="0"></p>
<p>NginX serves as caching reverse proxy before WordPress machines. It’s the only VM that has unrestricted public access. All otger VM-s are no accessible from public internet. Blob storage and Azure CDN can be used for all static assets in wp-content folder to keep load away from small VM-s. </p>
<p>Our Azure Front Door and WAF cloud architecture for WordPress VM-s solution is shown on the following diagram.</p>
<p align="center"><img decoding="async" width="399" height="446" title="WordPress virtual machines behind Azure Front Door" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="WordPress virtual machines behind Azure Front Door" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/05/wordpress-vms-behind-azure-front-door.png" border="0"></p>
<p>Notice that there’s no more NginX and load balancing is done by Azure Front Door.</p>
<h3>Setting up Azure Front Door</h3>
<p>Load balancing with NginX is great but there’s one issue – it’s regional and not global. Setting up our own NginX to every region of Azure is out of question. It will be expensive and I’m sure that it needs close monitoring even after all pieces of puzzle start work together as one system. This is where Azure Front Door comes to help.</p>
<p align="center"><img decoding="async" width="693" height="313" title="Azure Front Door configuration" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="Azure Front Door configuration" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/05/azure-front-door-config.png" border="0"></p>
<p>Azure Front Door service is set up with three steps:</p>
<ol>
<li><strong>Frontend/domains</strong> – these are domains that later have CNAME record to Azure Front End end-point. </li>
<li><strong>Backend pools</strong> – pools on backend servers where requests are sent. It can be just one server but it can be also cluster of servers. For simple WordPress blog one backend pool is enough. I have one backend pool and two WordPress servers in pool. </li>
<li><strong>Routing rules</strong> – here you can decide which URL ends in which backend pool. When you create service then default rule is created automatically. You can add more rules later if needed.</li>
</ol>
<p>I don’t go through all steps as they are documented very well by Microsoft. There are some things to consider when setting up the service.</p>
<ul>
<li><strong>Custom domains</strong> are supported but you can add one after service is created for you. For custom domain you need also certificate. If you don’t have one you can let Azure Front Door set up one for you. If you have certificate in Azure Key Vault then you must add Azure Front Door service as a user of your key vault.</li>
<li><strong>Backend pool</strong> servers running WordPress doesn’t necessarily need caching plugins to be activated. If you need to use one then make sure that they share page cache. Otherwise your pages get easily out of sync. Making WordPress output caches share disk space is not easy thing to do and I finally gave up.</li>
<li><strong>Load balancing</strong> – if you don’t have previous experiences with load balancers then leave these settings as they are. These are good defaults for most of scenarios. Read carefully about healt probes later in this post to avoid some dark surprises.</li>
<li><strong>Caching</strong> – I enabled caching and made it ignore query strings. I can access backend pool machines directly and I don’t want requests from public space to be able to ask too much from server. Ignoring query strings helps avoid different attacks but be aware – purging of content is up to you.</li>
<li><strong>Allow Azure Front Door IP-s </strong>in your firewall if you are using virtual network. Just add IP range 147.243.0.0/16 to list of allowed IP-s to your firewall. Without this Azure Front Door cannot check for servers health and server content from backend pool.</li>
</ul>
<p>When everything is set up and configured it’s time see the results.</p>
<h3>First results</h3>
<p>As we can now push our content close to our visitors there are some visible benefits we will see pretty soon after Azure Front Door is in action. Take a look at the following global ping charts comparing situation before and after enabling Azure Front Door.</p>
<p align="center"><img decoding="async" width="715" height="357" title="Average ping test duration before and after Azure Front Door" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="Average ping test duration before and after Azure Front Door" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/05/azure-front-door-ping-test.png" border="0"></p>
<p>It’s rougly taken a 3.5 times improvement in ping times. So, depending where your WordPress site is geographically hosted, you just made a favor to your readers in all other regions in the world.</p>
<blockquote>
<p><strong>For mobile devices</strong> my blog <a title="PageSpeed Insights" href="https://developers.google.com/speed/pagespeed/insights/">PageSpeed Insights</a> score went up from 66% to 74% after moving to Azure Front Door. It is for pages served from PoP servers cache. I don’t know exactly how much this number affects SEO but Google said years ago that page opening speed will matter in future (<a title="Speed is now a landing page factor for Google Search and Ads" href="https://developers.google.com/web/updates/2018/07/search-ads-speed">Speed is now a landing page factor for Google Search and Ads</a>).</p>
</blockquote>
<h3>Configuring Azure Web Application Firewall</h3>
<p>Web Application Firewall (WAF) is Azure offering for web applications. WAF protects web applications from all kind of attacks, including DDoS attacks. WAF works either in protection or detection mode. Detection mode means that WAF only logs suspicious things but doesn’t involve itself. In prevention mode WAF takes action when dangerous request is coming in. </p>
<p>WAF is able to handle attack like cross-site scripting, Java attacks, local file inclusion, PHP injection attacks, remote command execution, remote file inclusion, session fixation, SQL injection attacks and protocol attacks. </p>
<p align="center"><img decoding="async" width="567" height="383" title="Azure Front Door with Web Application Firewall (WAF)" style="margin: 0px 0px 15px; border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="Azure Front Door with Web Application Firewall (WAF)" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/05/azure-front-door-waf.png" border="0"><br /><em>Azure Web Application Firewall (WAF) on Azure Front Door. This image is taken from<br />Azure Front Door documentation page <a title="Azure Web Application Firewall on Azure Front Door" href="https://docs.microsoft.com/en-us/azure/web-application-firewall/afds/afds-overview">Azure Web Application Firewall on Azure Front Door</a>.</p>
<p></em></p>
<p>I was first a little suspicious about WAF as it comes with its own price that is not so easy to estimate. This far my NginX was able to survive all anomalies with ease and I didn’t saw much point to enable WAF. I have set of rules defined for WordPress and this has been good enough security net for me this far. But I decided to give WAF a try and I had some good surprises.</p>
<p>The following chart illustrates requests to Azure Front Door end-point. Blue line shows requests sent to backend pool – WordPress cluster. Red line shows all requests that came in to Azure Front Door end-point and dark blue line is the number of requests handled by WAF.</p>
<p align="center"><img decoding="async" width="537" height="357" title="Azure Front Doot and WAF requests diagram" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="Azure Front Doot and WAF requests diagram" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/05/azure-front-door-requests.png" border="0"></p>
<p>From numbers you see that caching has great impact on how much requests land in backend pool. From web server logs I see that WAF stops almost all weird requests to WordPress. I’m not sure how it’s done but it seems to be really effective on protecting web applications.</p>
<blockquote>
<p><strong>Spam stopped immediately!</strong> It was normal that Akismet stopped ~100 spam comments per day before lockdown. During lockdown spammers activated and the number of spam doubled up. After enabling WAF there was only<strong> </strong>one spam message per 48h.</p>
</blockquote>
<p> I was actually blown away as I didn’t expect WAF to be so effective.</p>
<h3>Be careful with health probes</h3>
<p>When I got Azure Front Door up and running I was blown away of load coming to machines in my WordPress cluster. I mean behing NginX the cluster was mostly calm and there was almost no load on WordPress VM-s. I checked web server logs and found out that there are many requests coming in from Azure Front Door PoP servers.</p>
<p>Well… by default health probe requests go to address “/” and interval is 30 seconds. No big deal, you want to say. But it is because all PoP servers use these settings to poll your backend pool. There’s a blog post <a title="Beware the non-obvious costs of Azure Front Door" href="https://brettmckenzie.net/2019/05/03/beware-the-non-obvious-costs-of-azure-front-door/">Beware the non-obvious costs of Azure Front Door</a> by Brett McKenzie where he calculated that healt proble pings came in from ~80 servers across the globe. By documentation there are 129 PoP locations, so I think Brett didn’t saw the full fury of the service.</p>
<p>Solution is simple – make health checks as small as possible. It works well if you set up some empty or one byte file and increase polling period. If your WordPress site is not mission critial then polling interval can be more than 30 seconds. Blog post <a title="Real World Cloud Migrations: Azure Front Door for global HTTP and path based load-balancing" href="https://www.hanselman.com/blog/RealWorldCloudMigrationsAzureFrontDoorForGlobalHTTPAndPathBasedLoadbalancing.aspx">Real World Cloud Migrations: Azure Front Door for global HTTP and path based load-balancing</a> by Scott Hanselman goes with 255 seconds – it’s a maximum interval.</p>
<p align="center"><img decoding="async" width="507" height="643" title="Azure Front Door health probes" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="Azure Front Door health probes" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/05/azure-front-door-health-probes.png" border="0"></p>
<p>This issue came to me as a real surprise. I wasn’t able to believe that PoP servers come to poll your site one by one. I first thought that it’s a Front Door service that makes health probe polls and broadcasts results to PoP servers but no. Okay, we can live with this if we don’t let poll requests to anything big or resource consuming. Still for me it’s the annoying fact to live with.</p>
<h3>Expenses</h3>
<p>All kind of load balancing on Azure is pricy if we are talking about sites that doesn’t generate a big buck. For simple blogs like I have Azure Front Door would be total overkill on pricing. But for mission critical applications I would use it together with WAF as they work actually well.</p>
<p>So, how much Azure Front Door adds to monthly bill?</p>
<p>In my case it would be around <strong>45 EUR/month</strong>.</p>
<p>For commercial site this number is actually small, almost nothing. For private blog it’s too much – you know, it’s 40 discounted beers per month, ooops, lets’s get back to NginX… :) After moving back to NginX it took few hours and Akismet started catching spam again. But during WAF times it was soooo quiet.</p>
<h3>Wrapping up</h3>
<p>Azure Front Door is great service for commercial web sites with more complex topology, fault tolerance or geo-distribution. It may feel pricy for private sites but for commercial sites making normal money it’s nothing. Just imagine other ways to build up something like this on Azure. It would be hell load of complex work and I’m sure it will be more expensive that going with Azure Front Door and WAF. I was actually surprised how easy it was to get Azure Front Door + WAF up and running. It took just few hours but it was my first time to set it up. WAF works well and stops most of malicious requests. I think for global and mission critical sites Azure Front Door with WAF is perfect choice.</p>
<h3>References</h3>
<ul>
<li><a title="Azure Front Door homepage" href="https://azure.microsoft.com/en-us/services/frontdoor/">Azure Front Door homepage</a></li>
<li><a title="What is Azure Front Door?" href="https://docs.microsoft.com/en-us/azure/frontdoor/front-door-overview">What is Azure Front Door? (Official documentation)</a></li>
<li><a title="Azure Web Application Firewall on Azure Front Door" href="https://docs.microsoft.com/en-us/azure/web-application-firewall/afds/afds-overview">Azure Web Application Firewall on Azure Front Door (Official documentation)</a></li>
<li><a title="Run a web application in multiple Azure regions for high availability" href="https://docs.microsoft.com/en-us/azure/architecture/reference-architectures/app-service-web-app/multi-region">Run a web application in multiple Azure regions for high availability (Official documentation)</a></li>
<li><a title="Hosting WordPress on Azure" href="https://gunnarpeipman.com/wordpress-on-azure/">Hosting WordPress on Azure (Gunnar Peipman)</a></li>
</ul>
<p>The post <a href="https://gunnarpeipman.com/wordpress-azure-front-door/">Hosting WordPress behind Azure Front Door</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gunnarpeipman.com/wordpress-azure-front-door/feed/</wfw:commentRss>
			<slash:comments>117</slash:comments>
		
		
			</item>
		<item>
		<title>Using Dapper in ASP.NET Core applications</title>
		<link>https://gunnarpeipman.com/aspnet-core-dapper/</link>
					<comments>https://gunnarpeipman.com/aspnet-core-dapper/#comments</comments>
		
		<dc:creator><![CDATA[Gunnar Peipman]]></dc:creator>
		<pubDate>Thu, 14 May 2020 08:39:15 +0000</pubDate>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[Data platform]]></category>
		<guid isPermaLink="false">https://gunnarpeipman.com/?p=6096</guid>

					<description><![CDATA[<p>Times ago I blogged about micro ORM-s. I have been busy through all Covid-19 times learning technical side of DDD and during that I met again my old friend Dapper. There are applications where Dapper is used to query read-only data without overhead coming with ORM-s. Also there are simple applications where for one or another reason developers decided to keep as close to raw SQL as possible. This blog post is brief introduction to Dapper anbd how to use it in ASP.NET Core applications.</p>
<p>The post <a href="https://gunnarpeipman.com/aspnet-core-dapper/">Using Dapper in ASP.NET Core applications</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Times ago I blogged about micro ORM-s. I have been busy through all Covid-19 times learning technical side of DDD and during that I met again my old friend Dapper. There are applications where Dapper is used to query read-only data without overhead coming with ORM-s. Also there are simple applications where for one or another reason developers decided to keep as close to raw SQL as possible. This blog post is brief introduction to Dapper anbd how to use it in ASP.NET Core applications.</p>
<p><span id="more-6096"></span></p>
<h3>What is Micro-ORM?</h3>
<p><a title="What is Micro ORM?" href="https://gunnarpeipman.com/micro-orm/">Micro-ORMs</a> are lightweight object-relational mappers (ORM). They have thin communication interface that makes it easy to query objects from database and – in some cases – to get them easily back to database too. Micro-ORMs doesn’t generate SQL based on object queries like full-blown ORM-s do. Also they usually don’t have change tracking and any other advanced features. As SQL is not generated for us we have to write it manually.</p>
<p>Manually written SQL and lack of powerful features of full-blown ORM-s means one thing – querying of database is easy task to do but updating of object graphs can be challenging.</p>
<h3>Introducing Dapper</h3>
<p><a title="Dapper @ GitHub" href="https://github.com/StackExchange/Dapper">Dapper</a> is perhaps most popular micro-ORM. It is worked out by Stack Exchange and one of the most popular sites it is running is Stack Overflow. Yeah, the same Stack Overflow we all know and from where tons code come to our systems thaks to Copy-Paste Driven Development. </p>
<p>I like Dapper because it is simple and damn easy to use and understand. It is implemented as set of extension methods to ADO.NET database connection and it sets itself on our way minimally. There are no interfaces to implement, no instances to create and take care of – only simple extension methods to use on objects we have to create anyway.</p>
<p>Here’s the example of list method for invoices.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">async</span>&nbsp;<span style="color: rgb(43, 145, 175);">Task</span>&lt;<span style="color: rgb(43, 145, 175);">IEnumerable</span>&lt;<span style="color: rgb(43, 145, 175);">Invoice</span>&gt;&gt; <span style="color: rgb(116, 83, 31);">ListInvoices</span>(<span style="color: blue;">int</span>&nbsp;<span style="color: rgb(31, 55, 127);">page</span>, <span style="color: blue;">int</span>&nbsp;<span style="color: rgb(31, 55, 127);">pageSize</span>)<br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">using</span> (<span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">connection</span> = _provider.<span style="color: rgb(116, 83, 31);">GetDbConnection</span>())<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">parameters</span> = <span style="color: blue;">new</span> { Skip = (<span style="color: rgb(31, 55, 127);">page</span> - 1)*<span style="color: rgb(31, 55, 127);">pageSize</span>, Take = <span style="color: rgb(31, 55, 127);">pageSize</span> };<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">query</span> = <span style="color: rgb(163, 21, 21);">"select * from Invoices order by CURRENT_TIMESTAMP "</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">query</span> += <span style="color: rgb(163, 21, 21);">"OFFSET @Skip ROWS "</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">query</span> += <span style="color: rgb(163, 21, 21);">"FETCH NEXT @Take ROWS ONLY"</span>;<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">return</span>&nbsp;<span style="color: blue;">await</span>&nbsp;<span style="color: rgb(31, 55, 127);">connection</span>.<span style="color: rgb(116, 83, 31);">QueryAsync</span>&lt;<span style="color: rgb(43, 145, 175);">Invoice</span>&gt;(<span style="color: rgb(31, 55, 127);">query</span>, <span style="color: rgb(31, 55, 127);">parameters</span>);<br>&nbsp;&nbsp;&nbsp; }<br>}</pre>
<p>QueryAsync() method is extension method by Dapper. It takes query and parameters object to build command, execute it and return objects of given type. There are also other methods for returning single object or results from multiple queries that were sent to server with one batch.</p>
<h3>Querying database using Dapper</h3>
<p>I wrote simple CRUD application on ASP.NET Core to demonstrate how to use Dapper. To keep code clean and SQL in one place I went with query classes similar to ones I demonstrated in my blog post <a title="Implementing repository querying interface in EF Core DbContext" href="https://gunnarpeipman.com/ef-core-dbcontext-repository/">Implementing repository querying interface in EF Core DbContextImplementing repository querying interface in EF Core DbContext</a>. </p>
<p>Let’s take a look at class for querying invoices. Notice GetInvoiceById() method that loads invoice rows from database only if user wants it to do so. </p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">class</span>&nbsp;<span style="color: rgb(43, 145, 175);">SqlServerInvoiceQueries</span> : <span style="color: rgb(43, 145, 175);">IInvoiceQueries</span><br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">private</span>&nbsp;<span style="color: blue;">readonly</span>&nbsp;<span style="color: rgb(43, 145, 175);">SqlServerConnectionProvider</span> _provider;<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">SqlServerInvoiceQueries</span>(<span style="color: rgb(43, 145, 175);">SqlServerConnectionProvider</span>&nbsp;<span style="color: rgb(31, 55, 127);">provider</span>)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _provider = <span style="color: rgb(31, 55, 127);">provider</span>;<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">async</span>&nbsp;<span style="color: rgb(43, 145, 175);">Task</span>&lt;<span style="color: rgb(43, 145, 175);">Invoice</span>&gt; <span style="color: rgb(116, 83, 31);">GetInvoiceById</span>(<span style="color: blue;">int</span>&nbsp;<span style="color: rgb(31, 55, 127);">id</span>, <span style="color: blue;">bool</span>&nbsp;<span style="color: rgb(31, 55, 127);">includeRows</span>)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">using</span>(<span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">connection</span> = _provider.<span style="color: rgb(116, 83, 31);">GetDbConnection</span>())<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">invoice</span> = <span style="color: blue;">await</span>&nbsp;<span style="color: rgb(31, 55, 127);">connection</span>.<span style="color: rgb(116, 83, 31);">QueryFirstAsync</span>&lt;<span style="color: rgb(43, 145, 175);">Invoice</span>&gt;(<span style="color: rgb(163, 21, 21);">"select * from invoices where id="</span> + <span style="color: rgb(31, 55, 127);">id</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">if</span>(<span style="color: rgb(31, 55, 127);">invoice</span> == <span style="color: blue;">null</span>)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">return</span>&nbsp;<span style="color: blue;">null</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">if</span>(<span style="color: rgb(31, 55, 127);">includeRows</span>)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">query</span> = <span style="color: rgb(163, 21, 21);">"select * from InvoiceLines where InvoiceId="</span> + <span style="color: rgb(31, 55, 127);">id</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">invoice</span>.InvoiceLines = (<span style="color: blue;">await</span>&nbsp;<span style="color: rgb(31, 55, 127);">connection</span>.<span style="color: rgb(116, 83, 31);">QueryAsync</span>&lt;<span style="color: rgb(43, 145, 175);">InvoiceLine</span>&gt;(<span style="color: rgb(31, 55, 127);">query</span>)).<span style="color: rgb(116, 83, 31);">ToList</span>();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">return</span>&nbsp;<span style="color: rgb(31, 55, 127);">invoice</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">async</span>&nbsp;<span style="color: rgb(43, 145, 175);">Task</span>&lt;<span style="color: rgb(43, 145, 175);">IEnumerable</span>&lt;<span style="color: rgb(43, 145, 175);">Invoice</span>&gt;&gt; <span style="color: rgb(116, 83, 31);">ListInvoices</span>(<span style="color: blue;">int</span>&nbsp;<span style="color: rgb(31, 55, 127);">page</span>, <span style="color: blue;">int</span>&nbsp;<span style="color: rgb(31, 55, 127);">pageSize</span>)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">using</span> (<span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">connection</span> = _provider.<span style="color: rgb(116, 83, 31);">GetDbConnection</span>())<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">parameters</span> = <span style="color: blue;">new</span> { Skip = (<span style="color: rgb(31, 55, 127);">page</span> - 1)*<span style="color: rgb(31, 55, 127);">pageSize</span>, Take = <span style="color: rgb(31, 55, 127);">pageSize</span> };<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">query</span> = <span style="color: rgb(163, 21, 21);">"select * from Invoices order by CURRENT_TIMESTAMP "</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">query</span> += <span style="color: rgb(163, 21, 21);">"OFFSET @Skip ROWS "</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">query</span> += <span style="color: rgb(163, 21, 21);">"FETCH NEXT @Take ROWS ONLY"</span>;<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">return</span>&nbsp;<span style="color: blue;">await</span>&nbsp;<span style="color: rgb(31, 55, 127);">connection</span>.<span style="color: rgb(116, 83, 31);">QueryAsync</span>&lt;<span style="color: rgb(43, 145, 175);">Invoice</span>&gt;(<span style="color: rgb(31, 55, 127);">query</span>, <span style="color: rgb(31, 55, 127);">parameters</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>}</pre>
<p>Queries classed need database connection provider – custom class to provide correct connection to query classes. For ASP.NET Core applications I register connection provider and query classes with framework-level dependency injection. Here is my MSSQL connection provider.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">class</span>&nbsp;<span style="color: rgb(43, 145, 175);">SqlServerConnectionProvider</span><br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">private</span>&nbsp;<span style="color: blue;">readonly</span>&nbsp;<span style="color: blue;">string</span> _connectionString;<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">SqlServerConnectionProvider</span>(<span style="color: blue;">string</span>&nbsp;<span style="color: rgb(31, 55, 127);">connectionString</span>)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _connectionString = <span style="color: rgb(31, 55, 127);">connectionString</span>;<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">IDbConnection</span>&nbsp;<span style="color: rgb(116, 83, 31);">GetDbConnection</span>()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">return</span>&nbsp;<span style="color: blue;">new</span>&nbsp;<span style="color: rgb(43, 145, 175);">SqlConnection</span>(_connectionString);<br>&nbsp;&nbsp;&nbsp; }<br>}</pre>
<p>Queries are plain SQL with parameters. Dapper takes away some pain on building parameters and adding these to commands. If our queries grow long, ugly and complex then we can move them to separate files or resource strings to keep query classes clean. </p>
<p>We can inject these query classes to ASP.NET Core controllers and call their methods to get data.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">class</span>&nbsp;<span style="color: rgb(43, 145, 175);">HomeController</span> : <span style="color: rgb(43, 145, 175);">Controller</span><br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">private</span>&nbsp;<span style="color: blue;">readonly</span>&nbsp;<span style="color: rgb(43, 145, 175);">IInvoiceQueries</span> _invoiceQueries;<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">HomeController</span>(<span style="color: rgb(43, 145, 175);">IInvoiceQueries</span>&nbsp;<span style="color: rgb(31, 55, 127);">invoiceQueries</span>)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _invoiceQueries = <span style="color: rgb(31, 55, 127);">invoiceQueries</span>;<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">async</span>&nbsp;<span style="color: rgb(43, 145, 175);">Task</span>&lt;<span style="color: rgb(43, 145, 175);">IActionResult</span>&gt; <span style="color: rgb(116, 83, 31);">Index</span>(<span style="color: blue;">int</span>&nbsp;<span style="color: rgb(31, 55, 127);">page</span> = 1)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">page</span> = <span style="color: rgb(43, 145, 175);">Math</span>.<span style="color: rgb(116, 83, 31);">Max</span>(1, <span style="color: rgb(31, 55, 127);">page</span>);<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">invoices</span> = <span style="color: blue;">await</span> _invoiceQueries.<span style="color: rgb(116, 83, 31);">ListInvoices</span>(<span style="color: rgb(31, 55, 127);">page</span>, 10);<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">return</span>&nbsp;<span style="color: rgb(116, 83, 31);">View</span>(<span style="color: rgb(31, 55, 127);">invoices</span>);<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: green;">// More actions follow</span><br>}</pre>
<p>For very primitive applications I don’t usually even bother to go with query classes. I need to get some simple objects from simple database tables and save them back. Be careful, of course, and don’t use this approach if there’s chance that application will grow. Example of this minimalistic approach can be found from my GitHub repository <a title="gpeipman/DapperDemo @ GitHub" href="https://github.com/gpeipman/DapperDemo">gpeipman/DapperDemo</a>.</p>
<h3>Modifying data using Dapper</h3>
<p>When we want to modify data then things get complex pretty fast. Things are easy until we work with primitive entities. But dealing with object graphs is different story.</p>
<p>Let’s take sample entities from one of my demos.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">class</span>&nbsp;<span style="color: rgb(43, 145, 175);">Invoice</span><br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">int</span> Id { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">DateTime</span> Date { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">DateTime</span> DueDate { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">string</span> Customer { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">string</span> InvoiceNo { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">IList</span>&lt;<span style="color: rgb(43, 145, 175);">InvoiceLine</span>&gt; InvoiceLines { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">Invoice</span>()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; InvoiceLines = <span style="color: blue;">new</span>&nbsp;<span style="color: rgb(43, 145, 175);">List</span>&lt;<span style="color: rgb(43, 145, 175);">InvoiceLine</span>&gt;();<br>&nbsp;&nbsp;&nbsp; }<br>}<br> <br><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">class</span>&nbsp;<span style="color: rgb(43, 145, 175);">InvoiceLine</span><br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">int</span> Id { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">string</span> LineItem { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">decimal</span> Amount { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">string</span> Unit { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">decimal</span> UnitPrice { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">int</span> VatPercent { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">decimal</span> Total { <span style="color: blue;">get</span> { <span style="color: rgb(143, 8, 196);">return</span> Amount * UnitPrice * (1 + 20 / 100); } <span style="color: blue;">set</span> { } }<br>}</pre>
<p>Suppose we have a form where we can create or modify invoice and lines it has. It’s all done dynamically in browser and when user clicks save button then invoice with rows is sent back to server. </p>
<p>Here are ASP.NET Core controller actions to update invoice.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">class</span>&nbsp;<span style="color: rgb(43, 145, 175);">HomeController</span> : <span style="color: rgb(43, 145, 175);">Controller</span><br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">private</span>&nbsp;<span style="color: blue;">readonly</span>&nbsp;<span style="color: rgb(43, 145, 175);">IInvoiceQueries</span> _invoiceQueries;<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">private</span>&nbsp;<span style="color: blue;">readonly</span>&nbsp;<span style="color: rgb(43, 145, 175);">IInvoiceRepository</span> _invoiceRepository;<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">HomeController</span>(<span style="color: rgb(43, 145, 175);">IInvoiceQueries</span>&nbsp;<span style="color: rgb(31, 55, 127);">invoiceQueries</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">IInvoiceRepository</span>&nbsp;<span style="color: rgb(31, 55, 127);">invoiceRepository</span>)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _invoiceQueries = <span style="color: rgb(31, 55, 127);">invoiceQueries</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _invoiceRepository = <span style="color: rgb(31, 55, 127);">invoiceRepository</span>;<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">void</span>&nbsp;<span style="color: rgb(116, 83, 31);">Index</span>() { }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: green;">// Some actions here</span><br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">async</span>&nbsp;<span style="color: rgb(43, 145, 175);">Task</span>&lt;<span style="color: rgb(43, 145, 175);">IActionResult</span>&gt; <span style="color: rgb(116, 83, 31);">Edit</span>(<span style="color: blue;">int</span>&nbsp;<span style="color: rgb(31, 55, 127);">id</span>)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">invoice</span> = <span style="color: blue;">await</span> _invoiceQueries.<span style="color: rgb(116, 83, 31);">GetInvoiceById</span>(<span style="color: rgb(31, 55, 127);">id</span>, <span style="color: blue;">true</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">if</span> (<span style="color: rgb(31, 55, 127);">invoice</span> == <span style="color: blue;">null</span>)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">return</span>&nbsp;<span style="color: rgb(116, 83, 31);">NotFound</span>();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">return</span>&nbsp;<span style="color: rgb(116, 83, 31);">View</span>(<span style="color: rgb(31, 55, 127);">invoice</span>);<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; [<span style="color: rgb(43, 145, 175);">HttpPost</span>]<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">async</span>&nbsp;<span style="color: rgb(43, 145, 175);">Task</span>&lt;<span style="color: rgb(43, 145, 175);">IActionResult</span>&gt; <span style="color: rgb(116, 83, 31);">Edit</span>(<span style="color: rgb(43, 145, 175);">Invoice</span>&nbsp;<span style="color: rgb(31, 55, 127);">invoice</span>)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">if</span>(!ModelState.IsValid)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">return</span>&nbsp;<span style="color: rgb(116, 83, 31);">View</span>(<span style="color: blue;">nameof</span>(<span style="color: blue;">this</span>.<span style="color: rgb(116, 83, 31);">Edit</span>), <span style="color: rgb(31, 55, 127);">invoice</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">await</span> _invoiceRepository.<span style="color: rgb(116, 83, 31);">Save</span>(<span style="color: rgb(31, 55, 127);">invoice</span>);<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">return</span>&nbsp;<span style="color: rgb(116, 83, 31);">RedirectToAction</span>(<span style="color: blue;">nameof</span>(<span style="color: blue;">this</span>.<span style="color: rgb(116, 83, 31);">Index</span>));<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: green;">// More actions follow</span><br>}</pre>
<p>As insert and delete parts are actually simple ones I leave them out. But update is not so easy when written manually without using full-blown ORM. It consists of four steps that are run in database transaction:</p>
<ol>
<li>Update invoice in database</li>
<li>Update existing invoice lines in database</li>
<li>Insert new invoice lines</li>
<li>Delete removed invoice lines</li>
</ol>
<p>Just to show how it looks in code here is the example of Update() method of my sample invoice repository.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">private</span>&nbsp;<span style="color: blue;">async</span>&nbsp;<span style="color: rgb(43, 145, 175);">Task</span>&nbsp;<span style="color: rgb(116, 83, 31);">Update</span>(<span style="color: rgb(43, 145, 175);">Invoice</span>&nbsp;<span style="color: rgb(31, 55, 127);">invoice</span>)<br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">using</span> (<span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">connection</span> = <span style="color: blue;">await</span>&nbsp;<span style="color: rgb(116, 83, 31);">GetOpenConnection</span>())<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">using</span> (<span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">transaction</span> = <span style="color: rgb(31, 55, 127);">connection</span>.<span style="color: rgb(116, 83, 31);">BeginTransaction</span>())<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">try</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">query</span> = <span style="color: rgb(163, 21, 21);">"UPDATE Invoices SET Date=@Date, DueDate=@DueDate "</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">query</span> += <span style="color: rgb(163, 21, 21);">"WHERE Id=@Id"</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">await</span>&nbsp;<span style="color: rgb(31, 55, 127);">connection</span>.<span style="color: rgb(116, 83, 31);">ExecuteAsync</span>(<span style="color: rgb(31, 55, 127);">query</span>, <span style="color: rgb(31, 55, 127);">invoice</span>, <span style="color: rgb(31, 55, 127);">transaction</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">lineIds</span> = <span style="color: blue;">new</span>&nbsp;<span style="color: rgb(43, 145, 175);">List</span>&lt;<span style="color: blue;">int</span>&gt;();<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">lineIds</span>.<span style="color: rgb(116, 83, 31);">AddRange</span>(<span style="color: rgb(31, 55, 127);">invoice</span>.InvoiceLines.<span style="color: rgb(116, 83, 31);">Where</span>(<span style="color: rgb(31, 55, 127);">l</span> =&gt; <span style="color: rgb(31, 55, 127);">l</span>.Id != 0).<span style="color: rgb(116, 83, 31);">Select</span>(<span style="color: rgb(31, 55, 127);">l</span> =&gt; <span style="color: rgb(31, 55, 127);">l</span>.Id));<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">foreach</span> (<span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">line</span>&nbsp;<span style="color: rgb(143, 8, 196);">in</span>&nbsp;<span style="color: rgb(31, 55, 127);">invoice</span>.InvoiceLines)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">if</span> (<span style="color: rgb(31, 55, 127);">line</span>.Id == 0)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">query</span> = <span style="color: rgb(163, 21, 21);">"INSERT INTO InvoiceLines (LineItem, Amount, Unit, UnitPrice, VatPercent, InvoiceId)"</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">query</span> += <span style="color: rgb(163, 21, 21);">"VALUES (@LineItem, @Amount, @Unit, @UnitPrice, @VatPercent,"</span> + <span style="color: rgb(31, 55, 127);">invoice</span>.Id + <span style="color: rgb(163, 21, 21);">"); "</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">query</span> += <span style="color: rgb(163, 21, 21);">"SELECT CAST(SCOPE_IDENTITY() AS INT)"</span>;<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">id</span> = <span style="color: blue;">await</span>&nbsp;<span style="color: rgb(31, 55, 127);">connection</span>.<span style="color: rgb(116, 83, 31);">QueryFirstAsync</span>&lt;<span style="color: blue;">int</span>&gt;(<span style="color: rgb(31, 55, 127);">query</span>, <span style="color: rgb(31, 55, 127);">line</span>, <span style="color: rgb(31, 55, 127);">transaction</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">lineIds</span>.<span style="color: rgb(116, 83, 31);">Add</span>(<span style="color: rgb(31, 55, 127);">id</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">else</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">query</span> = <span style="color: rgb(163, 21, 21);">"UPDATE InvoiceLines SET LineItem=@LineItem,Amount=@Amount,Unit=@Unit,"</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">query</span> += <span style="color: rgb(163, 21, 21);">"UnitPrice=@UnitPrice,VatPercent=@VatPercent "</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">query</span> += <span style="color: rgb(163, 21, 21);">"WHERE Id=@Id"</span>;<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">await</span>&nbsp;<span style="color: rgb(31, 55, 127);">connection</span>.<span style="color: rgb(116, 83, 31);">ExecuteAsync</span>(<span style="color: rgb(31, 55, 127);">query</span>, <span style="color: rgb(31, 55, 127);">line</span>, <span style="color: rgb(31, 55, 127);">transaction</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">if</span> (<span style="color: rgb(31, 55, 127);">lineIds</span>.Count &gt; 0)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">query</span> = <span style="color: rgb(163, 21, 21);">"DELETE FROM InvoiceLines WHERE InvoiceId="</span> + <span style="color: rgb(31, 55, 127);">invoice</span>.Id + <span style="color: rgb(163, 21, 21);">" AND "</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">query</span> += <span style="color: rgb(163, 21, 21);">"Id NOT IN("</span> + <span style="color: blue;">string</span>.<span style="color: rgb(116, 83, 31);">Join</span>(<span style="color: rgb(163, 21, 21);">','</span>, <span style="color: rgb(31, 55, 127);">lineIds</span>) + <span style="color: rgb(163, 21, 21);">")"</span>;<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">await</span>&nbsp;<span style="color: rgb(31, 55, 127);">connection</span>.<span style="color: rgb(116, 83, 31);">ExecuteAsync</span>(<span style="color: rgb(31, 55, 127);">query</span>, <span style="color: rgb(31, 55, 127);">transaction</span>: <span style="color: rgb(31, 55, 127);">transaction</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">transaction</span>.<span style="color: rgb(116, 83, 31);">Commit</span>();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">catch</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">transaction</span>.<span style="color: rgb(116, 83, 31);">Rollback</span>();<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">throw</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>}</pre>
<p>I’m sure we don’t want to write code like this and this is why I don’t consider Dapper or any other micro-ORM as a best choice for modifying data.</p>
<h3>Taking best from the both worlds – CQRS</h3>
<p>Command Query Responsibility Segregation (CQRS) is pattern first introduced by Greg Young. It’s about separating operations that query data from those that modify system state. On queries side we have data querying – it’s read-only and we are using Dapper. On commands side we modify system state and there we can use EF Core, NHibernate and other full-blown ORM-s.</p>
<p align="center"><img decoding="async" width="637" height="464" title="martin-fowler-cqrs" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="martin-fowler-cqrs" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/05/martin-fowler-cqrs.png" border="0"><br /><em>CQRS illustrated. Image is taken from <a title="CQRS by Martin Fowler" href="https://martinfowler.com/bliki/CQRS.html">CQRS</a> page by Martin Fowler.</em></p>
<p>CQRS is not must-be. It’s like any other pattern – think before you use it. It doesn’t solve all your problems and it’s not a silver bullet. In his <a title="CQRS by Martin Fowler" href="https://martinfowler.com/bliki/CQRS.html">CQRS article</a> Martin Fowler warns: “For some situations, this separation can be valuable, but beware that for most systems CQRS adds risky complexity.”</p>
<h3>Wrapping up</h3>
<p>Using Dapper we can write SQL to execute directly against the database server we are using. It is easy to use and there are just some methods we need to call to get objects out from database. As we saw from examples then querying for data is easy and straightforward but modifying data can be very challenging when it comes to object graphs. Because of this we may want to go with CQRS pattern to have separate interfaces and models for querying and modifying data. CQRS is not a silver bullet and we have to think if we want to apply it in our system or not. For applications with simple object graphs we can go with Dapper based repositories without making things too complex.</p>
<p>The post <a href="https://gunnarpeipman.com/aspnet-core-dapper/">Using Dapper in ASP.NET Core applications</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gunnarpeipman.com/aspnet-core-dapper/feed/</wfw:commentRss>
			<slash:comments>65</slash:comments>
		
		
			</item>
		<item>
		<title>Optimize database traffic with future results in NHibernate</title>
		<link>https://gunnarpeipman.com/nhibernate-future-results/</link>
					<comments>https://gunnarpeipman.com/nhibernate-future-results/#comments</comments>
		
		<dc:creator><![CDATA[Gunnar Peipman]]></dc:creator>
		<pubDate>Wed, 25 Mar 2020 06:13:21 +0000</pubDate>
				<category><![CDATA[Data platform]]></category>
		<guid isPermaLink="false">https://gunnarpeipman.com/?p=6086</guid>

					<description><![CDATA[<p>One nice feature that NHibernate has is future results. It is technically a capability to put queries on hold until data is actually asked. When data is asked then all queries are sent to server as one batch. This blog post shows how to use future results with NHibernate.</p>
<p>The post <a href="https://gunnarpeipman.com/nhibernate-future-results/">Optimize database traffic with future results in NHibernate</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>One nice feature that NHibernate has is future results. It is technically a capability to put queries on hold until data is actually asked. When data is asked from one delayed query then all queries are sent to database server as one batch and results are read also as one batch of multiple result sets. This blog post explains how to use future results with NHibernate.</p>
<p><span id="more-6086"></span></p>
<h3>Why future results?</h3>
<p>Future results decrease traffic between application and database server. Most of database servers support processing of multiple queries sent as one batch resulting in returning multiple result sets with one batch.</p>
<p align="center"><img decoding="async" width="779" height="295" title="NHibernate future results" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="NHibernate future results" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/03/nhibernate-future-results.png" border="0"></p>
<p>Suppose we have a dashboard showing some charts, tables and gauges. We can send queries to database one by one. After sending query to server we have to wait when results are sent back and then we can execute next query. But our dashboard turns out to be an excellent use case for future results because all queries we need to execute are not dependent on other queries results.</p>
<blockquote>
<p><strong>As future results</strong> are used to query data from database you should consider using stateless session of NHibernate. Stateless session performs better as it doesn’t have change tracking enabled.</p>
</blockquote>
<h3>How to use future results?</h3>
<p>Using future results is actually easy. We build queries like usually but the last call in row is to ToFuture() or ToFutureValue() method. ToFuture() and ToFutureValue() methods put queries on hold until data is asked. </p>
<p>Let’s start with simple ASP.NET Core model for dashboard.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">class</span>&nbsp;<span style="color: rgb(43, 145, 175);">DashboardModel</span><br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">IList</span>&lt;<span style="color: rgb(43, 145, 175);">Task</span>&gt; MyPendingTasks { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">IList</span>&lt;<span style="color: rgb(43, 145, 175);">Task</span>&gt; MyOverDueTasks { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">IList</span>&lt;<span style="color: rgb(43, 145, 175);">WorkLog</span>&gt; MyWorkToday { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }<br>}</pre>
<p>We need three database queries to get values to all properties of this model. Here are sample queries that are all delayed until data is actually asked in code.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">myPendingTasks</span> = _nhSession.Query&lt;<font color="#2b91af">ProjectTask</font>&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">Fetch</span>(<span style="color: rgb(31, 55, 127);">t</span> =&gt; <span style="color: rgb(31, 55, 127);">t</span>.Project)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">Where</span>(<span style="color: rgb(31, 55, 127);">t</span> =&gt; <span style="color: rgb(31, 55, 127);">t</span>.AssignedTo.InternalName == <span style="color: rgb(31, 55, 127);">userName</span> &amp;&amp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">t</span>.Deadline <span style="color: rgb(116, 83, 31);">&gt;</span>&nbsp;<span style="color: rgb(43, 145, 175);">DateTime</span>.Now &amp;&amp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">t</span>.Status != <span style="color: rgb(43, 145, 175);">ProjectTaskStatusEnum</span>.Closed &amp;&amp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">t</span>.Status != <span style="color: rgb(43, 145, 175);">ProjectTaskStatusEnum</span>.WaitingForApproval)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">Take</span>(10)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">ToFuture</span>();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br><span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">myOverDueTasks</span> = _nhSession.Query&lt;<font color="#2b91af">ProjectTask</font>&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">Fetch</span>(<span style="color: rgb(31, 55, 127);">t</span> =&gt; <span style="color: rgb(31, 55, 127);">t</span>.Project)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">Where</span>(<span style="color: rgb(31, 55, 127);">t</span> =&gt; <span style="color: rgb(31, 55, 127);">t</span>.AssignedTo.InternalName == <span style="color: rgb(31, 55, 127);">userName</span> &amp;&amp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">t</span>.Deadline <span style="color: rgb(116, 83, 31);">&lt;</span>&nbsp;<span style="color: rgb(43, 145, 175);">DateTime</span>.Now &amp;&amp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">t</span>.Status != <span style="color: rgb(43, 145, 175);">ProjectTaskStatusEnum</span>.Closed &amp;&amp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">t</span>.Status != <span style="color: rgb(43, 145, 175);">ProjectTaskStatusEnum</span>.WaitingForApproval)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">Take</span>(10)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">ToFuture</span>();<br> <br><span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">myWork</span> = _nhSession.Query&lt;<font color="#2b91af">WorkLog</font>&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">Fetch</span>(<span style="color: rgb(31, 55, 127);">w</span> =&gt; <span style="color: rgb(31, 55, 127);">w</span>.Task)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">ThenFetch</span>(<span style="color: rgb(31, 55, 127);">w</span> =&gt; <span style="color: rgb(31, 55, 127);">w</span>.Project)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">Where</span>(<span style="color: rgb(31, 55, 127);">w</span> =&gt; <span style="color: rgb(31, 55, 127);">w</span>.User.InternalName == <span style="color: rgb(31, 55, 127);">userName</span> &amp;&amp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">w</span>.Date <span style="color: rgb(116, 83, 31);">==</span>&nbsp;<span style="color: rgb(43, 145, 175);">DateTime</span>.Now.Date)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">ToFuture</span>();<br> <br><span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">model</span> = <span style="color: blue;">new</span>&nbsp;<span style="color: rgb(43, 145, 175);">DashboardModel</span>();<br><span style="color: rgb(31, 55, 127);">model</span>.MyPendingTasks = (<span style="color: blue;">await</span>&nbsp;<span style="color: rgb(31, 55, 127);">myPendingTasks</span>.<span style="color: rgb(116, 83, 31);">GetEnumerableAsync</span>()).<span style="color: rgb(116, 83, 31);">ToList</span>();<br><span style="color: rgb(31, 55, 127);">model</span>.MyOverDueTasks = (<span style="color: blue;">await</span>&nbsp;<span style="color: rgb(31, 55, 127);">myOverDueTasks</span>.<span style="color: rgb(116, 83, 31);">GetEnumerableAsync</span>()).<span style="color: rgb(116, 83, 31);">ToList</span>();<br><span style="color: rgb(31, 55, 127);">model</span>.MyWorkToday = (<span style="color: blue;">await</span>&nbsp;<span style="color: rgb(31, 55, 127);">myWork</span>.<span style="color: rgb(116, 83, 31);">GetEnumerableAsync</span>()).<span style="color: rgb(116, 83, 31);">ToList</span>();</pre>
<p>Asking of data happens when model.MyPendingTasks is assigned. Here’s the query that was sent to database server when data was asked first time from some of those delayed queries. <strong>NB!</strong> I left out fields list from FROM clauses to keep queries more readable.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">select</span>&nbsp;<br>&nbsp;&nbsp;&nbsp; <span style="color: gray;">...</span>&nbsp;<br><span style="color: blue;">from</span>&nbsp;<br>&nbsp;&nbsp;&nbsp; ProjectTasks projecttas0_ <br>&nbsp;&nbsp;&nbsp; <span style="color: gray;">inner</span>&nbsp;<span style="color: gray;">join</span> Users user1_ <span style="color: blue;">on</span>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; projecttas0_<span style="color: gray;">.</span>AssignedToId<span style="color: gray;">=</span>user1_<span style="color: gray;">.</span>Id <br>&nbsp;&nbsp;&nbsp; <span style="color: gray;">left</span>&nbsp;<span style="color: gray;">outer</span>&nbsp;<span style="color: gray;">join</span> Projects project2_ <span style="color: blue;">on</span>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; projecttas0_<span style="color: gray;">.</span>ProjectId<span style="color: gray;">=</span>project2_<span style="color: gray;">.</span>Id <br><span style="color: blue;">where</span>&nbsp;<br>&nbsp;&nbsp;&nbsp; user1_<span style="color: gray;">.</span>InternalName<span style="color: gray;">=</span>@p0 <span style="color: gray;">and</span>&nbsp;<br>&nbsp;&nbsp;&nbsp; projecttas0_<span style="color: gray;">.</span>Deadline<span style="color: gray;">&gt;</span>@p1 <span style="color: gray;">and</span>&nbsp;<br><span style="color: blue;">&nbsp;&nbsp;&nbsp; </span><span style="color: gray;">(</span>projecttas0_<span style="color: gray;">.</span><span style="color: blue;">Status</span><span style="color: gray;">&lt;&gt;</span>@p2 <span style="color: gray;">or</span> projecttas0_<span style="color: gray;">.</span><span style="color: blue;">Status</span>&nbsp;<span style="color: gray;">is</span>&nbsp;<span style="color: gray;">null)</span>&nbsp;<span style="color: gray;">and</span>&nbsp;<br><span style="color: blue;">&nbsp;&nbsp;&nbsp; </span><span style="color: gray;">(</span>projecttas0_<span style="color: gray;">.</span><span style="color: blue;">Status</span><span style="color: gray;">&lt;&gt;</span>@p3 <span style="color: gray;">or</span> projecttas0_<span style="color: gray;">.</span><span style="color: blue;">Status</span>&nbsp;<span style="color: gray;">is</span>&nbsp;<span style="color: gray;">null)</span>&nbsp;<br><span style="color: blue;">ORDER</span>&nbsp;<span style="color: blue;">BY</span>&nbsp;<br>&nbsp;&nbsp;&nbsp; <span style="color: magenta;">CURRENT_TIMESTAMP</span>&nbsp;<br>OFFSET 0 <span style="color: blue;">ROWS</span>&nbsp;<span style="color: blue;">FETCH</span>&nbsp;<span style="color: blue;">FIRST</span> @p4 <span style="color: blue;">ROWS</span> ONLY<span style="color: gray;">;</span><br> <br><span style="color: blue;">select</span><br>&nbsp;&nbsp;&nbsp; <span style="color: gray;">...</span><br><span style="color: blue;">from</span>&nbsp;<br>&nbsp;&nbsp;&nbsp; ProjectTasks projecttas0_ <br>&nbsp;&nbsp;&nbsp; <span style="color: gray;">inner</span>&nbsp;<span style="color: gray;">join</span> Users user1_ <span style="color: blue;">on</span>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; projecttas0_<span style="color: gray;">.</span>AssignedToId<span style="color: gray;">=</span>user1_<span style="color: gray;">.</span>Id <br>&nbsp;&nbsp;&nbsp; <span style="color: gray;">left</span>&nbsp;<span style="color: gray;">outer</span>&nbsp;<span style="color: gray;">join</span> Projects project2_ <span style="color: blue;">on</span>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; projecttas0_<span style="color: gray;">.</span>ProjectId<span style="color: gray;">=</span>project2_<span style="color: gray;">.</span>Id <br><span style="color: blue;">where</span>&nbsp;<br>&nbsp;&nbsp;&nbsp; user1_<span style="color: gray;">.</span>InternalName<span style="color: gray;">=</span>@p5 <span style="color: gray;">and</span>&nbsp;<br>&nbsp;&nbsp;&nbsp; projecttas0_<span style="color: gray;">.</span>Deadline<span style="color: gray;">&lt;</span>@p6 <span style="color: gray;">and</span>&nbsp;<br><span style="color: blue;">&nbsp;&nbsp;&nbsp; </span><span style="color: gray;">(</span>projecttas0_<span style="color: gray;">.</span><span style="color: blue;">Status</span><span style="color: gray;">&lt;&gt;</span>@p7 <span style="color: gray;">or</span> projecttas0_<span style="color: gray;">.</span><span style="color: blue;">Status</span>&nbsp;<span style="color: gray;">is</span>&nbsp;<span style="color: gray;">null)</span>&nbsp;<span style="color: gray;">and</span>&nbsp;<br><span style="color: blue;">&nbsp;&nbsp;&nbsp; </span><span style="color: gray;">(</span>projecttas0_<span style="color: gray;">.</span><span style="color: blue;">Status</span><span style="color: gray;">&lt;&gt;</span>@p8 <span style="color: gray;">or</span> projecttas0_<span style="color: gray;">.</span><span style="color: blue;">Status</span>&nbsp;<span style="color: gray;">is</span>&nbsp;<span style="color: gray;">null)</span>&nbsp;<br><span style="color: blue;">ORDER</span>&nbsp;<span style="color: blue;">BY</span>&nbsp;<br>&nbsp;&nbsp;&nbsp; <span style="color: magenta;">CURRENT_TIMESTAMP</span>&nbsp;<br>OFFSET 0 <span style="color: blue;">ROWS</span>&nbsp;<span style="color: blue;">FETCH</span>&nbsp;<span style="color: blue;">FIRST</span> @p9 <span style="color: blue;">ROWS</span> ONLY<span style="color: gray;">;</span><br> <br><span style="color: blue;">select</span><br>&nbsp;&nbsp;&nbsp; <span style="color: gray;">...</span><br><span style="color: blue;">from</span>&nbsp;<br>&nbsp;&nbsp;&nbsp; WorkLogs worklog0_ <br>&nbsp;&nbsp;&nbsp; <span style="color: gray;">inner</span>&nbsp;<span style="color: gray;">join</span> Users user1_ <span style="color: blue;">on</span>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; worklog0_<span style="color: gray;">.</span>UserId<span style="color: gray;">=</span>user1_<span style="color: gray;">.</span>Id <br>&nbsp;&nbsp;&nbsp; <span style="color: gray;">left</span>&nbsp;<span style="color: gray;">outer</span>&nbsp;<span style="color: gray;">join</span> ProjectTasks projecttas2_ <span style="color: blue;">on</span>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; worklog0_<span style="color: gray;">.</span>TaskId<span style="color: gray;">=</span>projecttas2_<span style="color: gray;">.</span>Id <br>&nbsp;&nbsp;&nbsp; <span style="color: gray;">left</span>&nbsp;<span style="color: gray;">outer</span>&nbsp;<span style="color: gray;">join</span> Projects project3_ <span style="color: blue;">on</span>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; projecttas2_<span style="color: gray;">.</span>ProjectId<span style="color: gray;">=</span>project3_<span style="color: gray;">.</span>Id <br><span style="color: blue;">where</span>&nbsp;<br>&nbsp;&nbsp;&nbsp; user1_<span style="color: gray;">.</span>InternalName<span style="color: gray;">=</span>@p10 <span style="color: gray;">and</span>&nbsp;<br>&nbsp;&nbsp;&nbsp; worklog0_<span style="color: gray;">.</span>[Date]<span style="color: gray;">=</span>@p11<span style="color: gray;">;</span></pre>
<p>We can clearly see that it was batch of multiple queries that was sent to database server with one shot.</p>
<blockquote>
<p><strong>NB!</strong> If you want to mimic DbContext from Entity Framework Core then please take a look at my blog post <a title="NHibernate on ASP.NET Core" href="https://gunnarpeipman.com/aspnet-core-nhibernate/">NHibernate on ASP.NET Core</a>.</p>
</blockquote>
<h3>Using Count() with future results</h3>
<p>Using Count() function is not very straightforward but it’s there and it’s easy to use. I mentioned previously extension method called ToFutureValue(). This method helps us turn queries to count queries.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">futureCount</span> = _nhSession.Query&lt;<font color="#2b91af">WorkLog</font>&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">Fetch</span>(<span style="color: rgb(31, 55, 127);">w</span> =&gt; <span style="color: rgb(31, 55, 127);">w</span>.Task)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">ThenFetch</span>(<span style="color: rgb(31, 55, 127);">w</span> =&gt; <span style="color: rgb(31, 55, 127);">w</span>.Project)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">Where</span>(<span style="color: rgb(31, 55, 127);">w</span> =&gt; <span style="color: rgb(31, 55, 127);">w</span>.User.InternalName == <span style="color: rgb(31, 55, 127);">userName</span> &amp;&amp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">w</span>.Date <span style="color: rgb(116, 83, 31);">==</span>&nbsp;<span style="color: rgb(43, 145, 175);">DateTime</span>.Now.Date)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">ToFutureValue</span>(<span style="color: rgb(31, 55, 127);">v</span> =&gt; <span style="color: rgb(31, 55, 127);">v</span>.<span style="color: rgb(116, 83, 31);">Count</span>());<br> <br><span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">count</span> = <span style="color: blue;">await</span>&nbsp;<span style="color: rgb(31, 55, 127);">futureCount</span>.<span style="color: rgb(116, 83, 31);">GetValueAsync</span>();</pre>
<p>Here is the query sent to database.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">select</span>&nbsp;<br>&nbsp;&nbsp;&nbsp; <span style="color: magenta;">cast</span><span style="color: gray;">(</span><span style="color: magenta;">count</span><span style="color: gray;">(*)</span>&nbsp;<span style="color: blue;">as</span>&nbsp;<span style="color: blue;">INT</span><span style="color: gray;">)</span>&nbsp;<span style="color: blue;">as</span> col_0_0_ <br><span style="color: blue;">from</span>&nbsp;<br>&nbsp;&nbsp;&nbsp; WorkLogs worklog0_ <br>&nbsp;&nbsp;&nbsp; <span style="color: gray;">inner</span>&nbsp;<span style="color: gray;">join</span> Users user1_ <span style="color: blue;">on</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; worklog0_<span style="color: gray;">.</span>UserId<span style="color: gray;">=</span>user1_<span style="color: gray;">.</span>Id <br><span style="color: blue;">where</span>&nbsp;<br>&nbsp;&nbsp;&nbsp; user1_<span style="color: gray;">.</span>InternalName<span style="color: gray;">=</span>@p0 <span style="color: gray;">and</span>&nbsp;<br>&nbsp;&nbsp;&nbsp; worklog0_<span style="color: gray;">.</span>[Date]<span style="color: gray;">=</span>@p1</pre>
<p>Same way we can use also other aggregate functions but also LINQ methods like Any(), FirstOrDefault(), etc.</p>
<blockquote>
<p><strong>NB!</strong> If you prefer to write queries using criteria API or if you don’t have any other option than criteria API then future results are also supported there. With criteria API you can also use <a title="Query batch (NHibernate documentation)" href="https://nhibernate.info/doc/nhibernate-reference/performance.html#performance-multi-query">query batches</a>. Query batches let you define sets of queries that are sent to database together. Future results are gathered by NHibernate and they are all executed as soon as data is actually asked from some future query.</p>
</blockquote>
<h3>Wrapping up</h3>
<p>Future results in NHibernate lead to decreased database traffic as all delayed queries are sent to database with one shot and results are also read back with one shot. It may put some additional load to client application but in these cases I suggest to use stateless sessions as they come with less overhead and no change tracking. Future results are not silver bullets and your mileage may vary. Like always – if you make any performance improvements to your application, make sure you measure the effect.</p>
<p>The post <a href="https://gunnarpeipman.com/nhibernate-future-results/">Optimize database traffic with future results in NHibernate</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gunnarpeipman.com/nhibernate-future-results/feed/</wfw:commentRss>
			<slash:comments>46</slash:comments>
		
		
			</item>
		<item>
		<title>Displaying enum as select list in ASP.NET Core</title>
		<link>https://gunnarpeipman.com/aspnet-core-enum-to-select-list/</link>
					<comments>https://gunnarpeipman.com/aspnet-core-enum-to-select-list/#comments</comments>
		
		<dc:creator><![CDATA[Gunnar Peipman]]></dc:creator>
		<pubDate>Tue, 24 Mar 2020 10:41:51 +0000</pubDate>
				<category><![CDATA[ASP.NET]]></category>
		<guid isPermaLink="false">https://gunnarpeipman.com/?p=6083</guid>

					<description><![CDATA[<p>Some properties of model classes come as enums and we want to show enum values in select list when edit form is opened. Sometimes we want enum element names but sometimes we want to use custom names or even translations. his blog post demonstrates how to get enum element names to select list on ASP.NET Core.</p>
<p>The post <a href="https://gunnarpeipman.com/aspnet-core-enum-to-select-list/">Displaying enum as select list in ASP.NET Core</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Some properties of model classes come as enums and we want to show enum values in select list when edit form is opened. Sometimes we want enum element names but sometimes we want to use custom names or even translations. his blog post demonstrates how to get enum element names to select list on ASP.NET Core.</p>
<p><span id="more-6083"></span></p>
<p>Let’s suppose we have customer entity that has customer type property defined as enum.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">class</span>&nbsp;<span style="color: rgb(43, 145, 175);">Customer</span><br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">Guid</span> Id { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">string</span> Name { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">CustomerTypeEnum</span> Type { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }<br>}</pre>
<p>Let’s define enum and make it use DisplayAttribute and resource file.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">enum</span>&nbsp;<span style="color: rgb(43, 145, 175);">CustomerTypeEnum</span><br>{<br>&nbsp;&nbsp;&nbsp; [<span style="color: rgb(43, 145, 175);">Display</span>(Name = <span style="color: rgb(163, 21, 21);">"Companies"</span>)]<br>&nbsp;&nbsp;&nbsp; PrivateSector,<br> <br>&nbsp;&nbsp;&nbsp; [<span style="color: rgb(43, 145, 175);">Display</span>(Name = <span style="color: rgb(163, 21, 21);">"PublicSector"</span>, ResourceType = <span style="color: blue;">typeof</span>(Resources.<span style="color: rgb(43, 145, 175);">Common</span>))]<br>&nbsp;&nbsp;&nbsp; PublicSector,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; Internal<br>}</pre>
<p>There are three different cases together now:</p>
<ol>
<li>Enum member with just a name</li>
<li>Enum member with Display attribute and static name</li>
<li>Enum member with Display attribute and resource file</li>
</ol>
<p>My resource file is here. Important thing: set resource modifier to Public (this option is visible when resource window is wide enough).</p>
<p align="center"><img decoding="async" width="473" height="182" title="Resource file to test Display attribute with GetEnumSelectList() method" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="Resource file to test Display attribute with GetEnumSelectList() method" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/03/getenumselectlist-resource-file.png" border="0"></p>
<p>I add now simple edit view and use <strong>Html.GetEnumSelectList&lt;T&gt;()</strong> extension method to fill select list with enum members. Notice how I added first empty selection (Select type …) as the only member of select list.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="background: yellow;">@model</span>&nbsp;<span style="color: rgb(43, 145, 175);">Customer</span><br><span style="background: yellow;">@{</span><br>&nbsp;&nbsp;&nbsp; ViewData[<span style="color: rgb(163, 21, 21);">"Title"</span>] = <span style="color: rgb(163, 21, 21);">"Edit"</span>;<br><span style="background: yellow;">}</span><br> <br><span style="color: blue;">&lt;</span><span style="color: maroon;">h1</span><span style="color: blue;">&gt;</span>Edit<span style="color: blue;">&lt;/</span><span style="color: maroon;">h1</span><span style="color: blue;">&gt;</span><br> <br><span style="color: blue;">&lt;</span><span style="color: maroon;">form</span>&nbsp;<span style="color: purple; font-weight: bold;">asp-action</span><span style="color: blue;">=</span><span style="color: blue;">"Edit"</span>&nbsp;<span style="color: red;">class</span><span style="color: blue;">=</span><span style="color: blue;">"row"</span><span style="color: blue;">&gt;</span><br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">&lt;</span><span style="color: maroon;">div</span>&nbsp;<span style="color: red;">class</span><span style="color: blue;">=</span><span style="color: blue;">"col-4"</span><span style="color: blue;">&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">&lt;</span><span style="color: maroon;">div</span>&nbsp;<span style="color: purple; font-weight: bold;">asp-validation-summary</span><span style="color: blue;">=</span><span style="color: blue;">"</span>All<span style="color: blue;">"</span>&nbsp;<span style="color: red;">class</span><span style="color: blue;">=</span><span style="color: blue;">"text-danger"</span><span style="color: blue;">&gt;&lt;/</span><span style="color: maroon;">div</span><span style="color: blue;">&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">&lt;</span><span style="color: maroon;">input</span>&nbsp;<span style="color: purple; font-weight: bold;">type</span><span style="color: blue;">=</span><span style="color: blue;">"hidden"</span>&nbsp;<span style="color: purple; font-weight: bold;">asp-for</span><span style="color: blue;">=</span><span style="color: blue;">"</span>Id<span style="color: blue;">"</span>&nbsp;<span style="color: blue;">/&gt;</span><br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">&lt;</span><span style="color: maroon;">div</span>&nbsp;<span style="color: red;">class</span><span style="color: blue;">=</span><span style="color: blue;">"form-group"</span><span style="color: blue;">&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">&lt;</span><span style="color: maroon;">label</span>&nbsp;<span style="color: purple; font-weight: bold;">asp-for</span><span style="color: blue;">=</span><span style="color: blue;">"</span>Name<span style="color: blue;">"</span>&nbsp;<span style="color: red;">class</span><span style="color: blue;">=</span><span style="color: blue;">"control-label"</span><span style="color: blue;">&gt;&lt;/</span><span style="color: maroon;">label</span><span style="color: blue;">&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">&lt;</span><span style="color: maroon;">input</span>&nbsp;<span style="color: purple; font-weight: bold;">asp-for</span><span style="color: blue;">=</span><span style="color: blue;">"</span>Name<span style="color: blue;">"</span>&nbsp;<span style="color: red;">class</span><span style="color: blue;">=</span><span style="color: blue;">"form-control"</span>&nbsp;<span style="color: blue;">/&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">&lt;</span><span style="color: maroon;">span</span>&nbsp;<span style="color: purple; font-weight: bold;">asp-validation-for</span><span style="color: blue;">=</span><span style="color: blue;">"</span>Name<span style="color: blue;">"</span>&nbsp;<span style="color: red;">class</span><span style="color: blue;">=</span><span style="color: blue;">"text-danger"</span><span style="color: blue;">&gt;&lt;/</span><span style="color: maroon;">span</span><span style="color: blue;">&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">&lt;/</span><span style="color: maroon;">div</span><span style="color: blue;">&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">&lt;</span><span style="color: maroon;">div</span>&nbsp;<span style="color: red;">class</span><span style="color: blue;">=</span><span style="color: blue;">"form-group"</span><span style="color: blue;">&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">&lt;</span><span style="color: maroon;">label</span>&nbsp;<span style="color: purple; font-weight: bold;">asp-for</span><span style="color: blue;">=</span><span style="color: blue;">"</span>Type<span style="color: blue;">"</span>&nbsp;<span style="color: red;">class</span><span style="color: blue;">=</span><span style="color: blue;">"control-label"</span><span style="color: blue;">&gt;&lt;/</span><span style="color: maroon;">label</span><span style="color: blue;">&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">&lt;</span><span style="color: maroon;">select</span>&nbsp;<span style="color: purple; font-weight: bold;">asp-for</span><span style="color: blue;">=</span><span style="color: blue;">"</span>Type<span style="color: blue;">"</span>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: red;">class</span><span style="color: blue;">=</span><span style="color: blue;">"form-control"</span>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: purple; font-weight: bold;">asp-items</span><span style="color: blue;">=</span><span style="color: blue;">"</span>Html.<span style="color: rgb(116, 83, 31);">GetEnumSelectList</span>&lt;<span style="color: rgb(43, 145, 175);">CustomerTypeEnum</span>&gt;()<span style="color: blue;">"</span><span style="color: blue;">&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">&lt;</span><span style="color: maroon;">option</span><span style="color: blue;">&gt;</span>Select type ...<span style="color: blue;">&lt;/</span><span style="color: maroon;">option</span><span style="color: blue;">&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">&lt;/</span><span style="color: maroon;">select</span><span style="color: blue;">&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">&lt;</span><span style="color: maroon;">span</span>&nbsp;<span style="color: purple; font-weight: bold;">asp-validation-for</span><span style="color: blue;">=</span><span style="color: blue;">"</span>Type<span style="color: blue;">"</span>&nbsp;<span style="color: red;">class</span><span style="color: blue;">=</span><span style="color: blue;">"text-danger"</span><span style="color: blue;">&gt;&lt;/</span><span style="color: maroon;">span</span><span style="color: blue;">&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">&lt;/</span><span style="color: maroon;">div</span><span style="color: blue;">&gt;</span><br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">&lt;</span><span style="color: maroon;">div</span>&nbsp;<span style="color: red;">class</span><span style="color: blue;">=</span><span style="color: blue;">"form-group"</span><span style="color: blue;">&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">&lt;</span><span style="color: maroon;">input</span>&nbsp;<span style="color: red;">type</span><span style="color: blue;">=</span><span style="color: blue;">"submit"</span>&nbsp;<span style="color: red;">value</span><span style="color: blue;">=</span><span style="color: blue;">"Save"</span>&nbsp;<span style="color: red;">class</span><span style="color: blue;">=</span><span style="color: blue;">"btn btn-primary"</span>&nbsp;<span style="color: blue;">/&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">&lt;/</span><span style="color: maroon;">div</span><span style="color: blue;">&gt;</span><br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">&lt;/</span><span style="color: maroon;">div</span><span style="color: blue;">&gt;</span><br><span style="color: blue;">&lt;/</span><span style="color: maroon;">form</span><span style="color: blue;">&gt;</span><br> <br><span style="color: blue;">&lt;</span><span style="color: maroon;">div</span><span style="color: blue;">&gt;</span><br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">&lt;</span><span style="color: maroon;">a</span>&nbsp;<span style="color: purple; font-weight: bold;">asp-action</span><span style="color: blue;">=</span><span style="color: blue;">"Index"</span><span style="color: blue;">&gt;</span>Back to List<span style="color: blue;">&lt;/</span><span style="color: maroon;">a</span><span style="color: blue;">&gt;</span><br><span style="color: blue;">&lt;/</span><span style="color: maroon;">div</span><span style="color: blue;">&gt;</span></pre>
<p>When we run application and move to edit form we can see that select list is filled with enum members and ASP.NET Core respects DisplayAttribute with static name and resource files.</p>
<p align="center"><img decoding="async" width="391" height="376" title="Html.GetEnumSelectList&lt;Customer&gt;() displaying list of customer types" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="Html.GetEnumSelectList&lt;Customer&gt;() displaying list of customer types" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/03/aspnet-core-enum-select-list.png" border="0"></p>
<p>If you don’t have control over enum (enum is defined in already built assembly) then you can’t apply Display attribute to enum and you need some other solution to get values you need.</p>
<h3>Wrapping up</h3>
<p>ASP.NET Core has built-in Html.GetEnumSelectList&lt;T&gt;() method we can use to turn enum members to select list items. The method is intelligent enough to support Display attribute and therefore we can use custom names for enum members and even translations from resource files. Well, until we have full control over enum. If enum comes from external library then we will get the names it has and if we want to change something then we have to find some other solution.</p>
<p>The post <a href="https://gunnarpeipman.com/aspnet-core-enum-to-select-list/">Displaying enum as select list in ASP.NET Core</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gunnarpeipman.com/aspnet-core-enum-to-select-list/feed/</wfw:commentRss>
			<slash:comments>18</slash:comments>
		
		
			</item>
		<item>
		<title>EF Core 5.0: Using ToQueryString() method to translate LINQ query to SQL</title>
		<link>https://gunnarpeipman.com/ef-core-toquerystring/</link>
					<comments>https://gunnarpeipman.com/ef-core-toquerystring/#comments</comments>
		
		<dc:creator><![CDATA[Gunnar Peipman]]></dc:creator>
		<pubDate>Fri, 20 Mar 2020 05:15:36 +0000</pubDate>
				<category><![CDATA[Data platform]]></category>
		<category><![CDATA[Visual Studio]]></category>
		<guid isPermaLink="false">https://gunnarpeipman.com/?p=6074</guid>

					<description><![CDATA[<p>Entity Framework Core 5.0 comes with SQL-based brother to ToString() method for LINQ-queries. This method is called ToQueryString() and it returns provider-specific SQL without connecting to database server. This blog post shows how ToQueryString() method works.</p>
<p>The post <a href="https://gunnarpeipman.com/ef-core-toquerystring/">EF Core 5.0: Using ToQueryString() method to translate LINQ query to SQL</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Entity Framework Core 5.0 comes with SQL-based brother to ToString() method for LINQ-queries. This method is called ToQueryString() and it returns provider-specific SQL without connecting to database server. In some means it&#8217;s similar to ToTraceString() method of Entity Framework. This blog post shows how ToQueryString() method works.</p>
<p><span id="more-6074"></span></p>
<blockquote>
<p><strong>NB!</strong> At the time of writing this post <a title="Download .NET Core 5.0" href="https://dotnet.microsoft.com/download/dotnet-core/5.0">.NET Core 5.0</a> and EF Core 5.0 are both in Preview and things may change in future versions of EF Core 5.0.</p>
</blockquote>
<p>I created new ASP.NET Core web application project with latest <a title="Download Visual Studio 2019 Preview" href="https://visualstudio.microsoft.com/vs/preview/">Visual Studio 2019 Preview</a> and connected EF Core to one of my existing databases. I added just few entities and primitive DbContext to try out how ToQueryString() <a title="Extension methods in C#" href="https://gunnarpeipman.com/csharp-extension-methods/">extension method</a> works.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">class</span>&nbsp;<span style="color: rgb(43, 145, 175);">Customer</span><br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">Guid</span> Id { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">string</span> Name { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }<br>}<br> <br><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">class</span>&nbsp;<span style="color: rgb(43, 145, 175);">Project</span><br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">Guid</span> Id { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">string</span> Title { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">string</span> ProjectKey { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">Customer</span> Customer { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }<br>}<br> <br><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">class</span>&nbsp;<span style="color: rgb(43, 145, 175);">MyDbContext</span> : <span style="color: rgb(43, 145, 175);">DbContext</span><br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">MyDbContext</span>(<span style="color: rgb(43, 145, 175);">DbContextOptions</span>&lt;<span style="color: rgb(43, 145, 175);">MyDbContext</span>&gt; <span style="color: rgb(31, 55, 127);">options</span>) : <span style="color: blue;">base</span>(<span style="color: rgb(31, 55, 127);">options</span>)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">DbSet</span>&lt;<span style="color: rgb(43, 145, 175);">Customer</span>&gt; Customers { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">DbSet</span>&lt;<span style="color: rgb(43, 145, 175);">Project</span>&gt; Projects { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }<br>}</pre>
<p>I injected my DbContext to HomeController and in Index() action I wrote a query to see what ToQueryString() method returns. I was a bit clever when writing the query – notice how I used variable called prefix in LINQ expression.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">class</span>&nbsp;<span style="color: rgb(43, 145, 175);">HomeController</span> : <span style="color: rgb(43, 145, 175);">Controller</span><br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">private</span>&nbsp;<span style="color: blue;">readonly</span>&nbsp;<span style="color: rgb(43, 145, 175);">MyDbContext</span> _dataContext;<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">HomeController</span>(<span style="color: rgb(43, 145, 175);">MyDbContext</span>&nbsp;<span style="color: rgb(31, 55, 127);">dataContext</span>)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _dataContext = <span style="color: rgb(31, 55, 127);">dataContext</span>;<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">IActionResult</span>&nbsp;<span style="color: rgb(116, 83, 31);">Index</span>()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">prefix</span> = <span style="color: rgb(163, 21, 21);">"A"</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">query</span> = _dataContext.Projects<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">Include</span>(<span style="color: rgb(31, 55, 127);">p</span> =&gt; <span style="color: rgb(31, 55, 127);">p</span>.Customer)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">Where</span>(<span style="color: rgb(31, 55, 127);">p</span> =&gt; <span style="color: rgb(31, 55, 127);">p</span>.Customer.Name.<span style="color: rgb(116, 83, 31);">StartsWith</span>(<span style="color: rgb(31, 55, 127);">prefix</span>))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">OrderBy</span>(<span style="color: rgb(31, 55, 127);">p</span> =&gt; <span style="color: rgb(31, 55, 127);">p</span>.Customer.Name)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">ThenBy</span>(<span style="color: rgb(31, 55, 127);">p</span> =&gt; <span style="color: rgb(31, 55, 127);">p</span>.Title)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">Select</span>(<span style="color: rgb(31, 55, 127);">p</span> =&gt; <span style="color: blue;">new</span> { Project = <span style="color: rgb(31, 55, 127);">p</span>.Title, Customer = <span style="color: rgb(31, 55, 127);">p</span>.Customer.Name });<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">queryString</span> = <span style="color: rgb(31, 55, 127);">query</span>.<span style="color: rgb(116, 83, 31);">ToQueryString</span>();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">result</span> = <span style="color: rgb(31, 55, 127);">query</span>.<span style="color: rgb(116, 83, 31);">FirstOrDefault</span>();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">return</span>&nbsp;<span style="color: rgb(116, 83, 31);">View</span>();<br>&nbsp;&nbsp;&nbsp; }<br>}</pre>
<p>When running the code in debug mode and checking the value of queryString variable we can see nice formatted SQL in Text Visualizer window.</p>
<p align="center"><img decoding="async" width="800" height="394" title="EF Core query as a string in Visual Studio Text Visualizer" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="EF Core query as a string in Visual Studio Text Visualizer" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/03/ef-core-toquerystring.png" border="0"></p>
<p>The best thing is – we can take this SQL with copy and paste to SQL Server Management Studio (SSMS) or some other database tool to investigate the query closer. It’s ready to run without any modifications.</p>
<h3>When ToQueryString() doesn’t work</h3>
<p>There’s a little gotcha with ToQueryString() method – we cannot use it with methods that immediately run SQL query. It gives us valid query for ToList() and ToListAsync() methods but if we call FirstOrDefault() or FirstOrDefaultAsync() method on query then these methods add some more SQL that we cannot see with ToQueryString() method.</p>
<p>Let’s see what SQL is generated when we apply FirstOrDefault() method to query above. The actual query that is sent to database server is here.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">SELECT</span>&nbsp;<span style="color: blue;">TOP</span><span style="color: gray;">(</span>1<span style="color: gray;">)</span> [p]<span style="color: gray;">.</span>[Title] <span style="color: blue;">AS</span> [Project]<span style="color: gray;">,</span> [c]<span style="color: gray;">.</span>[Name] <span style="color: blue;">AS</span> [Customer]<br><span style="color: blue;">FROM</span> [Projects] <span style="color: blue;">AS</span> [p]<br><span style="color: gray;">LEFT</span>&nbsp;<span style="color: gray;">JOIN</span> [Customers] <span style="color: blue;">AS</span> [c] <span style="color: blue;">ON</span> [p]<span style="color: gray;">.</span>[CustomerId] <span style="color: gray;">=</span> [c]<span style="color: gray;">.</span>[Id]<br><span style="color: blue;">WHERE </span><span style="color: gray;">(</span>@__prefix_0 <span style="color: gray;">=</span>&nbsp;<span style="color: red;">N''</span><span style="color: gray;">)</span>&nbsp;<span style="color: gray;">OR</span><span style="color: blue;">&nbsp;</span><span style="color: gray;">(</span>[c]<span style="color: gray;">.</span>[Name] <span style="color: gray;">IS</span>&nbsp;<span style="color: gray;">NOT</span>&nbsp;<span style="color: gray;">NULL</span>&nbsp;<span style="color: gray;">AND</span><span style="color: blue;">&nbsp;</span><span style="color: gray;">(LEFT</span><br><span style="color: gray;">(</span>[c]<span style="color: gray;">.</span>[Name]<span style="color: gray;">,</span>&nbsp;<span style="color: magenta;">LEN</span><span style="color: gray;">(</span>@__prefix_0<span style="color: gray;">))</span>&nbsp;<span style="color: gray;">=</span> @__prefix_0<span style="color: gray;">))</span><br><span style="color: blue;">ORDER</span>&nbsp;<span style="color: blue;">BY</span> [c]<span style="color: gray;">.</span>[Name]<span style="color: gray;">,</span> [p]<span style="color: gray;">.</span>[Title]</pre>
<p>It’s almost the same but there’s TOP(1) after SELECT. The query gets even more different when we apply Count() method instead of FirstOrDefault().</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">SELECT</span>&nbsp;<span style="color: magenta;">COUNT</span><span style="color: gray;">(*)</span><br><span style="color: blue;">FROM</span> [Projects] <span style="color: blue;">AS</span> [p]<br><span style="color: gray;">LEFT</span>&nbsp;<span style="color: gray;">JOIN</span> [Customers] <span style="color: blue;">AS</span> [c] <span style="color: blue;">ON</span> [p]<span style="color: gray;">.</span>[CustomerId] <span style="color: gray;">=</span> [c]<span style="color: gray;">.</span>[Id]<br><span style="color: blue;">WHERE </span><span style="color: gray;">(</span>@__prefix_0 <span style="color: gray;">=</span>&nbsp;<span style="color: red;">N''</span><span style="color: gray;">)</span>&nbsp;<span style="color: gray;">OR</span><span style="color: blue;">&nbsp;</span><span style="color: gray;">(</span>[c]<span style="color: gray;">.</span>[Name] <span style="color: gray;">IS</span>&nbsp;<span style="color: gray;">NOT</span>&nbsp;<span style="color: gray;">NULL</span>&nbsp;<span style="color: gray;">AND</span><span style="color: blue;">&nbsp;</span><span style="color: gray;">(LEFT</span><br><span style="color: gray;">(</span>[c]<span style="color: gray;">.</span>[Name]<span style="color: gray;">,</span>&nbsp;<span style="color: magenta;">LEN</span><span style="color: gray;">(</span>@__prefix_0<span style="color: gray;">))</span>&nbsp;<span style="color: gray;">=</span> @__prefix_0<span style="color: gray;">))</span></pre>
<p>For methods like FirstOrDefault() and Count() we need EF Core query logging. I will cover it in some of my future posts.</p>
<h3>Wrapping up</h3>
<p>ToQueryString() method helps us to see database queries generated by EF Core. It’s new feature in coming EF Core 5.0. We can use this method to get main part of SQL based on LINQ query we wrote. We cannot use ToQueryString() method to find out how query is modified by methods that send query to database – FirstOrDefault(), Count(), etc. For these methods we have to use EF Core logging that is not covered here. ToQueryString() method gives us SQL without making actual request to database server. The SQL we get is ready to run in database management tools for further investigation of generated query.</p>
<p>The post <a href="https://gunnarpeipman.com/ef-core-toquerystring/">EF Core 5.0: Using ToQueryString() method to translate LINQ query to SQL</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gunnarpeipman.com/ef-core-toquerystring/feed/</wfw:commentRss>
			<slash:comments>21</slash:comments>
		
		
			</item>
		<item>
		<title>Using query strings in ASP.NET Core unit tests</title>
		<link>https://gunnarpeipman.com/aspnet-core-unit-test-query-string/</link>
					<comments>https://gunnarpeipman.com/aspnet-core-unit-test-query-string/#comments</comments>
		
		<dc:creator><![CDATA[Gunnar Peipman]]></dc:creator>
		<pubDate>Wed, 18 Mar 2020 04:37:27 +0000</pubDate>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[Testing]]></category>
		<guid isPermaLink="false">https://gunnarpeipman.com/?p=6069</guid>

					<description><![CDATA[<p>Using query string in controller unit tests is actually easy until we don’t need anything more advanced. We can buld up a string with query parameters and go with it. But what if things get more complex and we need encoding or multiple values? Here’s how to build safe query string for ASP.NET COre controller unit tests.</p>
<p>The post <a href="https://gunnarpeipman.com/aspnet-core-unit-test-query-string/">Using query strings in ASP.NET Core unit tests</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Using query string in controller unit tests is actually easy until we don’t need anything more advanced. We can buld up a string with query parameters and go with it. But what if things get more complex and we need encoding or multiple values? Here’s how to build safe query string for ASP.NET COre controller unit tests.</p>
<p><span id="more-6069"></span></p>
<blockquote>
<p><strong>NB!</strong> It is recommended to use action method arguments instead of request query parameters in your controllers. If you have good reason to work with query strings directly then this post will help you.</p>
</blockquote>
<p>Let’s start with quick’n’dirty example where query string is hardcoded.</p>
<pre style="background: white; color: black; font-family: consolas;">[<span style="color: rgb(43, 145, 175);">Fact</span>]<br><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">async</span>&nbsp;<span style="color: rgb(43, 145, 175);">Task</span>&nbsp;<span style="color: rgb(116, 83, 31);">ViewPdf_returns_view_if_application_exists_and_html_was_asked</span>()<br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">model</span> = <span style="color: blue;">new</span>&nbsp;<span style="color: rgb(43, 145, 175);">ApplicationReviewModel</span>();<br>&nbsp;&nbsp;&nbsp; _controller.Request.QueryString = <span style="color: blue;">new</span>&nbsp;<span style="color: rgb(43, 145, 175);">QueryString</span>(<span style="color: rgb(163, 21, 21);">"?showhtml=1&amp;showdoc=0"</span>);<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; _applicationServiceMock.<span style="color: rgb(116, 83, 31);">Setup</span>(<span style="color: rgb(31, 55, 127);">a</span> =&gt; <span style="color: rgb(31, 55, 127);">a</span>.<span style="color: rgb(116, 83, 31);">GetDocumentReview</span>(<span style="color: rgb(43, 145, 175);">It</span>.<span style="color: rgb(116, 83, 31);">IsAny</span>&lt;<span style="color: rgb(43, 145, 175);">Guid</span>&gt;(), <span style="color: rgb(43, 145, 175);">It</span>.<span style="color: rgb(116, 83, 31);">IsAny</span>&lt;<span style="color: blue;">string</span>&gt;()))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">ReturnsAsync</span>(() =&gt; <span style="color: rgb(31, 55, 127);">model</span>);<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">result</span> = <span style="color: blue;">await</span> _controller.<span style="color: rgb(116, 83, 31);">ViewPdf</span>(<span style="color: rgb(43, 145, 175);">Guid</span>.<span style="color: rgb(116, 83, 31);">NewGuid</span>()) <span style="color: blue;">as</span>&nbsp;<span style="color: rgb(43, 145, 175);">ViewResult</span>;<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">Assert</span>.<span style="color: rgb(116, 83, 31);">Same</span>(<span style="color: rgb(31, 55, 127);">model</span>, <span style="color: rgb(31, 55, 127);">result</span>.Model);<br>&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">Assert</span>.<span style="color: rgb(116, 83, 31);">Equal</span>(<span style="color: rgb(163, 21, 21);">"ApplicationPdf"</span>, <span style="color: rgb(31, 55, 127);">result</span>.ViewName);<br>}</pre>
<p>But what if we don’t have primitive query strings and we don’t want to take care of formatting and encoding of query parameters?</p>
<h3>Building query string using QueryCollection</h3>
<p>To build more complex query strings we can use QueryCollection class. It’s a little bit unconveniet beast but it has everything we need to build up query strings from values we have.</p>
<p>Building query string using QueryCollection class needs three steps:</p>
<ol>
<li>Create instance of <strong>StringValues</strong> class. It’s a class that takes either string or array of strings to its constructor. This class holds values for query string parameter.</li>
<li>Create <strong>Dictionary&lt;string,StringValues&gt;</strong> for query parameters. Add query parameter name and instance of StringValues to dictionary. Repeat it for all query parameters.</li>
<li>Create instance of <strong>QueryCollection</strong> and use dictionary as contructor argument.</li>
</ol>
<p>Here’s one unit test to illustrate building of query string using StringValues, dictionary and QueryCollection. Notice QueryCollection is assigned to Query property of Request.</p>
<pre style="background: white; color: black; font-family: consolas;">[<span style="color: rgb(43, 145, 175);">Fact</span>]<br><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">async</span>&nbsp;<span style="color: rgb(43, 145, 175);">Task</span>&nbsp;<span style="color: rgb(116, 83, 31);">ViewPdf_returns_view_if_document_exists_and_html_was_asked</span>()<br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">model</span> = <span style="color: blue;">new</span>&nbsp;<span style="color: rgb(43, 145, 175);">ApplicationReviewModel</span>();<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">dictionary</span> = <span style="color: blue;">new</span>&nbsp;<span style="color: rgb(43, 145, 175);">Dictionary</span>&lt;<span style="color: blue;">string</span>, <span style="color: rgb(43, 145, 175);">StringValues</span>&gt;();<br>&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">dictionary</span>.<span style="color: rgb(116, 83, 31);">Add</span>(<span style="color: rgb(163, 21, 21);">"showhtml"</span>, <span style="color: blue;">new</span>&nbsp;<span style="color: rgb(43, 145, 175);">StringValues</span>(<span style="color: rgb(163, 21, 21);">"1"</span>));<br>&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">dictionary</span>.<span style="color: rgb(116, 83, 31);">Add</span>(<span style="color: rgb(163, 21, 21);">"showtoc"</span>, <span style="color: blue;">new</span>&nbsp;<span style="color: rgb(43, 145, 175);">StringValues</span>(<span style="color: rgb(163, 21, 21);">"0"</span>));<br> <br>&nbsp;&nbsp;&nbsp; _controller.Request.Query = <span style="color: blue;">new</span>&nbsp;<span style="color: rgb(43, 145, 175);">QueryCollection</span>(<span style="color: rgb(31, 55, 127);">dictionary</span>);<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; _applicationServiceMock.Setup(<span style="color: rgb(31, 55, 127);">a</span> =&gt; <span style="color: rgb(31, 55, 127);">a</span>.GetDocumentReview(<span style="color: rgb(43, 145, 175);">It</span>.<span style="color: rgb(116, 83, 31);">IsAny</span>&lt;<span style="color: rgb(43, 145, 175);">Guid</span>&gt;(), <span style="color: rgb(43, 145, 175);">It</span>.<span style="color: rgb(116, 83, 31);">IsAny</span>&lt;<span style="color: blue;">string</span>&gt;()))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .ReturnsAsync(() =&gt; <span style="color: rgb(31, 55, 127);">model</span>);<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">result</span> = <span style="color: blue;">await</span> _controller.<span style="color: rgb(116, 83, 31);">ViewPdf</span>(<span style="color: rgb(43, 145, 175);">Guid</span>.<span style="color: rgb(116, 83, 31);">NewGuid</span>()) <span style="color: blue;">as</span>&nbsp;<span style="color: rgb(43, 145, 175);">ViewResult</span>;<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">Assert</span>.<span style="color: rgb(116, 83, 31);">Same</span>(<span style="color: rgb(31, 55, 127);">model</span>, <span style="color: rgb(31, 55, 127);">result</span>.Model);<br>&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">Assert</span>.<span style="color: rgb(116, 83, 31);">Equal</span>(<span style="color: rgb(163, 21, 21);">"ApplicationPdf"</span>, <span style="color: rgb(31, 55, 127);">result</span>.ViewName);<br>}</pre>
<p>Let’s modify this test a little bit and add query parameter with multiple values.</p>
<pre style="background: white; color: black; font-family: consolas;">[<span style="color: rgb(43, 145, 175);">Fact</span>]<br><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">async</span>&nbsp;<span style="color: rgb(43, 145, 175);">Task</span>&nbsp;<span style="color: rgb(116, 83, 31);">ViewPdf_returns_view_if_document_exists_and_html_was_asked</span>()<br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">model</span> = <span style="color: blue;">new</span>&nbsp;<span style="color: rgb(43, 145, 175);">ApplicationReviewModel</span>();<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">dictionary</span> = <span style="color: blue;">new</span>&nbsp;<span style="color: rgb(43, 145, 175);">Dictionary</span>&lt;<span style="color: blue;">string</span>, <span style="color: rgb(43, 145, 175);">StringValues</span>&gt;();<br>&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">dictionary</span>.<span style="color: rgb(116, 83, 31);">Add</span>(<span style="color: rgb(163, 21, 21);">"showhtml"</span>, <span style="color: blue;">new</span>&nbsp;<span style="color: rgb(43, 145, 175);">StringValues</span>(<span style="color: rgb(163, 21, 21);">"1"</span>));<br>&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">dictionary</span>.<span style="color: rgb(116, 83, 31);">Add</span>(<span style="color: rgb(163, 21, 21);">"showtoc"</span>, <span style="color: blue;">new</span>&nbsp;<span style="color: rgb(43, 145, 175);">StringValues</span>(<span style="color: rgb(163, 21, 21);">"0"</span>));<br>&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">dictionary</span>.<span style="color: rgb(116, 83, 31);">Add</span>(<span style="color: rgb(163, 21, 21);">"showpages"</span>, <span style="color: blue;">new</span>&nbsp;<span style="color: rgb(43, 145, 175);">StringValues</span>(<span style="color: blue;">new</span>[] { <span style="color: rgb(163, 21, 21);">"1"</span>, <span style="color: rgb(163, 21, 21);">"3"</span> }));<br> <br>&nbsp;&nbsp;&nbsp; _controller.Request.Query = <span style="color: blue;">new</span>&nbsp;<span style="color: rgb(43, 145, 175);">QueryCollection</span>(<span style="color: rgb(31, 55, 127);">dictionary</span>);<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; _applicationServiceMock.<span style="color: rgb(116, 83, 31);">Setup</span>(<span style="color: rgb(31, 55, 127);">a</span> =&gt; <span style="color: rgb(31, 55, 127);">a</span>.<span style="color: rgb(116, 83, 31);">GetDocumentReview</span>(<span style="color: rgb(43, 145, 175);">It</span>.<span style="color: rgb(116, 83, 31);">IsAny</span>&lt;<span style="color: rgb(43, 145, 175);">Guid</span>&gt;(), <span style="color: rgb(43, 145, 175);">It</span>.<span style="color: rgb(116, 83, 31);">IsAny</span>&lt;<span style="color: blue;">string</span>&gt;()))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">ReturnsAsync</span>(() =&gt; <span style="color: rgb(31, 55, 127);">model</span>);<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">result</span> = <span style="color: blue;">await</span> _controller.<span style="color: rgb(116, 83, 31);">ViewPdf</span>(<span style="color: rgb(43, 145, 175);">Guid</span>.<span style="color: rgb(116, 83, 31);">NewGuid</span>()) <span style="color: blue;">as</span>&nbsp;<span style="color: rgb(43, 145, 175);">ViewResult</span>;<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">Assert</span>.<span style="color: rgb(116, 83, 31);">Same</span>(<span style="color: rgb(31, 55, 127);">model</span>, <span style="color: rgb(31, 55, 127);">result</span>.Model);<br>&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">Assert</span>.<span style="color: rgb(116, 83, 31);">Equal</span>(<span style="color: rgb(163, 21, 21);">"ApplicationPdf"</span>, <span style="color: rgb(31, 55, 127);">result</span>.ViewName);<br>}</pre>
<p>Here’s the resulting query string in red box.</p>
<p align="center"><a href="https://static.gunnarpeipman.com/wp-content/uploads/2020/03/aspnet-core-controller-test-querystring-multivalue.png"><img decoding="async" width="1600" height="817" title="Multi-valued query string parameter in ASP.NET Core unit test" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="Multi-valued query string parameter in ASP.NET Core unit test" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/03/aspnet-core-controller-test-querystring-multivalue_thumb.png" border="0"></a></p>
<p>If query parameter has value that needs encoding then encoding is done automatically. We don’t have to worry about it. We just add parameters and their values and ASP.NET Core takes care of everything else.</p>
<h3>Wrapping up</h3>
<p>When unit testing ASP.NET Core controller actions that read query strings from request we can use QueryString class. It’s easy but we have to provide strictly correct query string. When using StringValues, dictionary and QueryCollection class we have to write more code. Luckily we don’t have to write ugly or too long code and all dirty work on building the final query string is done by ASP.NET Core.</p>
<p>The post <a href="https://gunnarpeipman.com/aspnet-core-unit-test-query-string/">Using query strings in ASP.NET Core unit tests</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gunnarpeipman.com/aspnet-core-unit-test-query-string/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
		<item>
		<title>Updating SQL Azure database using Visual Studio database project and Azure DevOps</title>
		<link>https://gunnarpeipman.com/visual-studio-database-project-azure-devops/</link>
					<comments>https://gunnarpeipman.com/visual-studio-database-project-azure-devops/#comments</comments>
		
		<dc:creator><![CDATA[Gunnar Peipman]]></dc:creator>
		<pubDate>Tue, 10 Mar 2020 06:00:17 +0000</pubDate>
				<category><![CDATA[Azure]]></category>
		<category><![CDATA[Data platform]]></category>
		<category><![CDATA[Visual Studio]]></category>
		<guid isPermaLink="false">https://gunnarpeipman.com/?p=6063</guid>

					<description><![CDATA[<p>Visual Studio database projects have been one of my important tools since Visual Studio 2010. Database projects were not easy to use with build servers ten years ago. Today things are different. It’s super easy to use database projects to update staging and live databases from Azure build and release pipelines. This blog post shows how to do it.</p>
<p>The post <a href="https://gunnarpeipman.com/visual-studio-database-project-azure-devops/">Updating SQL Azure database using Visual Studio database project and Azure DevOps</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Visual Studio database projects have been one of my important tools since Visual Studio 2010. Database projects were not easy to use with build servers ten years ago. Today things are different. It’s super easy to use database projects to update staging and live databases from Azure build and release pipelines. This blog post shows how to do it.</p>
<p><span id="more-6063"></span></p>
<h3>Azure pipelines with database update</h3>
<p>Suppose we have solution with SQL Server database project and we want to use schema compare feature to update production database when new version of application is deployed. We don’t want to update database directly from Visual Studio but using Azure DevOps release pipelines. Here’s the pipeline I’m using in one of my projects. Blue blocks are steps in build pipeline and orange blocks are steps in release pipeline of Azure DevOps.</p>
<p align="center"><img decoding="async" width="800" height="325" title="Azure DevOps build and release pipeline with database tasks" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="Azure DevOps build and release pipeline with database tasks" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/03/azure-devops-database-build-release-pipeline.png" border="0"></p>
<p>I don’t cover all steps of building Azure DevOps build and release pipelines as these topics are already covered thousands of times by different pages in internet. </p>
<h3>Comparing schemas</h3>
<p>SQL Server database projects make database schema versioned. We have history of database structure changes in Github or some other source code repository. It’s easy to take a look at history and see what changes and when were made to database. But there’s more.</p>
<p>If we change development database we can use schema compare feature of Visual Studio to compare changes between database and schema project.</p>
<p align="center"><img decoding="async" width="800" height="567" title="Comparing dev database schema to database project" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="Comparing dev database schema to database project" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/03/visual-studio-2019-schema-comparison.png" border="0"></p>
<p>Same way we can compare schema project to production database and if needed we can update database with one button click. That’s nice but it’s manual work and doesn’t fit well into automated release topic.</p>
<h3>How to build database project on Azure DevOps</h3>
<p>We can build database projects on Azure DevOps. As a result we get DACPAC file with database structure. If everything is build using MSBuild then things should be easy. But I had a problematic situation – I can’t build database project together with other projects as all other projects use .NET Core 3.0 and .NET Standard 2.1. .NET Core tooling today doesn’t support build database projects. It doesn’t mean we cannot build database projects at all when .NET Core projects are involved.</p>
<p>On Azure DevOps I solved the problem by adding MSBuild task to build pipeline. .NET Core tooling skips database project and MSBuild task skips .NET Core projects. So, both types of projects are together and at same time separated.</p>
<p>I configured it to build only schema project.</p>
<p align="center"><a href="https://static.gunnarpeipman.com/wp-content/uploads/2020/03/msbuild-sqlproj.png"><img decoding="async" width="907" height="596" title="Azure DevOps MSBuild task to build database project" style="display: inline; background-image: none;" alt="Azure DevOps MSBuild task to build database project" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/03/msbuild-sqlproj_thumb.png" border="0"></a></p>
<p>Next thing I had to do was to copy resulting DACPAC file to build artifacts drop folder. I used File Copy task for this.</p>
<p align="center"><a href="https://static.gunnarpeipman.com/wp-content/uploads/2020/03/azure-devops-copy-dacpac.png"><img decoding="async" width="904" height="594" title="Azure DevOps copy files task" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="Azure DevOps copy files task" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/03/azure-devops-copy-dacpac_thumb.png" border="0"></a></p>
<p>Although file location in drop folder is far from perfect, the DACPAC file is there and available to release pipeline.</p>
<h3>Deploying changes to Azure SQL</h3>
<p>I have release pipeline that is run manually. It updates database and deploys new versions of web applications to Azure App Service. Updating database is first step in the release pipeline. There’s special pipeline step by Microsoft to update Azure SQL database. Just add it to pipeline, fill configuration parameters and you are good to go.</p>
<p align="center"><a href="https://static.gunnarpeipman.com/wp-content/uploads/2020/03/azure-devops-sql-database-deployment.png"><img decoding="async" width="917" height="1178" title="AzureDev Ops database deployment task" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="AzureDev Ops database deployment task" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/03/azure-devops-sql-database-deployment_thumb.png" border="0"></a></p>
<p>Database update is done based on DACPAC file built in previous section. All we have to do is to organize DACPAC file to Azure SQL Database deployment step and magic happens automatically.</p>
<h3>Wrapping up</h3>
<p>Visual Studio database projects are one of my main tools since Visual Studio 2010. Over times tooling has changed and improved. Today we can use database projects also in Azure DevOps build and release pipelines to automatically update Azure SQL databases. Although most of new web applications are built on ASP.NET Core, I was still able to use MSBuild on Azure DevOps to make database project build independent from web applications. Deploying update to live database is matter of just one database deployment task that is easy to set up and configure.</p>
<h3>References</h3>
<ul>
<li><a title="Visual Studio database projects" href="https://gunnarpeipman.com/visual-studio-2010-database-projects/">Visual Studio database projects</a> (Gunnar Peipman)</li>
<li><a title="Using Visual Studio database projects in real life" href="https://gunnarpeipman.com/using-visual-studio-database-projects-in-real-life/">Using Visual Studio database projects in real life</a> (Gunnar Peipman)</li>
</ul>
<p>The post <a href="https://gunnarpeipman.com/visual-studio-database-project-azure-devops/">Updating SQL Azure database using Visual Studio database project and Azure DevOps</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gunnarpeipman.com/visual-studio-database-project-azure-devops/feed/</wfw:commentRss>
			<slash:comments>9</slash:comments>
		
		
			</item>
		<item>
		<title>Creating storage accounts and blob containers using Azure fluent API-s</title>
		<link>https://gunnarpeipman.com/azure-storage-fluent-api/</link>
					<comments>https://gunnarpeipman.com/azure-storage-fluent-api/#comments</comments>
		
		<dc:creator><![CDATA[Gunnar Peipman]]></dc:creator>
		<pubDate>Wed, 04 Mar 2020 05:28:27 +0000</pubDate>
				<category><![CDATA[Azure]]></category>
		<guid isPermaLink="false">https://gunnarpeipman.com/?p=6051</guid>

					<description><![CDATA[<p>Using Azure fluent API-s it is easy to create storage accounts and blob containers. After experimenting with fluent API of Azure storage I found it to be good match for multitenant web applications where tenant files are held on Azure blob storage. I was surprised how clean and short code I got using fluent API. Here’s my overview of fluent API for Azure storage with some code samples I wrote.</p>
<p>The post <a href="https://gunnarpeipman.com/azure-storage-fluent-api/">Creating storage accounts and blob containers using Azure fluent API-s</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>
Using Azure fluent API-s it is easy to create storage accounts and blob containers. After experimenting with fluent API of Azure storage I found it to be good match for <a title="Multi-tenant ASP.NET Core" href="https://gunnarpeipman.com/series/multi-tenant-aspnet-core/">multitenant web applications</a> where tenant files are held on Azure blob storage. I was surprised how clean and short code I got using fluent API. Here’s my overview of fluent API for Azure storage with some code samples I wrote.</p>
<p><span id="more-6051"></span></p>
<h3>Getting started</h3>
<p>Before getting to code we need Azure portal account and some configuration parameters:</p>
<ul>
<li><strong>TenantId</strong> – ID of Azure AD tenant. Open Azure AD settings in Azure portal to get tenant ID.</li>
<li><strong>ClientId and ClientSecret</strong> – these are for service principal (or account) we want to use for accessing Azure services. To set up service principal please jump to Azure documentation page <a title="How to: Use the portal to create an Azure AD application and service principal that can access resources" href="https://docs.microsoft.com/en-us/azure/active-directory/develop/howto-create-service-principal-portal">How to: Use the portal to create an Azure AD application and service principal that can access resources</a>.</li>
<li><strong>SubscriptionId</strong> – ID of Azure subscription where we want to create storage accounts. Open Subscriptions in Azure portal to get subscription ID.</li>
<li><strong>ResourceGroup</strong> – name of resource group under what storage accounts are created. Make sure the resource group exists already or create new one if you need.</li>
</ul>
<p>With settings ready it’s time to get into code.</p>
<h3>Fluent syntax for Azure blob storage</h3>
<p>There are few important things to know before implementing class to create storage accounts. Fluent syntax for Azure services uses IAzure interface as a bridge head to row of fluent method calls. When building IAzure instance we need to provide all configuration parameters mentioned above.</p>
<p>Here’s the example. Azure.Configure() method starts the row of fluent configuring methods to build up client class we will use later. </p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">principalLogIn</span> = <span style="color: blue;">new</span>&nbsp;<span style="color: rgb(43, 145, 175);">ServicePrincipalLoginInformation</span>();<br><span style="color: rgb(31, 55, 127);">principalLogIn</span>.ClientId = ClientId;<br><span style="color: rgb(31, 55, 127);">principalLogIn</span>.ClientSecret = ClientSecret;<br> <br><span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">environment</span> = <span style="color: rgb(43, 145, 175);">AzureEnvironment</span>.AzureGlobalCloud;<br><span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">credentials</span> = <span style="color: blue;">new</span>&nbsp;<span style="color: rgb(43, 145, 175);">AzureCredentials</span>(<span style="color: rgb(31, 55, 127);">principalLogIn</span>, TenantId, <span style="color: rgb(31, 55, 127);">environment</span>);<br> <br>_azure = <span style="color: rgb(43, 145, 175);">Azure</span>.<span style="color: rgb(116, 83, 31);">Configure</span>()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">WithLogLevel</span>(<span style="color: rgb(43, 145, 175);">HttpLoggingDelegatingHandler</span>.<span style="color: rgb(43, 145, 175);">Level</span>.Basic)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">Authenticate</span>(<span style="color: rgb(31, 55, 127);">credentials</span>)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">WithSubscription</span>(SubscriptionId);</pre>
<p>To create blob storage account we will use initialized Azure client like shown in the following example.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">await</span> _azure.StorageAccounts.<span style="color: rgb(116, 83, 31);">Define</span>(<span style="color: rgb(31, 55, 127);">accountName</span>)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">WithRegion</span>(<span style="color: rgb(43, 145, 175);">Region</span>.EuropeWest)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">WithExistingResourceGroup</span>(ResourceGroup)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">WithAccessFromAllNetworks</span>()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">WithGeneralPurposeAccountKindV2</span>()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">WithOnlyHttpsTraffic</span>()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">WithSku</span>(<span style="color: rgb(43, 145, 175);">StorageAccountSkuType</span>.Standard_LRS)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">CreateAsync</span>();</pre>
<p>Although fluent methods shown above are just few of those provided, notice how new account is defined using clear and readable fluent methods that specify important aspects of account. Finally CreateAsync() method is called and then new storage account is created.</p>
<p>Similar fluent API-s are available also for some other Azure services and in big part they follow the same idea as shown here with Azure storage account.</p>
<h3>Creating storage account and blob containers</h3>
<p>It’s time to get to code and build something real. Let’s start with NuGet packages we need in our project:</p>
<ul>
<li>Microsoft.Azure.Management.Fluent</li>
<li>Microsoft.Azure.Management.Storage.Fluent</li>
<li>WindowsAzure.Storage (if you want to manage blobs in containers)</li>
</ul>
<p>To try fluent storage API-s out, it doesn’t matter much what kind of application to create – be it console or web application or maybe Azure Function. I decided to go with web application as I’m building demo tenants manager application for some of my blog posts.</p>
<p>When new tenant is created we need to create also storage account for it and add blob containers that multitenant application expects to exist. Tenant can be created using long spaghetti code but I don’t like chaos and therefore I want more intelligent approach. Let’s try to write simple client class for creating storage accounts for tenants.</p>
<p>I start with simple interface.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">interface</span>&nbsp;<span style="color: rgb(43, 145, 175);">IStorageManager</span><br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">Task</span>&nbsp;<span style="color: rgb(116, 83, 31);">CreateAccountWithFolders</span>(<span style="color: blue;">string</span>&nbsp;<span style="color: rgb(31, 55, 127);">name</span>, <span style="color: blue;">params</span>&nbsp;<span style="color: blue;">string</span>[] <span style="color: rgb(31, 55, 127);">container</span>);<br>}</pre>
<p>CreateAccountWithFolders() method takes new storage account name and array of container names that must be created with account. For this blog post this minimalistic interface is enough.</p>
<p>Let’s add a class called AzureBlobStorageManager to our solution. Here are namespaces used in this class.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">using</span> System;<br><span style="color: blue;">using</span> System.Threading.Tasks;<br><span style="color: blue;">using</span> Microsoft.Azure.Management.Fluent;<br><span style="color: blue;">using</span> Microsoft.Azure.Management.ResourceManager.Fluent;<br><span style="color: blue;">using</span> Microsoft.Azure.Management.ResourceManager.Fluent.Authentication;<br><span style="color: blue;">using</span> Microsoft.Azure.Management.ResourceManager.Fluent.Core;<br><span style="color: blue;">using</span> Microsoft.Azure.Management.Storage.Fluent;<br><span style="color: blue;">using</span> Microsoft.Azure.Management.Storage.Fluent.Models;</pre>
<p>Class to create Azure storage accounts is here. Notice you need all configuration parameter values now to make the class actually work.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">class</span>&nbsp;<span style="color: rgb(43, 145, 175);">AzureBlobStorageManager</span> : <span style="color: rgb(43, 145, 175);">IStorageManager</span><br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">private</span>&nbsp;<span style="color: blue;">const</span>&nbsp;<span style="color: blue;">string</span> TenantId = <span style="color: rgb(163, 21, 21);">"4dcea3b0-b401-4b25-af70-971068b99d1c"</span>;<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">private</span>&nbsp;<span style="color: blue;">const</span>&nbsp;<span style="color: blue;">string</span> ClientId = <span style="color: rgb(163, 21, 21);">"9cce9aed-69eb-45af-9bed-a5d7e403019f"</span>;<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">private</span>&nbsp;<span style="color: blue;">const</span>&nbsp;<span style="color: blue;">string</span> ClientSecret = <span style="color: rgb(163, 21, 21);">"74d99bc5-e239-4308-ba15-e3e2acdb7fcf"</span>;<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">private</span>&nbsp;<span style="color: blue;">const</span>&nbsp;<span style="color: blue;">string</span> SubscriptionId = <span style="color: rgb(163, 21, 21);">"6ca601d2-417f-4fa4-ae19-cd465102f8de"</span>;<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">private</span>&nbsp;<span style="color: blue;">const</span>&nbsp;<span style="color: blue;">string</span> ResourceGroup = <span style="color: rgb(163, 21, 21);">"TestResourceGroup"</span>;<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">private</span>&nbsp;<span style="color: blue;">readonly</span>&nbsp;<span style="color: rgb(43, 145, 175);">IAzure</span> _azure;<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">AzureBlobStorageManager</span>()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">principalLogIn</span> = <span style="color: blue;">new</span>&nbsp;<span style="color: rgb(43, 145, 175);">ServicePrincipalLoginInformation</span>();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">principalLogIn</span>.ClientId = ClientId;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">principalLogIn</span>.ClientSecret = ClientSecret;<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">environment</span> = <span style="color: rgb(43, 145, 175);">AzureEnvironment</span>.AzureGlobalCloud;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">credentials</span> = <span style="color: blue;">new</span>&nbsp;<span style="color: rgb(43, 145, 175);">AzureCredentials</span>(<span style="color: rgb(31, 55, 127);">principalLogIn</span>, TenantId, <span style="color: rgb(31, 55, 127);">environment</span>);<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _azure = <span style="color: rgb(43, 145, 175);">Azure</span>.<span style="color: rgb(116, 83, 31);">Configure</span>()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">WithLogLevel</span>(<span style="color: rgb(43, 145, 175);">HttpLoggingDelegatingHandler</span>.<span style="color: rgb(43, 145, 175);">Level</span>.Basic)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">Authenticate</span>(<span style="color: rgb(31, 55, 127);">credentials</span>)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">WithSubscription</span>(SubscriptionId);<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">async</span>&nbsp;<span style="color: rgb(43, 145, 175);">Task</span>&nbsp;<span style="color: rgb(116, 83, 31);">CreateAccountWithFolders</span>(<span style="color: blue;">string</span>&nbsp;<span style="color: rgb(31, 55, 127);">accountName</span>, <span style="color: blue;">params</span>&nbsp;<span style="color: blue;">string</span>[] <span style="color: rgb(31, 55, 127);">containerNames</span>)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">availabilityResult</span> = <span style="color: blue;">await</span> _azure.StorageAccounts.<span style="color: rgb(116, 83, 31);">CheckNameAvailabilityAsync</span>(<span style="color: rgb(31, 55, 127);">accountName</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">if</span>(!<span style="color: rgb(31, 55, 127);">availabilityResult</span>.IsAvailable.Value)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">throw</span>&nbsp;<span style="color: blue;">new</span>&nbsp;<span style="color: rgb(43, 145, 175);">Exception</span>(<span style="color: rgb(163, 21, 21);">"Account name is not available"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">account</span> = <span style="color: blue;">await</span> _azure.StorageAccounts.<span style="color: rgb(116, 83, 31);">Define</span>(<span style="color: rgb(31, 55, 127);">accountName</span>)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">WithRegion</span>(<span style="color: rgb(43, 145, 175);">Region</span>.EuropeWest)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">WithExistingResourceGroup</span>(ResourceGroup)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">WithAccessFromAllNetworks</span>()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">WithGeneralPurposeAccountKindV2</span>()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">WithOnlyHttpsTraffic</span>()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">WithSku</span>(<span style="color: rgb(43, 145, 175);">StorageAccountSkuType</span>.Standard_LRS)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">CreateAsync</span>();<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">containers</span> = <span style="color: rgb(31, 55, 127);">account</span>.Manager.BlobContainers;<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">foreach</span> (<span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">containerName</span>&nbsp;<span style="color: rgb(143, 8, 196);">in</span>&nbsp;<span style="color: rgb(31, 55, 127);">containerNames</span>)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">await</span>&nbsp;<span style="color: rgb(31, 55, 127);">containers</span>.<span style="color: rgb(116, 83, 31);">DefineContainer</span>(<span style="color: rgb(31, 55, 127);">containerName</span>)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">WithExistingBlobService</span>(ResourceGroup, <span style="color: rgb(31, 55, 127);">accountName</span>)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">WithPublicAccess</span>(<span style="color: rgb(43, 145, 175);">PublicAccess</span>.None)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">CreateAsync</span>();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>}</pre>
<p>For web applications we can register this class in framework-level dependency injection to inject it to controllers. This is how ConfigureServices() method of my Starpup class looks like.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">void</span>&nbsp;<span style="color: rgb(116, 83, 31);">ConfigureServices</span>(<span style="color: rgb(43, 145, 175);">IServiceCollection</span>&nbsp;<span style="color: rgb(31, 55, 127);">services</span>)<br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">services</span>.<span style="color: rgb(116, 83, 31);">AddControllersWithViews</span>();<br>&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">services</span>.<span style="color: rgb(116, 83, 31);">AddScoped</span>&lt;<span style="color: rgb(43, 145, 175);">IStorageManager</span>, <span style="color: rgb(43, 145, 175);">AzureBlobStorageManager</span>&gt;();<br>}</pre>
<p>And here is the minimalistic example of controller that makes use of IStorageManager.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">class</span>&nbsp;<span style="color: rgb(43, 145, 175);">HomeController</span> : <span style="color: rgb(43, 145, 175);">Controller</span><br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">private</span>&nbsp;<span style="color: blue;">readonly</span>&nbsp;<span style="color: rgb(43, 145, 175);">IStorageManager</span> _storageManager;<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">HomeController</span>(<span style="color: rgb(43, 145, 175);">IStorageManager</span>&nbsp;<span style="color: rgb(31, 55, 127);">storageManager</span>)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _storageManager = <span style="color: rgb(31, 55, 127);">storageManager</span>;<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: green;">// ...</span><br> <br>&nbsp;&nbsp;&nbsp; [<span style="color: rgb(43, 145, 175);">HttpPost</span>]<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">async</span>&nbsp;<span style="color: rgb(43, 145, 175);">Task</span>&lt;<span style="color: rgb(43, 145, 175);">IActionResult</span>&gt; <span style="color: rgb(116, 83, 31);">Edit</span>(<span style="color: blue;">string</span>&nbsp;<span style="color: rgb(31, 55, 127);">account</span>)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">await</span> _storageManager.<span style="color: rgb(116, 83, 31);">CreateAccountWithFolders</span>(<span style="color: rgb(31, 55, 127);">account</span>, <span style="color: rgb(163, 21, 21);">"images"</span>, <span style="color: rgb(163, 21, 21);">"documents"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">return</span>&nbsp;<span style="color: rgb(116, 83, 31);">View</span>();<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: green;">// ...</span><br>}</pre>
<p>Using the code above I created new storage account with two blob containers – documents and images.</p>
<p align="center"><img decoding="async" width="802" height="355" title="Azure storage account and blob containers" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="Azure storage account and blob containers" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/03/azure-blob-storage-containers.png" border="0"></p>
<p>In practice we don’t get away so easily as we need to read out storage connection string after account is created and probably we also need SAS key for another services that access files on Azure storage. But with simple client class shown here you have good starting point for your own Azure storage management client.</p>
<h3>Wrapping up</h3>
<p>Although it was just an experiment to see how fluent API for Azure storage works, it was good find. When creating Azure storage accounts in code it’s important to have a good overview of features that new account will have. With fluent API-s I was able to write the code that looks like specification defining new account to be created. Good news is that there are similar fluent API-s available for other Azure services too.</p>
<p>The post <a href="https://gunnarpeipman.com/azure-storage-fluent-api/">Creating storage accounts and blob containers using Azure fluent API-s</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gunnarpeipman.com/azure-storage-fluent-api/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
		<item>
		<title>MSSQL data and log files on Azure blob storage</title>
		<link>https://gunnarpeipman.com/mssql-files-on-azure-blob-storage/</link>
					<comments>https://gunnarpeipman.com/mssql-files-on-azure-blob-storage/#comments</comments>
		
		<dc:creator><![CDATA[Gunnar Peipman]]></dc:creator>
		<pubDate>Tue, 03 Mar 2020 07:52:51 +0000</pubDate>
				<category><![CDATA[Azure]]></category>
		<category><![CDATA[Data platform]]></category>
		<guid isPermaLink="false">https://gunnarpeipman.com/?p=6048</guid>

					<description><![CDATA[<p>I discovered lately one killer feature of SQL Server – keeping data and log files on Azure blob storage. There are scenarios where we may want to go with blob storage instead of buying and building up our own stable and reliable storage. This blog post introduces how MSSQL data and log files work on Azure blob storage.</p>
<p>The post <a href="https://gunnarpeipman.com/mssql-files-on-azure-blob-storage/">MSSQL data and log files on Azure blob storage</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>I discovered lately one killer feature of SQL Server – keeping data and log files on Azure blob storage. There are scenarios where we may want to go with blob storage instead of buying and building up our own stable and reliable storage. This blog post introduces how MSSQL data and log files work on Azure blob storage.</p>
<p><span id="more-6048"></span></p>
<h3>Why MSSQL data and log files on Azure blob storage?</h3>
<p>There are multiple reasons why one may want to keep MSSQL data and log files on Azure blob storage:</p>
<ul>
<li><strong>Ownership and maintenance costs</strong> – Azure blob storage is stable and reliable cloud storage service and those who don’t want to build up their own storage solution may decide to benefit from Azure blob storage as MSSQL data files location.</li>
<li><strong>High-availability</strong> – it’s possible to configure multiple MSSQL virtual machines to use same data files and when one machine crashes then the other takes over withing few minutes. There’s no need to restore data as the latest state is already available on cloud.</li>
<li><strong>SaaS solution</strong> – SaaS providers who host MSSQL on virtual machines may find it more convenient for maintenance if data and log files are on Azure blob storage.</li>
</ul>
<p>Now let’s try to set up a database to see how data and log files on blob storage work.</p>
<h3>Generating shared access signature (SAS) key</h3>
<p>First there must Azure storage account with at least one blob storage container where data and log files are held. We need shared access signature (SAS) key for MSSQL to be able to communicate with blob storage. SAS key can be generated from Azure portal.</p>
<p align="center"><img decoding="async" width="802" height="677" title="Generating SAS key" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="Generating SAS key" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/03/azure-blob-storage-sas.png" border="0"></p>
<p>SAS key can also be generated using <a title="Azure Storage Explorer" href="https://azure.microsoft.com/en-us/features/storage-explorer/">Azure Storage Explorer</a> – the convenient tool for managing Azure storage.<br />
It’s free and I’m using it practically every day. Of course, those who are strong on PowerShell can also use PowerShell.</p>
<h3>Creating cloud credential </h3>
<p>Before creating databases and data files we need to create credential for MSSQL. It’s done with the following simple command.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">CREATE</span>&nbsp;<span style="color: blue;">CREDENTIAL</span> [https://example.blob.core.windows.net/data]<br><span style="color: blue;">WITH</span>&nbsp;<span style="color: blue;">IDENTITY</span><span style="color: gray;">=</span><span style="color: red;">'SHARED ACCESS SIGNATURE'</span><span style="color: gray;">,</span><br><span style="color: blue;">SECRET</span>&nbsp;<span style="color: gray;">=</span>&nbsp;<span style="color: red;">'&lt;your SAS key&gt;'</span></pre>
<p>Make sure you also use correct URL to blob storage container where data files will be held.</p>
<h3>Creating database to Azure blob storage</h3>
<p>Creating database on Azure blob storage is simple. We use familiar CREATE DATABASE command with file locations.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">CREATE</span>&nbsp;<span style="color: blue;">DATABASE</span> test<br><span style="color: blue;">ON</span>&nbsp; <br><span style="color: gray;">(</span>&nbsp;<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">NAME</span>&nbsp;<span style="color: gray;">=</span> test_data<span style="color: gray;">,</span>&nbsp; <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">FILENAME</span>&nbsp;<span style="color: gray;">=</span>&nbsp;<span style="color: red;">'https://sample.blob.core.windows.net/data/TestData.mdf'</span>&nbsp;<br><span style="color: gray;">)</span>&nbsp; <br><span style="color: magenta;">LOG</span>&nbsp;<span style="color: blue;">ON</span>&nbsp; <br><span style="color: gray;">(</span>&nbsp;<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">NAME</span>&nbsp;<span style="color: gray;">=</span> test_log<span style="color: gray;">,</span>&nbsp; <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">FILENAME</span>&nbsp;<span style="color: gray;">=</span>&nbsp; <span style="color: red;">'https://testdb.blob.core.windows.net/data/TestLog.ldf'</span><br><span style="color: gray;">)</span></pre>
<p>It’s also possible to add new database file to existing database for tables we want to be available on cloud. Here are files of my demo database for my first linked servers blog post <a title="Querying MySQL from SQL Server using linked server" href="https://gunnarpeipman.com/mssql-mysql-linked-server/">Querying MySQL from SQL Server using linked server</a>. Database file OnBlobStorage1 is held on Azure blog storage.</p>
<p align="center"><img decoding="async" width="788" height="593" title="MSSQL data file on Azure blob storage" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="MSSQL data file on Azure blob storage" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/03/mssql-data-file-on-azure-blob-storage.png" border="0"></p>
<p>Let’s see now how things work out.</p>
<h3>My experience</h3>
<p>There are not many concerns when MSSQL is hosted in same data center. There are fast cable connections between servers and services are maintained by well trained personnel. I wanted to try out a hybrid scenario – in-prem MSSQL and data file on cloud. My main concern was performance. Considering that MSSQL is located in Estonia and data file is located in Amsterdam – it’s approximately 1500 km over the air or 2000 km on the land – then what are the penalties? </p>
<p>Experiments with small databases went well. I didn’t noticed any delays that should affect web application consuming the database. I also tried things out with database of little bit over 2GB. I hosted data files and logs to cloud just to see how things works out. After getting data files to cloud I started application on my dev box to see what happens.</p>
<p align="center"><img decoding="async" width="740" height="300" title="Ingress and egress of blob storage with MSSQL data files" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="Ingress and egress of blob storage with MSSQL data files" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/03/mssql-azure-blob-storage-egress-ingress.png" border="0"></p>
<p>Few notes about those charts:</p>
<ol>
<li>Incoming data (ingress) made high peak when I uploaded data files to blob storage.</li>
<li>Outgoing data (egress) made high peak when I took database online and started web application.</li>
<li>When browsing around in web application there were some small peaks on egress chart – usually around 20MB.</li>
</ol>
<p>If MSSQL is configured correctly then there should not be much traffic between MSSQL and Azure blob storage. Of course, if data is added, updated or deleted then there will be additional traffic. Anyway I didn’t noticed any lags or other references to possible bottlenecks with data files on Azure.</p>
<h3>Wrapping up</h3>
<p>Although in my mind I was ready for surprises like huge latency and unexpected traffic between MSSQL and Azure blob storage, my experiment went very smooth and well. My local MSSQL has enough resources to run 2GB database and probably this is why there was not much traffic. Also I didn’t faced any bad delays although I made experiments on regular home connection that is not in perfect shape all the time. When planning to use Azure blob storage for MSSQL make some homework on validate if service works well for you and if costs doesn’t grow too high.</p>
<p>The post <a href="https://gunnarpeipman.com/mssql-files-on-azure-blob-storage/">MSSQL data and log files on Azure blob storage</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gunnarpeipman.com/mssql-files-on-azure-blob-storage/feed/</wfw:commentRss>
			<slash:comments>5</slash:comments>
		
		
			</item>
		<item>
		<title>Using data from MSSQL linked server with EF Core</title>
		<link>https://gunnarpeipman.com/ef-core-mssql-linked-server/</link>
					<comments>https://gunnarpeipman.com/ef-core-mssql-linked-server/#comments</comments>
		
		<dc:creator><![CDATA[Gunnar Peipman]]></dc:creator>
		<pubDate>Thu, 27 Feb 2020 22:39:43 +0000</pubDate>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[Data platform]]></category>
		<guid isPermaLink="false">https://gunnarpeipman.com/?p=6042</guid>

					<description><![CDATA[<p>My previous blog post Querying MySQL from SQL Server using linked server introduced how to link MySQL database to MSSQL and how to write queries that gather data from local and linked server. This blog post demonstrates how to get data mixed from those sources to Entity Framework Core.</p>
<p>The post <a href="https://gunnarpeipman.com/ef-core-mssql-linked-server/">Using data from MSSQL linked server with EF Core</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>My previous blog post <a title="Querying MySQL from SQL Server using linked server" href="https://gunnarpeipman.com/mssql-mysql-linked-server/">Querying MySQL from SQL Server using linked server</a> introduced how to link MySQL database to MSSQL and how to write queries that gather data from local and linked server. This blog post demonstrates how to get data mixed from those sources to Entity Framework Core.</p>
<p><span id="more-6042"></span></p>
<h3>Using data from MSSQL linked servers</h3>
<p>Linked servers are not directly supported by Entity Framework Core at LINQ level. There are few options how to handle data in linked servers:</p>
<ul>
<li><strong>Custom SQL</strong> – we can write custom SQL queries for DbContext. On positive side we have full control over all SQL we want to run. On negative side we have custom SQL and we have to go around DbSets and create all kind of nasty hacks.</li>
<li><strong>Custom views </strong>– we can hide querying from linked servers to views and have DbSets like we usually do. It needs more work on database side but we don’t have to hack DbContext.</li>
</ul>
<p>In this post I don’t stop on custom SQL approach as this is same as running custom SQL queries through DbContext and it’s well covered in many other public sources. Also I don’t prefer this approach as too much database gets into application code.</p>
<blockquote>
<p><strong>NB!</strong> This blog post doesn’t cover data modification in linked server. It seems like simple topic but there are actually many complexities to get over. In my practice data from linked servers is only for displaying it as otherwise there are good chances that direct changes to data will conflict with business rules set by other systems.</p>
</blockquote>
<h3>Sample customer tables</h3>
<p>All the following code is based on my blog post <a title="Querying MySQL from SQL Server using linked server" href="https://gunnarpeipman.com/mssql-mysql-linked-server/">Querying MySQL from SQL Server using linked server</a>. I had two customers databases – one on MSSQL and other on MySQL. MySQL database was linked to MSSQL. The following screenshot shows customers table in both databases. Some fields are matching and some fields are different.</p>
<p align="center"><img decoding="async" width="670" height="326" title="Customers tables in MySQL and MSSQL" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="Customers tables in MySQL and MSSQL" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/02/mysql-mssql-linked-server-customers.png" border="0"></p>
<p>You can find guidance about setting up linked server from my blog post <a title="Querying MySQL from SQL Server using linked server" href="https://gunnarpeipman.com/mssql-mysql-linked-server/">Querying MySQL from SQL Server using linked server</a>.</p>
<h3>Creating view with data from local and linked server</h3>
<p>Using SQL Server Management Studio (SSMS) it’s easy to write a query to mix data from both customer tables shown above.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">SELECT</span><br>&nbsp;&nbsp;&nbsp; c<span style="color: gray;">.</span>FirstName<span style="color: gray;">,</span><br>&nbsp;&nbsp;&nbsp; c<span style="color: gray;">.</span>LastName<span style="color: gray;">,</span><br>&nbsp;&nbsp;&nbsp; crm_c<span style="color: gray;">.</span>credit_rating <span style="color: blue;">as</span> CreditRating<br><span style="color: blue;">FROM</span>&nbsp;<br>&nbsp;&nbsp;&nbsp; Customers c<br>&nbsp;&nbsp;&nbsp; <span style="color: gray;">LEFT</span>&nbsp;<span style="color: gray;">JOIN</span> MYSQLCRM<span style="color: gray;">...</span>customers crm_c <span style="color: blue;">ON</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c<span style="color: gray;">.</span>ssn <span style="color: gray;">=</span> crm_c<span style="color: gray;">.</span>ssn<br><span style="color: blue;">ORDER</span>&nbsp;<span style="color: blue;">BY</span><br>&nbsp;&nbsp;&nbsp; crm_c<span style="color: gray;">.</span>credit_rating<span style="color: gray;">,</span><br>&nbsp;&nbsp;&nbsp; c<span style="color: gray;">.</span>LastName<span style="color: gray;">,</span><br>&nbsp;&nbsp;&nbsp; c<span style="color: gray;">.</span>FirstName</pre>
<p>We take all fields from customers table on MSSQL and ask credit rating field from customers table on MySQL. It works like charm if link between databases is set up and configured appropriately. </p>
<p>For EF Core we want to have DbSet so we don’t need to mess with custom SQL in our code. The closer we will stay to DbSet pattern the better it is. Happily EF Core doesn’t care if data is coming from table or view. Let’s take the SQL query shown above and save it as view to MSSQL.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">CREATE</span>&nbsp;<span style="color: blue;">VIEW</span> [dbo]<span style="color: gray;">.</span>[VW_CUSTOMERS]<br><span style="color: blue;">AS</span><br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">SELECT</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c<span style="color: gray;">.</span>Id<span style="color: gray;">,</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c<span style="color: gray;">.</span>FirstName<span style="color: gray;">,</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c<span style="color: gray;">.</span>LastName<span style="color: gray;">,</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c<span style="color: gray;">.</span>Ssn<span style="color: gray;">,</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c<span style="color: gray;">.</span>BillingAddress<span style="color: gray;">,</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; crm_c<span style="color: gray;">.</span>credit_rating <span style="color: blue;">as</span> CreditRating<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">FROM</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dbo<span style="color: gray;">.</span>Customers c<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: gray;">LEFT</span>&nbsp;<span style="color: gray;">JOIN</span> MYSQLCRM<span style="color: gray;">...</span>customers crm_c <span style="color: blue;">ON</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c<span style="color: gray;">.</span>Ssn <span style="color: gray;">=</span> crm_c<span style="color: gray;">.</span>ssn<br><span style="color: blue;">GO</span></pre>
<p>We can open it in SSMS and see table with results.</p>
<p align="center"><img decoding="async" width="630" height="132" title="Mixed results from view" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="Mixed results from view" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/02/mysql-mssql-linked-server-query-results.png" border="0"></p>
<p>There’s one thing left to do – we have to make sure that deletes to VW_CUSTOMERS view doesn’t affect linked database. For this we can use INSTEAD OF DELETE trigger. This trigger is run when rows are deleted from view and it replaces default delete behavior.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">CREATE</span>&nbsp;<span style="color: blue;">TRIGGER</span> [dbo]<span style="color: gray;">.</span>[VW_CUSTOMERS_DELETE]<br>&nbsp;&nbsp; <span style="color: blue;">ON</span> [dbo]<span style="color: gray;">.</span>[VW_CUSTOMERS]<br>&nbsp;&nbsp; <span style="color: blue;">INSTEAD</span>&nbsp;<span style="color: blue;">OF</span>&nbsp;<span style="color: blue;">DELETE</span><br><span style="color: blue;">AS</span>&nbsp;<br><span style="color: blue;">BEGIN</span><br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">SET</span>&nbsp;<span style="color: blue;">NOCOUNT</span>&nbsp;<span style="color: blue;">ON</span><br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">DELETE</span>&nbsp;<span style="color: blue;">FROM</span> Customers <span style="color: blue;">WHERE</span> Id <span style="color: gray;">IN</span><span style="color: blue;">&nbsp;</span><span style="color: gray;">(</span><span style="color: blue;">SELECT</span> Id <span style="color: blue;">FROM</span> deleted<span style="color: gray;">)</span><br> <br><span style="color: blue;">END</span></pre>
<blockquote>
<p><strong>What happens without this trigger?</strong> Without this trigger MSSQL detects the situation it cannot handle – modification to multiple tables. The result is error and cancelled delete operation.</p>
</blockquote>
<h3>Using linked server table from DbContext</h3>
<p>To demonstrate using data from linked server with EF Core I created simple customer class based on VW_CUSTOMERS view.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">class</span>&nbsp;<span style="color: rgb(43, 145, 175);">SalesCustomer</span><br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">int</span> Id { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">string</span> FirstName { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">string</span> LastName { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">string</span> Ssn { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">string</span> BillingAddress { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">int</span>? CreditRating { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }<br>}</pre>
<p>We also need DbContext class to communicate with database. It looks almost like any other DbContext but there’s one trick – CreditRating property is marked as read-only. Of course, to make DbContext use VW_CUSTOMERS view instead of looking for SalesCustomer table we have to call ToTable() method on SalesCustomer entity.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">class</span>&nbsp;<span style="color: rgb(43, 145, 175);">SalesDbContext</span> : <span style="color: rgb(43, 145, 175);">DbContext</span><br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">SalesDbContext</span>(<span style="color: rgb(43, 145, 175);">DbContextOptions</span>&lt;<span style="color: rgb(43, 145, 175);">SalesDbContext</span>&gt; <span style="color: rgb(31, 55, 127);">options</span>) : <span style="color: blue;">base</span>(<span style="color: rgb(31, 55, 127);">options</span>)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">protected</span>&nbsp;<span style="color: blue;">override</span>&nbsp;<span style="color: blue;">void</span>&nbsp;<span style="color: rgb(116, 83, 31);">OnModelCreating</span>(<span style="color: rgb(43, 145, 175);">ModelBuilder</span>&nbsp;<span style="color: rgb(31, 55, 127);">modelBuilder</span>)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">modelBuilder</span>.<span style="color: rgb(116, 83, 31);">Entity</span>&lt;<span style="color: rgb(43, 145, 175);">SalesCustomer</span>&gt;().<span style="color: rgb(116, 83, 31);">ToTable</span>(<span style="color: rgb(163, 21, 21);">"VW_CUSTOMERS"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">modelBuilder</span>.<span style="color: rgb(116, 83, 31);">Entity</span>&lt;<span style="color: rgb(43, 145, 175);">SalesCustomer</span>&gt;()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">Property</span>(<span style="color: rgb(31, 55, 127);">p</span> =&gt; <span style="color: rgb(31, 55, 127);">p</span>.CreditRating)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">ValueGeneratedOnAddOrUpdate</span>();<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">base</span>.<span style="color: rgb(116, 83, 31);">OnModelCreating</span>(<span style="color: rgb(31, 55, 127);">modelBuilder</span>);<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">DbSet</span>&lt;<span style="color: rgb(43, 145, 175);">SalesCustomer</span>&gt; Customers { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }<br>}</pre>
<p>We can create more properties based on fields in linked tables but we have to mark them all as read-only to avoid conflicting changes to databases owned by other systems.</p>
<h3>Wrapping up</h3>
<p>Although MSSQL linked servers are not something we are using everyday and EF Core doesn’t have out-of-box tooling for it, we can still work out views and triggers to make mixed data from local and linked server visible as a table for EF Core. We marked customer entity properties that come from linked server as read-only to avoid making changes to linked table. This is usual requirement if linked table belongs to some other system that has its own business rules. We left all complex stuff to database and on EF Core we are using views as tables.</p>
<p>The post <a href="https://gunnarpeipman.com/ef-core-mssql-linked-server/">Using data from MSSQL linked server with EF Core</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gunnarpeipman.com/ef-core-mssql-linked-server/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
		<item>
		<title>Querying MySQL from SQL Server using linked server</title>
		<link>https://gunnarpeipman.com/mssql-mysql-linked-server/</link>
					<comments>https://gunnarpeipman.com/mssql-mysql-linked-server/#comments</comments>
		
		<dc:creator><![CDATA[Gunnar Peipman]]></dc:creator>
		<pubDate>Thu, 06 Feb 2020 04:40:56 +0000</pubDate>
				<category><![CDATA[Data platform]]></category>
		<guid isPermaLink="false">https://gunnarpeipman.com/?p=6035</guid>

					<description><![CDATA[<p>SQL Server has interesting feature calles Linked Servers. It’s about linking other databases to SQL Server and using their data like it’s local. There are many powerful open-source systems written on PHP and they are mostly using MySQL as database. This blog post shows how to link MySQL database to SQL Server and how to use linked server in SQL queries.</p>
<p>The post <a href="https://gunnarpeipman.com/mssql-mysql-linked-server/">Querying MySQL from SQL Server using linked server</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>SQL Server has interesting feature calles Linked Servers. It’s about linking other databases to SQL Server and using their data like it’s local. There are many powerful open-source systems written on PHP and they are mostly using MySQL as database. This blog post shows how to link MySQL database to SQL Server and how to use linked server in SQL queries.</p>
<p><span id="more-6035"></span></p>
<h3>What is linked server?</h3>
<p>Linked server in MSSQL is some other database server connected to given one, making it possible to query and manipulate data in other databases. By example, we can link some MySQL database to MSSQL and use it almost like any other database on MSSQL.</p>
<p align="center"><img decoding="async" width="429" height="357" title="Architure of SQL Server linked servers" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="Architure of SQL Server linked servers" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/02/mssql-linked-server.png" border="0"><br />&nbsp;<br /><em>Image is taken from MSSQL 2019 documentation page <br /></em><a title="MSSQL documentation: Linked Servers (Database Engine)" href="https://docs.microsoft.com/en-us/sql/relational-databases/linked-servers/linked-servers-database-engine?view=sql-server-ver15"><em>Linked Servers (Database Engine)</em></a></p>
<p>Although communication with linked servers goes through OLE DB providers, there is also OLE DB provider for ODBC and we can use it if our external database doesn’t have OLE DB provider.</p>
<blockquote>
<p><strong>NB!</strong> Linked server is available for whole SQL Server instance. It means that all SQL Server databases can use linked server to retrieve data.</p>
</blockquote>
<h3>Linking MySQL to SQL Server</h3>
<p>Adding linked server and configuring connection setting is not always easy and straightforward. </p>
<p>To get MySQL linked to SQL Server I needed to create ODBC DSN for MySQL (I named it as MySQLCrm). Before going to next steps, make sure that ODBC data source works.</p>
<p>Follow these steps to link MySQL to SQL Server:</p>
<ol>
<li>Run SQL Server Management Studio (SSMS)</li>
<li>Connect to your server</li>
<li>Expand Server Objects node from tree at left</li>
<li>Right-click on Linked Servers</li>
<li>Select New Linked Server…</li>
</ol>
<p>You should see the following dialog (or bit different but the idea remains the same).</p>
<p align="center"><img decoding="async" width="690" height="625" title="MySQL linked server settings" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="MySQL linked server settings" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/02/mssql-mysql-linked-server.png" border="0"></p>
<blockquote>
<p><strong>NB! </strong>Pay extra attention to what you insert to this dialog. With this set of data I made link work. I tried different values and if something is one millimeter wrong then connection fails. It’s damn sensitive dialog.</p>
</blockquote>
<p>Connection string to MySQL database should be like shown here:</p>
<pre>DRIVER=(MySQL ODBC 8.0 Unicode Driver); SERVER=localhost; PORT=3306; DATABASE=crmlinked; USER=crmuser; PASSWORD=crm_user_password; OPTION=3;</pre>
<p>Also pay attention to OPTION=3 – without this I got only errors back when connecting to linked server.</p>
<p>Try to save by clicking OK and see if you can browse to linked server. If you get errors then right-click on server and select properties. Keeping the dialog open, move to Server Options page. Set RPC and RPC Out settings to True. </p>
<p><img decoding="async" width="690" height="625" title="MySQL linked server options" style="border: 0px currentcolor; border-image: none; margin-right: auto; margin-left: auto; float: none; display: block; background-image: none;" alt="MySQL linked server options" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/02/mssql-mysql-linked-server-options.png" border="0"></p>
<p>I’m still not very sure what are these options doing but some of those who had issues with link to MySQL made it work after setting RPC-s to true.</p>
<p>To make querying actually work, we need one more little change that affects <strong>whole</strong> OLE DB provider and therefore all connections using it. Open Providers node under Linked Servers, right-click on MSDASQL (this is OLE DB provider for ODBC data sources) and select properties.</p>
<p align="center"><a href="https://static.gunnarpeipman.com/wp-content/uploads/2020/02/mssql-mysql-linked-server-msdasql-options.png"><img decoding="async" width="959" height="723" title="Configuring OLE DB data-source for ODBC" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="Configuring OLE DB data-source for ODBC" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/02/mssql-mysql-linked-server-msdasql-options_thumb.png" border="0"></a></p>
<p>Check the box before Level Zero only and click OK to save changes.</p>
<h3>Querying data from linked server</h3>
<p>Querying linked databases is actually easy. Here’s the customers table from crmlinked database in MySQL. This database is linked to my SQL Server.</p>
<p align="center"><img decoding="async" width="800" height="397" title="Customers table in MySQL database" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="Customers table in MySQL database" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/02/mysql-linked-server-customers-table.png" border="0"></p>
<p>Syntax for querying linked server is a little bit different from what we usually write on SQL Server. We need to use four-part names: server.database.schema.table. As there’s no schemas on MySQL and connection string specifies database name, then we can leave these out like shown here.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">select</span>&nbsp;<span style="color: gray;">*</span>&nbsp;<span style="color: blue;">from</span> MYSQLCRM<span style="color: gray;">...</span>customers<br></pre>
<p>Running this query from SSMS gives the following output. It’s the same data that is in MySQL customers table.</p>
<p align="center"><img decoding="async" width="383" height="144" title="Query results from linked MySQL server" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="Query results from linked MySQL server" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/02/mysql-linked-server-customers-list.png" border="0"></p>
<p>Of course, we can also write more complex queries. Everything that ODBC can handle is okay.</p>
<h3>Mixing data from local and linked server</h3>
<p>Tables from linked server are not totally isolated from local database tables and views. We can also mix data from local and linked server.</p>
<p align="center"><img decoding="async" width="517" height="110" title="Customers table on SQL Server" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="Customers table on SQL Server" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/02/mssql-linked-server-customers-table.png" border="0"></p>
<p>To demonstrate mixed query over local and linked tables let’s write simple query to get all customers from local table and their credit ratings from linked table.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">SELECT</span><br>&nbsp;&nbsp;&nbsp; c<span style="color: gray;">.</span>FirstName<span style="color: gray;">,</span><br>&nbsp;&nbsp;&nbsp; c<span style="color: gray;">.</span>LastName<span style="color: gray;">,</span><br>&nbsp;&nbsp;&nbsp; crm_c<span style="color: gray;">.</span>credit_rating <span style="color: blue;">as</span> CreditRating<br><span style="color: blue;">FROM</span>&nbsp;<br>&nbsp;&nbsp;&nbsp; Customers c<br>&nbsp;&nbsp;&nbsp; <span style="color: gray;">LEFT</span>&nbsp;<span style="color: gray;">JOIN</span> MYSQLCRM<span style="color: gray;">...</span>customers crm_c <span style="color: blue;">ON</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c<span style="color: gray;">.</span>ssn <span style="color: gray;">=</span> crm_c<span style="color: gray;">.</span>ssn<br><span style="color: blue;">ORDER</span>&nbsp;<span style="color: blue;">BY</span><br>&nbsp;&nbsp;&nbsp; crm_c<span style="color: gray;">.</span>credit_rating<span style="color: gray;">,</span><br>&nbsp;&nbsp;&nbsp; c<span style="color: gray;">.</span>LastName<span style="color: gray;">,</span><br>&nbsp;&nbsp;&nbsp; c<span style="color: gray;">.</span>FirstName</pre>
<p>Running this query gives us the following output.</p>
<p align="center"><img decoding="async" width="288" height="127" title="Results of mixed query over local and linked server data" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="Results of mixed query over local and linked server data" src="https://static.gunnarpeipman.com/wp-content/uploads/2020/02/mssql-mysql-linked-server-mixed-query-results.png" border="0"></p>
<p>As Mark is not present in MySQL database (suppose he is new customer in e-shop and sales department doesn’t have him yet in their CRM system) then he doesn’t have credit rating available. Credit ratings for John and Mary are coming from MySQL in current case.</p>
<h3>Using OPENQUERY() to execute query in linked server</h3>
<p>The examples above make all data processing on SQL Server. It can be very unoptimal if there’s a lot of data in linked server’s tables. We may want – or usually want &#8211; to process some data in linked server before SQL Server starts local processing. For this we have OPENQUERY().</p>
<p>Here’s the example of using OPENQUERY() function in mixed query. We have to specify linked server name and SQL query to run in linked server when calling OPENQUERY(). The query in red is executed in MySQL server and results are read to SQL Server for further processing.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">SELECT</span><br>&nbsp;&nbsp;&nbsp; c<span style="color: gray;">.</span>FirstName<span style="color: gray;">,</span><br>&nbsp;&nbsp;&nbsp; c<span style="color: gray;">.</span>LastName<span style="color: gray;">,</span><br>&nbsp;&nbsp;&nbsp; crm_c<span style="color: gray;">.</span>credit_rating <span style="color: blue;">as</span> CreditRating<br><span style="color: blue;">FROM</span>&nbsp;<br>&nbsp;&nbsp;&nbsp; Customers c<br>&nbsp;&nbsp;&nbsp; <span style="color: gray;">LEFT</span>&nbsp;<span style="color: gray;">JOIN</span>&nbsp;<span style="color: blue;">OPENQUERY</span><span style="color: gray;">(</span>MYSQLCRM<span style="color: gray;">,</span>&nbsp;<span style="color: red;">'</span><br><span style="color: red;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT </span><br><span style="color: red;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c.credit_rating</span><br><span style="color: red;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FROM </span><br><span style="color: red;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; customers p</span><br><span style="color: red;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; left join loyalty_points lp on</span><br><span style="color: red;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c.customer_id = lp.customer_id</span><br><span style="color: red;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WHERE</span><br><span style="color: red;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lp.points &gt; 1000</span><br><span style="color: red;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; '</span><span style="color: gray;">)</span> crm_c <span style="color: blue;">ON</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c<span style="color: gray;">.</span>ssn <span style="color: gray;">=</span> crm_c<span style="color: gray;">.</span>ssn<br><span style="color: blue;">ORDER</span>&nbsp;<span style="color: blue;">BY</span><br>&nbsp;&nbsp;&nbsp; crm_c<span style="color: gray;">.</span>credit_rating<span style="color: gray;">,</span><br>&nbsp;&nbsp;&nbsp; c<span style="color: gray;">.</span>LastName<span style="color: gray;">,</span><br>&nbsp;&nbsp;&nbsp; c<span style="color: gray;">.</span>FirstName </pre>
<p>OPENQUERY() is great way to optimize and speed up mixed queries by running more complex queries over linked server data in linked server. </p>
<h3>Wrapping up</h3>
<p>Linked servers is powerful feature of SQL Server making it easy for us to use data from external servers. There are two ways to write queries using data from linked servers – direct queries that do all processing on SQL Server and OPENQUERY() that lets us do some processing in remote server. Linked server is integration and therefore using it needs extra care. Planning and performance measuring are must-be activities when planning to use linked server.</p>
<p>The post <a href="https://gunnarpeipman.com/mssql-mysql-linked-server/">Querying MySQL from SQL Server using linked server</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gunnarpeipman.com/mssql-mysql-linked-server/feed/</wfw:commentRss>
			<slash:comments>7</slash:comments>
		
		
			</item>
		<item>
		<title>Implementing repository querying interface in EF Core DbContext</title>
		<link>https://gunnarpeipman.com/ef-core-dbcontext-repository/</link>
					<comments>https://gunnarpeipman.com/ef-core-dbcontext-repository/#comments</comments>
		
		<dc:creator><![CDATA[Gunnar Peipman]]></dc:creator>
		<pubDate>Mon, 03 Feb 2020 05:00:30 +0000</pubDate>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[Architecture/Design/Patterns]]></category>
		<category><![CDATA[Data platform]]></category>
		<guid isPermaLink="false">https://gunnarpeipman.com/?p=6015</guid>

					<description><![CDATA[<p>My last bold statement was that we don’t need custom unit of work and repository classes with Entity Framework Core. One issue remained unsolved and it was querying part of repositories (yeah, those custom querying methods). After some experiments to get querying interface of repositories to DbContext I worked out something that I kind of like. I managed to make DbContext to work like classic unit of work that hosts repository instances. Here’s my experiment and the solution I worked out.</p>
<p>The post <a href="https://gunnarpeipman.com/ef-core-dbcontext-repository/">Implementing repository querying interface in EF Core DbContext</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>My last bold statement was that we <a title="No need for repositories and unit of work with Entity Framework Core" href="https://gunnarpeipman.com/ef-core-repository-unit-of-work/">don’t need custom unit of work and repository classes with Entity Framework Core</a>. One issue remained unsolved and it was querying part of repositories (yeah, those custom querying methods). After some experiments to get querying interface of repositories to DbContext I worked out something that I kind of like. I managed to make DbContext to work like classic unit of work that hosts repository instances. Here’s my experiment and the solution I worked out.</p>
<p><span id="more-6015"></span></p>
<blockquote>
<p><strong>NB!</strong> My goal here is to stay strictly with Entity Framework Core or some other mapper that supports LINQ queries. Replacing ORM is usually extreme case and during my 20+ years in software development I have seen only few cases when it was done. If you prefer NHibernate over EF Core then check out my post <a title="NHibernate on ASP.NET Core" href="https://gunnarpeipman.com/aspnet-core-nhibernate/">NHibernate on ASP.NET Core</a> to see how imitate DbContext with NHibernate.</p>
</blockquote>
<h3>“Repositorifying” DbContext</h3>
<p>Making DbContext similar to typical unit of work that contains repository instances is not easy. One weakness of repository pattern is that it can be easily abused as a querying methods store. I have seen repositories that are thousands of lines long thanks to querying methods. But hey, they are still easy to use in unit tests as they implement interfaces we can mock. DbContext is different beast. It can easily be injected to repositories and other classes but it’s not easy to inject querying part of repositories there. </p>
<p>It would be nice to have something like shown here.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">class</span>&nbsp;<span style="color: rgb(43, 145, 175);">SalesDbContext</span> : <span style="color: rgb(43, 145, 175);">DbContext</span><br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">SalesDbContext</span>(<span style="color: rgb(43, 145, 175);">DbContextOptions</span>&lt;<span style="color: rgb(43, 145, 175);">SalesDbContext</span>&gt; <span style="color: rgb(31, 55, 127);">options</span>) : <span style="color: blue;">base</span>(<span style="color: rgb(31, 55, 127);">options</span>)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">DbSet</span>&lt;<span style="color: rgb(43, 145, 175);">Customer</span>&gt; Customers { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: green;">// Other DbSets</span><br>}<br><br><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">void</span>&nbsp;<span style="color: rgb(116, 83, 31);">DoSomething</span>()<br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">debtors</span> = dbContext.Customers.<span style="color: rgb(116, 83, 31);">ListDebtors</span>();<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: green;">// ...</span><br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">date</span> = <span style="color: rgb(43, 145, 175);">DateTime</span>.Now.<span style="color: rgb(116, 83, 31);">AddDays</span>(-14);<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">newCustomers</span> = dbContext.Customers.<span style="color: rgb(116, 83, 31);">ListNewRegistrations</span>(<span style="color: rgb(31, 55, 127);">date</span>);<br>}</pre>
<p>There are some obstacles on our way that are hard – if not impossible – to remove with simple tricks. Let’s briefly explore our options:</p>
<ul>
<li><strong>DbSet&lt;T&gt; is not for inheriting</strong>– internals of instantiating DbSet&lt;T&gt; are complex and luckily these complexities are hidden from us. Still these complexities are good enough reason for product group to not support extending of DbSet&lt;T&gt;. Let’s agree with them and abandon the idea of using digital violence to get our will.</li>
<li><strong>Extension methods for DbSet&lt;T&gt;</strong> – we can build extension methods for given DbSet&lt;T&gt; and host these methods in some static class in same namespace. It’s the easy way out but it comes with price – we can’t easily mock extension methods. We have to use type isolation and there is limited number of tools with this feature. </li>
<li><strong>Querying methods in DbContext</strong> – another easy way out but again there’s price to pay. Piling all querying methods to DbContext will bloat this class. It can get even worse if querying methods call each other. I wouldn’t go with this approach.</li>
<li><strong>Injecting querying interfaces to DbContext class</strong> &#8211; creates chicken-egg situation because DbContext needs querying classes to be injected and query classes need DbContext to be injected. </li>
</ul>
<p>Of approaches mentioned above only to are worth to experiment: extension methods for DBSet&lt;T&gt; and querying classes that are injected to DbContext.</p>
<h3>Extension methods for DbSet&lt;T&gt;</h3>
<p>Extension methods are easiest ones to implement. They work until we stay with pure LINQ. In case of multiple database types and custom SQL queries this approach doesn’t work. Let’s write extension methods for DbSet&lt;Customer&gt;.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">static</span>&nbsp;<span style="color: blue;">class</span>&nbsp;<span style="color: rgb(43, 145, 175);">SalesDbContextCustomersExtensions</span><br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">static</span>&nbsp;<span style="color: rgb(43, 145, 175);">IQueryable</span>&lt;<span style="color: rgb(43, 145, 175);">Customer</span>&gt; <span style="color: rgb(116, 83, 31);">ListDebtors</span>(<span style="color: blue;">this</span>&nbsp;<span style="color: rgb(43, 145, 175);">DbSet</span>&lt;<span style="color: rgb(43, 145, 175);">Customer</span>&gt; <span style="color: rgb(31, 55, 127);">customers</span>)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">return</span>&nbsp;<span style="color: rgb(31, 55, 127);">customers</span>.<span style="color: rgb(116, 83, 31);">Where</span>(<span style="color: rgb(31, 55, 127);">c</span> =&gt; <span style="color: rgb(31, 55, 127);">c</span>.Balance &lt; 0);<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">static</span>&nbsp;<span style="color: rgb(43, 145, 175);">IQueryable</span>&lt;<span style="color: rgb(43, 145, 175);">Customer</span>&gt; <span style="color: rgb(116, 83, 31);">ListNewRegistrations</span>(<span style="color: blue;">this</span>&nbsp;<span style="color: rgb(43, 145, 175);">DbSet</span>&lt;<span style="color: rgb(43, 145, 175);">Customer</span>&gt; <span style="color: rgb(31, 55, 127);">customers</span>, <span style="color: rgb(43, 145, 175);">DateTime</span>&nbsp;<span style="color: rgb(31, 55, 127);">fromDate</span>)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">return</span>&nbsp;<span style="color: rgb(31, 55, 127);">customers</span>.<span style="color: rgb(116, 83, 31);">Where</span>(<span style="color: rgb(31, 55, 127);">c</span> =&gt; <span style="color: rgb(31, 55, 127);">c</span>.Created <span style="color: rgb(116, 83, 31);">&gt;=</span>&nbsp;<span style="color: rgb(31, 55, 127);">fromDate</span>);<br>&nbsp;&nbsp;&nbsp; }<br>}</pre>
<p>We have separate class with extension methods and we don’t bloat DbContext with queries. Still these extension methods are easy to use.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">void</span>&nbsp;<span style="color: rgb(116, 83, 31);">DoSomething</span>()<br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">debtors</span> = dbContext.Customers.<span style="color: rgb(116, 83, 31);">ListDebtors</span>();<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: green;">// ...</span><br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">date</span> = <span style="color: rgb(43, 145, 175);">DateTime</span>.Now.<span style="color: rgb(116, 83, 31);">AddDays</span>(-14);<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">newCustomers</span> = dbContext.Customers.<span style="color: rgb(116, 83, 31);">ListNewRegistrations</span>(<span style="color: rgb(31, 55, 127);">date</span>);<br>}</pre>
<p>Those who want to isolate direct access to DbSets can’t use extension methods as marking DbSets protected restricts external access to them.</p>
<blockquote>
<p>If you want to go with extension methods then here few more ideas what you can do in data layer: <a title="Implementing Query Specification pattern in Entity Framework Core" href="https://gunnarpeipman.com/ef-core-query-specification/">Implementing Query Specification pattern in Entity Framework Core</a> and <a title="Readable fluent queries with Entity Framework Core" href="https://gunnarpeipman.com/ef-core-readable-fluent-queries/">Readable fluent queries with Entity Framework Core</a>.</p>
</blockquote>
<h3>Injecting querying classes to DbContext</h3>
<p>If extension methods are not an option then we have to introduce querying classes that are injected to DbContext. Like mentioned above there’s a chicken and egg problem, but it’s not hard to solve. Let’s start with intrface and class for querying customers. We use interface because we probably want to use fake version of querying class when writing unit tests.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">interface</span>&nbsp;<span style="color: rgb(43, 145, 175);">ICustomerQueries</span><br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">void</span>&nbsp;<span style="color: rgb(116, 83, 31);">SetDbContext</span>(<span style="color: rgb(43, 145, 175);">SalesDbContext</span>&nbsp;<span style="color: rgb(31, 55, 127);">dbContext</span>);<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">IQueryable</span>&lt;<span style="color: rgb(43, 145, 175);">Customer</span>&gt; <span style="color: rgb(116, 83, 31);">ListDebtors</span>();<br>&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">IQueryable</span>&lt;<span style="color: rgb(43, 145, 175);">Customer</span>&gt; <span style="color: rgb(116, 83, 31);">ListNewRegistrations</span>(<span style="color: rgb(43, 145, 175);">DateTime</span>&nbsp;<span style="color: rgb(31, 55, 127);">date</span>);<br>}<br> <br><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">class</span>&nbsp;<span style="color: rgb(43, 145, 175);">CustomerQueries</span> : <span style="color: rgb(43, 145, 175);">ICustomerQueries</span><br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">private</span>&nbsp;<span style="color: rgb(43, 145, 175);">SalesDbContext</span> _dbContext; <br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public virtual</span>&nbsp;<span style="color: rgb(43, 145, 175);">IQueryable</span>&lt;<span style="color: rgb(43, 145, 175);">Customer</span>&gt; <span style="color: rgb(116, 83, 31);">ListDebtors</span>()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">return</span> _dbContext.Customers.<span style="color: rgb(116, 83, 31);">Where</span>(<span style="color: rgb(31, 55, 127);">c</span> =&gt; <span style="color: rgb(31, 55, 127);">c</span>.Balance &lt; 0);<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public virtual</span>&nbsp;<span style="color: rgb(43, 145, 175);">IQueryable</span>&lt;<span style="color: rgb(43, 145, 175);">Customer</span>&gt; <span style="color: rgb(116, 83, 31);">ListNewRegistrations</span>(<span style="color: rgb(43, 145, 175);">DateTime</span>&nbsp;<span style="color: rgb(31, 55, 127);">date</span>)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">return</span> _dbContext.Customers.<span style="color: rgb(116, 83, 31);">Where</span>(<span style="color: rgb(31, 55, 127);">c</span> =&gt; <span style="color: rgb(31, 55, 127);">c</span>.Created <span style="color: rgb(116, 83, 31);">&gt;=</span>&nbsp;<span style="color: rgb(31, 55, 127);">date</span>);<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">void</span>&nbsp;<span style="color: rgb(116, 83, 31);">SetDbContext</span>(<span style="color: rgb(43, 145, 175);">SalesDbContext</span>&nbsp;<span style="color: rgb(31, 55, 127);">dbContext</span>)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _dbContext = <span style="color: rgb(31, 55, 127);">dbContext</span>;<br>&nbsp;&nbsp;&nbsp; }<br>}</pre>
<p>Notice two things. SetDbContext() method – we have to assign DbContext when instance of ICustomerQueries is injected to DbContext. Otherwise there’s no connection between these two classes. Customer queries class has virtual methods. We can keep there pure LINQ methods and extend this class if we need let’s say SqlServerCustomerQueries class that overrides some methods to use SQL Server specific SQL commands.</p>
<p>Here’s our DbContext after changes.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">class</span>&nbsp;<span style="color: rgb(43, 145, 175);">SalesDbContext</span> : <span style="color: rgb(43, 145, 175);">DbContext</span><br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">SalesDbContext</span>(<span style="color: rgb(43, 145, 175);">DbContextOptions</span>&lt;<span style="color: rgb(43, 145, 175);">SalesDbContext</span>&gt; <span style="color: rgb(31, 55, 127);">options</span>, <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">ICustomerQueries</span>&nbsp;<span style="color: rgb(31, 55, 127);">customerQueries</span>) : <span style="color: blue;">base</span>(<span style="color: rgb(31, 55, 127);">options</span>)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CustomerQueries = <span style="color: rgb(31, 55, 127);">customerQueries</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">customerQueries</span>.<span style="color: rgb(116, 83, 31);">SetDbContext</span>(<span style="color: blue;">this</span>);<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">DbSet</span>&lt;<span style="color: rgb(43, 145, 175);">Customer</span>&gt; Customers { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: green;">// Other DbSets</span><br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">ICustomerQueries</span> CustomerQueries { <span style="color: blue;">get</span>; <span style="color: blue;">private</span>&nbsp;<span style="color: blue;">set</span>; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: green;">// Other queries</span><br>}</pre>
<p>In assigns itself to DbContext property of all injected querying classes. It’s easy but still something we have to remember to do when introducing new quering class for some DbSet&lt;T&gt;.&nbsp; Our previous dummy demo method looks now just a little bit different than before.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">void</span>&nbsp;<span style="color: rgb(116, 83, 31);">DoSomething</span>()<br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">debtors</span> = dbContext.CustomerQueries.<span style="color: rgb(116, 83, 31);">ListDebtors</span>();<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: green;">// ...</span><br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">date</span> = <span style="color: rgb(43, 145, 175);">DateTime</span>.Now.<span style="color: rgb(116, 83, 31);">AddDays</span>(-14);<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">newCustomers</span> = dbContext.CustomerQueries<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">ListNewRegistrations</span>(<span style="color: rgb(31, 55, 127);">date</span>);<br>}</pre>
<p>For ASP.NET Core we have to add querying interface and class to dependency injection.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: rgb(31, 55, 127);">services</span>.<span style="color: rgb(116, 83, 31);">AddScoped</span>&lt;<span style="color: rgb(43, 145, 175);">ICustomerQueries</span>, <span style="color: rgb(43, 145, 175);">CustomerQueries</span>&gt;();<br></pre>
<p>Now we have a bit inconveniet DbContext that actually acts as an unit of work with local instances of repositories.</p>
<h3>Supporting database-specific commands</h3>
<p>As I previously mentioned we need sometimes database-specific commands. These commands can contain SQL that is understood only by one supported database. It’s clear we cannot run these commands against other types of databases. </p>
<blockquote>
<p><strong>Database-specific commands</strong> are usual in applications that have reporting. Some ideas about how to implement common reporting with Entity Framework Core are given in my posts <a title="Execute raw SQL commands in Entity Framework Core" href="https://gunnarpeipman.com/ef-core-execute-raw-sql/">Execute raw SQL commands in Entity Framework Core</a> and <a title="DataSet and DataTable based ad-hoc reporting with ASP.NET Core" href="https://gunnarpeipman.com/aspnet-core-reporting-dataset-datatable/">DataSet and DataTable based ad-hoc reporting with ASP.NET Core</a>.</p>
</blockquote>
<p>This is customer queries class we created above with one little change – DbContext is now available for inheriting classes.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">class</span>&nbsp;<span style="color: rgb(43, 145, 175);">CustomerQueries</span> : <span style="color: rgb(43, 145, 175);">ICustomerQueries</span><br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">protected</span>&nbsp;<span style="color: rgb(43, 145, 175);">SalesDbContext</span> dbContext { <span style="color: blue;">get</span>; <span style="color: blue;">private</span>&nbsp;<span style="color: blue;">set</span>; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">virtual</span>&nbsp;<span style="color: rgb(43, 145, 175);">IQueryable</span>&lt;<span style="color: rgb(43, 145, 175);">Customer</span>&gt; <span style="color: rgb(116, 83, 31);">ListDebtors</span>()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">return</span> dbContext.Customers.<span style="color: rgb(116, 83, 31);">Where</span>(<span style="color: rgb(31, 55, 127);">c</span> =&gt; <span style="color: rgb(31, 55, 127);">c</span>.Balance &lt; 0);<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">virtual</span>&nbsp;<span style="color: rgb(43, 145, 175);">IQueryable</span>&lt;<span style="color: rgb(43, 145, 175);">Customer</span>&gt; <span style="color: rgb(116, 83, 31);">ListNewRegistrations</span>(<span style="color: rgb(43, 145, 175);">DateTime</span>&nbsp;<span style="color: rgb(31, 55, 127);">date</span>)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">return</span> dbContext.Customers.<span style="color: rgb(116, 83, 31);">Where</span>(<span style="color: rgb(31, 55, 127);">c</span> =&gt; <span style="color: rgb(31, 55, 127);">c</span>.Created <span style="color: rgb(116, 83, 31);">&gt;=</span>&nbsp;<span style="color: rgb(31, 55, 127);">date</span>);<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">void</span>&nbsp;<span style="color: rgb(116, 83, 31);">SetDbContext</span>(<span style="color: rgb(43, 145, 175);">SalesDbContext</span>&nbsp;<span style="color: rgb(31, 55, 127);">context</span>)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dbContext = <span style="color: rgb(31, 55, 127);">context</span>;<br>&nbsp;&nbsp;&nbsp; }<br>}</pre>
<p>We marked querying methods as virtual and there was a reason to do so. Suppose ListDeptors() method is tricky and we need custom SQL for this when using MySQL.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">class</span>&nbsp;<span style="color: rgb(43, 145, 175);">MySqlCustomerQueries</span> : <span style="color: rgb(43, 145, 175);">CustomerQueries</span><br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">override</span>&nbsp;<span style="color: rgb(43, 145, 175);">IQueryable</span>&lt;<span style="color: rgb(43, 145, 175);">Customer</span>&gt; <span style="color: rgb(116, 83, 31);">ListDebtors</span>()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">return</span> dbContext.Customers.<span style="color: rgb(116, 83, 31);">FromSql</span>(<span style="color: rgb(163, 21, 21);">"MySQL specific SQL"</span>);<br>&nbsp;&nbsp;&nbsp; }<br>}</pre>
<p>Same way we can also build specialized classes for SQL Server, Oracle, Postgre etc.</p>
<h3>Mocking querying classes in unit tests</h3>
<p>Querying classes we inject using their interfaces can be easily mocked in unit tests. Suppose we have CustomersService class with kind method to zero all debts.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">class</span>&nbsp;<span style="color: rgb(43, 145, 175);">CustomersService</span> : <span style="color: rgb(43, 145, 175);">ICustomersService</span>&nbsp;<br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">private</span>&nbsp;<span style="color: blue;">readonly</span>&nbsp;<span style="color: rgb(43, 145, 175);">SalesDbContext</span> _salesDbContext;<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">CustomersService</span>(<span style="color: rgb(43, 145, 175);">SalesDbContext</span>&nbsp;<span style="color: rgb(31, 55, 127);">salesDbContext</span>)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _salesDbContext = <span style="color: rgb(31, 55, 127);">salesDbContext</span>;<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">void</span>&nbsp;<span style="color: rgb(116, 83, 31);">ClearDebts</span>()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">debtors</span> = _salesDbContext.CustomerQueries.<span style="color: rgb(116, 83, 31);">ListDebtors</span>();<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(143, 8, 196);">foreach</span>(<span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">debtor</span>&nbsp;<span style="color: rgb(143, 8, 196);">in</span>&nbsp;<span style="color: rgb(31, 55, 127);">debtors</span>)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">debtor</span>.Balance = 0;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _salesDbContext.<span style="color: rgb(116, 83, 31);">SaveChanges</span>();<br>&nbsp;&nbsp;&nbsp; }<br>}</pre>
<p>Using xUnit and Moq we can write the following test class to check if ClearDebts() sets all debts to zero.</p>
<pre style="background: white; color: black; font-family: consolas;"><span style="color: blue;">public</span>&nbsp;<span style="color: blue;">class</span>&nbsp;<span style="color: rgb(43, 145, 175);">CustomerServiceTests</span><br>{<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">private</span>&nbsp;<span style="color: rgb(43, 145, 175);">Mock</span>&lt;<span style="color: rgb(43, 145, 175);">ICustomerQueries</span>&gt; _customerQueriesMock;<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">private</span>&nbsp;<span style="color: rgb(43, 145, 175);">SalesDbContext</span> _dbContext;<br> <br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: rgb(43, 145, 175);">CustomerServiceTests</span>()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _customerQueriesMock = <span style="color: blue;">new</span>&nbsp;<span style="color: rgb(43, 145, 175);">Mock</span>&lt;<span style="color: rgb(43, 145, 175);">ICustomerQueries</span>&gt;();<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">options</span> = <span style="color: blue;">new</span>&nbsp;<span style="color: rgb(43, 145, 175);">DbContextOptionsBuilder</span>&lt;<span style="color: rgb(43, 145, 175);">SalesDbContext</span>&gt;()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">UseInMemoryDatabase</span>(<span style="color: rgb(43, 145, 175);">Guid</span>.<span style="color: rgb(116, 83, 31);">NewGuid</span>().<span style="color: rgb(116, 83, 31);">ToString</span>())<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Options;<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _dbContext = <span style="color: blue;">new</span>&nbsp;<span style="color: rgb(43, 145, 175);">SalesDbContext</span>(<span style="color: rgb(31, 55, 127);">options</span>, _customerQueriesMock.Object);<br>&nbsp;&nbsp;&nbsp; }<br> <br>&nbsp;&nbsp;&nbsp; [<span style="color: rgb(43, 145, 175);">Fact</span>]<br>&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span>&nbsp;<span style="color: blue;">void</span>&nbsp;<span style="color: rgb(116, 83, 31);">ClearDebths_should_set_debtors_balance_to_zero</span>()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">service</span> = <span style="color: blue;">new</span>&nbsp;<span style="color: rgb(43, 145, 175);">CustomersService</span>(_dbContext);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span>&nbsp;<span style="color: rgb(31, 55, 127);">debtors</span> = <span style="color: blue;">new</span>&nbsp;<span style="color: rgb(43, 145, 175);">List</span>&lt;<span style="color: rgb(43, 145, 175);">Customer</span>&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">new</span>&nbsp;<span style="color: rgb(43, 145, 175);">Customer</span> { Id = 1, Name = <span style="color: rgb(163, 21, 21);">"John Doe"</span>, Balance = -20 },<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">new</span>&nbsp;<span style="color: rgb(43, 145, 175);">Customer</span> { Id = 2, Name = <span style="color: rgb(163, 21, 21);">"Jane Doe"</span>, Balance = -5 }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; };<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _customerQueriesMock.<span style="color: rgb(116, 83, 31);">Setup</span>(<span style="color: rgb(31, 55, 127);">c</span> =&gt; <span style="color: rgb(31, 55, 127);">c</span>.<span style="color: rgb(116, 83, 31);">ListDebtors</span>())<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .<span style="color: rgb(116, 83, 31);">Returns</span>(<span style="color: rgb(31, 55, 127);">debtors</span>.<span style="color: rgb(116, 83, 31);">AsQueryable</span>());<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(31, 55, 127);">service</span>.<span style="color: rgb(116, 83, 31);">ClearDebts</span>();<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">Assert</span>.<span style="color: rgb(116, 83, 31);">Equal</span>(0, <span style="color: rgb(31, 55, 127);">debtors</span>[0].Balance);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(43, 145, 175);">Assert</span>.<span style="color: rgb(116, 83, 31);">Equal</span>(0, <span style="color: rgb(31, 55, 127);">debtors</span>[1].Balance);<br>&nbsp;&nbsp;&nbsp; }<br>}</pre>
<p>In real world we should have more tests but for illustration this one is okay. We can create class-level mocks also for other querying classes we need in DbContext. Those who don’t like mocks can use stub classes. It’s easy because querying classes have interfaces.</p>
<h3>How this approach works in practice?</h3>
<p>After getting to point where I was kind of okay with the solution, of course I was eager to try it out on some real project. Luckily I have one application under development that is perfect candidate for test-drive. It’s very proccess-centric having complex service classes that make heavy querying. </p>
<p>Some characteristics to understand the system I’m using as lab rat:</p>
<ul>
<li>two web application projects</li>
<li>one project with backgroud services</li>
<li>shared projects for business logic and data layers</li>
<li>database with ~40 tables (3 tables with many fields)</li>
<li>ten service classes (few of them really big)</li>
</ul>
<p>I’m using DbContext in applications through interface meaning that application see only what they need to see. I can restrict direct access to DbSet&lt;T&gt; properties and introduce generic Get, Save and Delete methods if needed. Querying classes form nice layer that handles all queries and I can build additional layers behind these if demands on querying happen to grow. </p>
<p>Leaving out the inconvenience on assigning DbContext to querying classes after they are injected to DbContext, I’m okay with my solution. Also it makes unit tests smaller and cleaner. I can easily mock querying objects and I don’t have to write code to insert correct test data to DbContext to make queries return the results that tests expect. </p>
<h3>Wrapping up</h3>
<p>Getting repositories querying interface to DbContext the way that we may have multiple implementations wasn’t very easy task. To be flexible we had to create querying classes, inject these to DbContext and assign DbContext to their data context property. Even if can safely extend DbSet&lt;T&gt; the problem will be the same – DbSet&lt;T&gt; needs to know DbContext. We created flexible query classes. There’s base class that hosts all pure LINQ-based querying methods. If we don’t have anything database specific then we can use these base classes. If we have something database-specific then we can extend database-specific querying classes from base class and override methods that need custom SQL. We have now DbContext that works as unit of wort containing set of repository instances. </p>
<p>The post <a href="https://gunnarpeipman.com/ef-core-dbcontext-repository/">Implementing repository querying interface in EF Core DbContext</a> appeared first on <a href="https://gunnarpeipman.com">Gunnar Peipman -  Programming Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gunnarpeipman.com/ef-core-dbcontext-repository/feed/</wfw:commentRss>
			<slash:comments>14</slash:comments>
		
		
			</item>
	</channel>
</rss>
