Jekyll2022-10-02T13:18:51-04:00https://scottdorman.blog/feed.xmlScott DormanScott Dorman - Microsoft MVP, Software Architect, Developer, AuthorScott DormanIndomitable Spirit2022-08-29T11:55:00-04:002022-08-29T11:55:00-04:00https://scottdorman.blog/2022/08/29/indomitable-spirit<p>Even though this is from 2017, I only saw this story and <a href="https://youtu.be/2AqPN6KJOzo">video</a> in my LinkedIn feed today. This might seem like any other video about high school football, but it’s not. It’s a story about overcoming obstacles and never giving up. In short, it’s about indomitable spirit.</p>
<p>If you train martial arts, you’re probably familiar with that term. Even if you don’t, you may still be familiar with it. <em>Spirit</em> is someone’s energy and liveliness. It shows in their everyday actions. <em>Indomitable</em> is something unyielding, unconquerable, and impossible to defeat or subdue. At first, how these two words fit together might not be clear. When someone has an <em>indomitable spirit</em>, they are determined to rise above their circumstances, showing courage, determination, and resolve. It’s about having grit.</p>
<p>What does indomitable spirit have to do with high school football? You might be tempted to guess that playing the sport brings out the indomitable spirit in the players. While that may be true, that’s not what I mean by indomitable spirit.</p>
<p>The story is about a young man named Sepp Shirey. Sepp was born with cerebral palsy. Football allowed him to connect with his friends and push himself to never quit. Eventually, Sepp met Tim Tebow through Tebow’s Wish 15 foundation. During his senior year at Atlee High School, Head Coach Matt Gray decided he should have one final moment on the field. Sepp was unexpectedly brought out on the field when the game outcome was inevitable. There wasn’t much planning involved, except that Sepp was to carry the ball a few yards before being “tackled” with a two-hand touch. That plan, however, changed with a linebacker on the opposing team who saw the look in Sepp’s eyes and started cheering him on. Not only that, but he told his teammates to let him run. Sepp’s run turned into an 80-yard touchdown.</p>
<p>Sepp faced and will continue to face challenges throughout his life due to his cerebral palsy. If you aren’t familiar with it, <a href="https://www.mayoclinic.org/diseases-conditions/cerebral-palsy/symptoms-causes/syc-20353999">cerebal palsy</a> is a group of disorders that affect movement and muscle tone or posture with no known cure. Generally, symptoms include developmental problems and speech, eating, movement, and coordination problems. Instead of accepting the limitations of his condition, Sepp chose to use them as the motivation for attacking his dreams. When he was <a href="https://www.wtvr.com/2017/11/02/the-story-behind-sepp-shireys-inspirational-touchdown-run">interviewed</a> afterward, he said, “The fact that I fulfilled a dream that I’ve had forever—of scoring a touchdown and crossing the goal line—is incredible.”</p>
<blockquote>
<p>That’s the power of indomitable spirit.</p>
</blockquote>
<p>Sepp’s dream wouldn’t have been possible without it. It also wouldn’t have been possible without the help, support, encouragement, empowerment, and vision of everyone around him. The players on the opposing team understood, whether they realized it or not, how empowering it would feel for him to fulfill that goal and encourage it.</p>
<p>Watch the video again. Watch the reactions of the players on both teams. Sepp’s story isn’t the only one like it. I challenge you to never give up. Face your challenges and overcome them, don’t let them be limiting factors.</p>Scott DormanEven though this is from 2017, I only saw this story and video in my LinkedIn feed today. This might seem like any other video about high school football, but it’s not. It’s a story about overcoming obstacles and never giving up. In short, it’s about indomitable spirit.There is no try2022-08-20T18:10:00-04:002022-08-20T18:10:00-04:00https://scottdorman.blog/2022/08/20/there-is-no-try<p>“Do. Or do not. There is no try.” That line is probably one of the most quoted lines from <em>The Empire Strikes Back</em>. The <a href="https://youtu.be/4RhmHfh7ZI8">scene</a> (from Star Wars HDR on YouTube) is only about 5 minutes long and worth watching, even if you’re already familiar with it. There are so many leadership and life lessons packed into those 5 minutes. Some may be easy to miss or overlook, and others might be misunderstood or misinterpreted.</p>
<p>The scene starts with Luke practicing his Force powers by levitating a rock in a one-handed handstand. He loses concentration when he gets distracted by the X-Wing sinking into the swamp. As Luke stands there, watching its final moments, he says, “Oh, no. We’ll never get it out now.” Like many of us, when faced with an obstacle, Luke’s first reaction is to give up. In our mind, the task is insurmountable and, therefore, impossible to do, so it’s not worth putting forth the effort to attempt it. Yoda responds by calling out his defeatist mindset, “So certain, are you? Always with you, it cannot be done. Hear you nothing that I say?” Yoda implies that Luke is listening but not hearing and that his “go-to” response is a defeatist belief that he can’t do difficult things.</p>
<p>Henry Ford said, “Whether you think you can, or you think you can’t— you’re right.” It’s all about belief and vision. If you believe you can accomplish a goal, then you’ll be able to accomplish it because, consciously or not, you’re going to take actions that move you toward that accomplishment. However, if you don’t believe you can accomplish a goal, the same thing will happen, and you’re going to take actions, consciously or not, that move you further from achieving it.</p>
<blockquote>
<p>Having a default reaction to an obstacle of “I can’t” means that, almost certainly, you won’t.</p>
</blockquote>
<p>The scene shifts now to Luke saying, “Master, moving stones around is one thing. This is totally different.” Here, Luke is justifying and rationalizing his inaction. Yes, he’s been able to move stones around using the Force, but those are just stones. They’re small. Moving an X-Wing fighter is different. Yoda’s response is, “No! No different! Only different in your mind. You must unlearn what you have learned.” Here, Yoda is trying to make Luke understand that the difference is only in his mind. To be successful, he needs to stop thinking of this task differently than moving the rocks.</p>
<p>In our life, each of us will face at least one obstacle that feels overwhelming. If we focus on the size of the problem based on a conventional understanding of it, then it will feel daunting. However, if we focus on the fact that we’ve achieved similar results on a smaller scale before and realize that the only difference is one of relative scale, we can begin to accept that this too is possible. We must leave preconceived beliefs behind and start from a fresh, unbiased, and unencumbered point of view.</p>
<blockquote>
<p>Limiting our beliefs to what is conventionally accepted does just that; it limits our belief.</p>
</blockquote>
<p>Now we’ve reached the moment in the scene that everyone loves to quote. Luke sighs and says, “All right, I’ll give it a try,” to which Yoda famously responds, “No! Try not. Do. Or do not. There is no try.” The dictionary defines try as “to make an attempt; to put effort into an action,” which implies that we can’t try without doing. Could Yoda have meant something else? If we know the outcome of a task before attempting it, do we say “I’ll try to do it” or “I will do it”? What if we don’t know the outcome beforehand? We say, “I’ll try to do it.”</p>
<p>The common belief is that when someone uses “try,” it shows they are unsure of the outcome of their actions. We say “try” because we accept that we might fail. What if, by acknowledging we might fail, we’re subconsciously setting ourselves up <em>to</em> fail? Removing the thought that we could fail, and believing that we can do it, is the best option for being able to do it. Could Yoda have been wrong when he said, “There is no try”? What if he meant that Luke could no longer let the uncertainty of the outcome be a limiting factor? To a Jedi, “trying” is believing that you can and cannot do something <em>at the same time</em>; it means not committing. Allowing doubt to cast a shadow in our lives means we’ve already accepted defeat, even if it’s subconsciously. If that sounds familiar, it should. It’s the basis for Henry Ford’s quote, which I mentioned earlier.</p>
<blockquote>
<p>Focus on the present and commit yourself; to do anything less is the same as not doing it at all.</p>
</blockquote>
<p>Luke attempts to raise the X-Wing and fails. Again, Luke justifies his failure by saying, “I can’t. It’s too big.” Yoda responds by sharing some philosophical and metaphysical wisdom about the Force. He explains to Luke that physical size isn’t important, saying, “Size matters not. Look at me. Judge me by my size, do you?” and that the Force is a “powerful ally.” He even goes so far as to say its energy “surrounds us and binds us.” In a discouraged tone, Luke tells Yoda, “You want the impossible.” When Yoda raises the X-Wing and sets it down, Luke stares in astonishment and says, “I don’t… I don’t believe it.” Yoda’s simple response is, “That is why you fail.”</p>
<p>Did Luke not believe it because he didn’t believe in himself? Earlier in the movie, we see Luke free his light saber from the ice with incredible difficulty. We have also seen him moving stones around with difficulty as well. He must have realized that Luke had a limited ability to control the Force. Why did Yoda still tell Luke to raise the X-Wing? In truth, Yoda did recognize it, but he also realized that Luke <em>could</em> lift the X-Wing. It was Luke who thought he couldn’t. What, then, was the lesson Luke needed to learn? He needed to learn how to fail.</p>
<blockquote>
<p>Knowing how to fail, accepting it, and learning from it are the only ways not to fail.</p>
</blockquote>
<p>Society, through our school systems (both public and private), our economic system, and even businesses, punish failure. We believe we get one shot, one chance, to do something. This belief leads to two mindsets: we can’t afford to fail, or that failure is inevitable, so we shouldn’t bother.</p>
<p>Neither of these mindsets is healthy. Believing we can’t afford to fail places extreme and unnecessary pressure on you to succeed, while believing failure is inevitable stagnates you and prevents you from growing. Instead, what’s needed is a mindset of accepting, and learning from, failure.</p>
<p>Luke didn’t learn from his failure because he gave up. What if he tried again? What if he asked for advice? What would the outcome have been instead?</p>
<p>Earlier, I asked if Yoda could have been wrong when he said, “There is no try.” I also mentioned that many leadership lessons in this scene could be missed or overlooked, and others might be misunderstood or misinterpreted.</p>
<p>Yoda’s famous quote might seem terse and even harsh when taken alone. However, this discussion brings an often overlooked nuance to the meaning. Trying doesn’t exist. It’s about using your skills and abilities to overcome obstacles and achieve objectives. If you already have the necessary skills, you either do it or don’t. However, if you don’t already have the skills, you either learn them and do it, or you don’t.</p>
<p>To borrow from Led Zeppelin’s famous song, <em>A Stairway to Heaven</em>, “Yes, there are two paths you can go by, but in the long run, there’s still time to change the road you’re on.” To overcome any obstacle, you must put in the work. You’re going to succeed, or you won’t. If you don’t, you change your road by figuring out what didn’t work, so you don’t make those same mistakes again and make another attempt. In either case, doubting or second-guessing yourself will guarantee you fail.</p>
<p>Luke fell victim to that. He limited himself by his preconceptions, rationalized his failure, believed the task was beyond his abilities and failed before he had even begun. In short, he thought he couldn’t, so he didn’t.</p>
<p>I challenge each of you to be better, to do better. Don’t let yourself become overwhelmed by “impossible odds” and “insurmountable challenges.” Recognize your abilities and learn them if you don’t have what’s necessary. Don’t “try” and be stuck between accomplishment and failure; commit yourself and do it.</p>
<p>In 2014, comedian Jim Carrey said in his <a href="https://www.youtube.com/watch?v=V80-gPkpH6M">MIU Commencement Address</a>, “You can fail at what you don’t want. You might as well take a chance on doing what you love.”</p>Scott Dorman“Do. Or do not. There is no try.” That line is probably one of the most quoted lines from The Empire Strikes Back. The scene (from Star Wars HDR on YouTube) is only about 5 minutes long and worth watching, even if you’re already familiar with it. There are so many leadership and life lessons packed into those 5 minutes. Some may be easy to miss or overlook, and others might be misunderstood or misinterpreted.Cadru 4.52020-09-13T17:59:00-04:002020-09-13T17:59:00-04:00https://scottdorman.blog/2020/09/13/cadru-4-5<p>It’s hard to believe that just over seven years ago, I <a href="/2013/08/05/introducing-cadru/">first released</a> Cadru as an open-source framework. In that time, there have been <a href="https://scottdorman.blog/tags/#cadru">a few updates</a>, but none as ambitious as the <a href="/2017/06/03/introducting-cadru-4-0-preview/">4.0 preview</a>. The main goal of that release, which was about three years ago, was to add support for .NET Standard and split up the project into smaller, and more focused, packages.</p>
<p>It feels like the 4.0 release has been in perpetual preview mode, with changes made periodically over that time. The most significant changes, though, have been in this past week and support the new Cadru 4.5 release.</p>
<h2 id="net-standard-support">.NET Standard support</h2>
<p>All of the projects, except one, have been updated to .NET Standard 2.1. This is a departure from the original idea of making Cadru support the broadest reach possible by targeting a “lowest common denominator” of portable APIs. With the upcoming November release of <a href="https://devblogs.microsoft.com/dotnet/introducing-net-5/">.NET 5</a>, it was time to bring Cadru into a more modern code base and make other improvements that are only available with newer language features. These changes will also allow me to update to .NET 5 more easily.</p>
<p>As of right now, <a href="https://github.com/scottdorman/cadru/tree/master/src/Cadru.Postal">Cadru.Postal</a>, is still on .NET 4.5. It’s due to be rewritten to support the <a href="https://docs.microsoft.com/en-us/aspnet/core/razor-pages/sdk?view=aspnetcore-3.1">Razor SDK</a>, but until then, it has to stay behind.</p>
<h2 id="c-80-language-features">C# 8.0 language features</h2>
<p>Updating to .NET Standard also brought with it an update to using C# 8.0 language features. One of those improvements is <a href="https://docs.microsoft.com/en-us/dotnet/csharp/nullable-references">nullable reference types</a>, enabling developers to make meaningful statements about the nullability of a reference type:</p>
<ul>
<li>A reference isn’t supposed to be null.</li>
<li>A reference may be null.</li>
</ul>
<p>By <a href="https://devblogs.microsoft.com/dotnet/embracing-nullable-reference-types/#the-nullable-rollout-phase">supporting nullable reference types now</a>, the eventual update to .NET 5, where nullable reference types are the “new normal”, will be that much easier.</p>
<p>Some of the other language features that were adopted are:</p>
<ul>
<li><a href="https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/switch-expression"><code class="language-plaintext highlighter-rouge">switch</code> expressions</a>, which allowed me to make some rather unwieldy <code class="language-plaintext highlighter-rouge">switch</code> statements much more concise and readable</li>
<li>The null-coalescing assignment operator <a href="https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8#null-coalescing-assignment"><code class="language-plaintext highlighter-rouge">??=</code></a></li>
<li>The <a href="https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/constraints-on-type-parameters#notnull-constraint"><code class="language-plaintext highlighter-rouge">notnull</code></a> and <a href="https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/constraints-on-type-parameters#unmanaged-constraint"><code class="language-plaintext highlighter-rouge">unmanaged</code></a> generic constraints</li>
<li>Improved pattern matching using the <a href="https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/is"><code class="language-plaintext highlighter-rouge">is</code></a> operator (introduced in C# 7.0). This is a really powerful operator, and I think there are many more places where I can use it for more simplification and correctness improvements.</li>
</ul>
<h2 id="new-projects-and-retired-old-ones">New projects and retired old ones</h2>
<p>There have been improvements in the project organization, including splitting things up into more projects, which also means that there are more <a href="https://www.nuget.org/packages?q=Tags:"cadru"">NuGet packages</a>. These are smaller, more focused packages that should allow for better flexibility in choosing what features you need.</p>
<ul>
<li><strong>Cadru.AspNetCore</strong> - Provides ASP.NET Core middleware and other extensions for request and/response logging.</li>
<li><strong>Cadru.AspNetCore.Mvc</strong> - Provides additional support for working with ASP.NET Core, such as custom view location expanders, support for <a href="https://docs.microsoft.com/en-us/dotnet/api/system.web.modelbinding.imetadataaware">IMetadataAware</a>, and rendering enumerated types as SelectLists based on a <a href="https://docs.microsoft.com/en-us/dotnet/api/system.componentmodel.dataannotations.uihintattribute">UiHint</a> attribute, and extensions to make working with state management a bit simpler.</li>
<li><strong>Cadru.AspNetCore.Mvc.TagHelpers</strong> - Provides additional ASP.NET Core TagHelpers.</li>
<li><strong>Cadru.Build.Tasks</strong> - Provides additional MSBuild tasks and is used to support <a href="https://github.com/scottdorman/assembly-build-versioning">assembly-build-versioning</a>.</li>
<li><strong>Cadru.Caching</strong> - Provides a standard implementation for creating and using cache keys.</li>
<li><strong>Cadru.Collections</strong> - Provides additional collection classes and extensions.</li>
<li><strong>Cadru.Contracts</strong> - Provides static classes for representing program contracts as preconditions in a way that’s compatible with System.Diagnostics.Contracts.</li>
<li><strong>Cadru.Core</strong> - Provides common extensions and new APIs for the .NET Framework.</li>
<li><strong>Cadru.Data</strong> - Provides a standard way to read Excel data and fixed width files.</li>
<li><strong>Cadru.Data.Annotations</strong> - Provides common data annotation attributes.</li>
<li><strong>Cadru.Data.Dapper</strong> - Provides a common database context and predicates for use with Dapper.</li>
<li><strong>Cadru.Environment</strong> - Provides support for determining framework versions, IIS version, and feature detection.</li>
<li><strong>Cadru.Extensions.FileProviders</strong> - Additional file providers and support for working with physical files and directories.</li>
<li><strong>Cadru.Net.Http</strong> - Provides transient error detection strategies for adding retry logic into your HttpClient calls and a UrlBuilder to help simplify building complex URLs.</li>
<li><strong>Cadru.Net.NetworkInformation</strong> - Provides access to network information and notification of network status changes.</li>
<li><strong>Cadru.Polly</strong> - Provides support for working with <a href="https://github.com/App-vNext/Polly">Polly</a> policies, including a strategy for resilient database queries.</li>
<li><strong>Cadru.Postal</strong> - Provides classes for generating email using ASP.NET MVC Razor views.</li>
<li><strong>Cadru.Scim</strong> - Support for creating System for Cross-domain Identity Management (SCIM) filters.</li>
<li><strong>Cadru.UnitTest.Framework</strong> - Provides additional assert capabilities for MS Test.</li>
</ul>
<p>While that’s a lot of packages, there are a few other changes to note:</p>
<ul>
<li><strong>Cadru.TransientFaultHandling</strong> - This package has been retired and should be replaced with <em>*Cadru.Polly</em>.</li>
<li><strong>Cadru.Net</strong> - This package is renamed to <em>*Cadru.Net.Http</em></li>
<li><strong>Cadru.Core.Windows</strong> - This package is retired, and features migrated to <strong>Cadru.Environment</strong>, <strong>Cadru.IO</strong>, and <strong>Cadru.Net.NetworkInformation</strong> as appropriate.</li>
<li><strong>Cadru.IO</strong> - This package will eventually be retired and replaced with <strong>Cadru.Extensions.FileProviders</strong>.</li>
</ul>
<h2 id="whats-next-for-cadru">What’s next for Cadru?</h2>
<p>The most significant update planned will be support for .NET 5 when it releases in November. Until then, there are a handful of known tasks still left. See the <a href="https://github.com/scottdorman/cadru/milestone/1">Cadru 5.0</a> milestone for more details. There are only a few issues in there right now, but I will be adding more over time.</p>Scott DormanIt’s hard to believe that just over seven years ago, I first released Cadru as an open-source framework. In that time, there have been a few updates, but none as ambitious as the 4.0 preview. The main goal of that release, which was about three years ago, was to add support for .NET Standard and split up the project into smaller, and more focused, packages.Database Resiliency with Polly2020-09-13T03:45:00-04:002020-09-13T03:45:00-04:00https://scottdorman.blog/2020/09/13/database-resiliency-with-polly<p>Handling errors is important to make your application more reliable. We all understand the importance of <a href="http://en.wikipedia.org/wiki/Defensive_programming">Defensive programming</a> (I <a href="/2008/07/04/what-is-defensive-programming/" title="What is "Defensive Programming"?">talked</a> about it way back in 2008), including standard programming constructions like <a href="https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/try-catch"><code class="language-plaintext highlighter-rouge">try-catch</code></a>, <code class="language-plaintext highlighter-rouge">null</code> checking, using things like <a href="https://docs.microsoft.com/en-us/dotnet/framework/debug-trace-profile/code-contracts">Code Contracts</a>), error <a href="https://docs.microsoft.com/en-us/dotnet/core/diagnostics/logging-tracing">logging and tracing</a>, and a variety of other techniques.</p>
<p>With all of that, one thing that frequently gets forgotten about is connection resiliency and fault tolerance. This applies to any action that needs a network connection to complete, such as calling REST APIs, or an external dependency, such as a database connection. Network latency, connectivity issues (short term or not), or resource throttling are just a few of the unexpected errors that can occur. While these errors are outside of our control, they’re usually transient in nature and correct themselves automatically and, most of the time, quickly.</p>
<blockquote>
<p>Resiliency is the ability to recover from failures and continue to function. It isn’t about avoiding failures but accepting the fact that failures will happen and responding to them in a way that avoids downtime or data loss. The goal of resiliency is to return the application to a fully functioning state after a failure. <small><a href="https://docs.microsoft.com/en-us/dotnet/architecture/microservices/implement-resilient-applications/">Implement resilient applications</a></small></p>
</blockquote>
<p>Although we can write custom code to handle these transient errors, that’s a time consuming and non-trivial task to do it correctly. It’s much better to use a dedicated library for such concerns. The first library (at least that I’m aware of and used) was the <a href="https://github.com/microsoftarchive/transient-fault-handling-application-block">Transient Fault Handling Application Block (“TOPAZ”)</a> from the Microsoft Patterns & Practices group. While that project was archived years ago, some of the ideas it introduced have made their way into parts of .NET Framework itself and other Microsoft cloud computing technologies. The current approach in .NET Core is to use <a href="https://github.com/App-vNext/Polly">Polly</a>, a .NET resilience and transient fault handling library. If you want to implement resilient HTTP requests using <code class="language-plaintext highlighter-rouge">IHttpClientFactory</code>, the <a href="https://docs.microsoft.com/en-us/dotnet/architecture/microservices/implement-resilient-applications/implement-http-call-retries-exponential-backoff-polly">recommended approach</a> is to use Polly policies.</p>
<p>While that’s great for HTTP based resources, what about database connections? There are many additional challenges when it comes to making resilient database queries, such as determining which errors are transient and determining the appropriate <em>strategy</em> for retying. The important part here is the word <em>strategy</em>. Retrying database access is more than catching an error and retrying the query a few times before giving up and reporting an error. It can depend on the database server, the error that occurred, and even what your application is trying to do.</p>
<p>Although the retry strategy described in <a href="https://docs.microsoft.com/en-us/azure/azure-sql/database/troubleshoot-common-errors-issues">Troubleshooting connectivity issues and other errors with Azure SQL Database and Azure SQL Managed Instance</a> is specific to Azure SQL, it applies equally well to on-premise SQL Server instance (and probably any other database back-end as well). Specifically, the strategy described is:</p>
<blockquote>
<p>It is strongly recommended that your client program has retry logic so that it could reestablish a connection after giving the transient fault time to correct itself. We recommend that you delay for 5 seconds before your first retry. Retrying after a delay shorter than 5 seconds risks overwhelming the cloud service. For each subsequent retry, the delay should grow exponentially, up to a maximum of 60 seconds.</p>
</blockquote>
<p>As you can see, that’s a non-trivial strategy to implement and requires specific retry policies in place. In searching for reasonable strategies using Polly, I came across <a href="https://stackify.com/resilient-applications-polly/">How To Build Resilient Applications with Polly</a> and <a href="https://sergeyakopov.com/reliable-database-connections-and-commands-with-polly/">Reliable Database Connections and Commands with Polly</a>. While these are good resources, they each took a slightly different approach.</p>
<p>I used the Stackify implementation, along with some of the <a href="https://github.com/vany0114/resilience-strategy-with-polly/issues/1#issuecomment-483856082">comments</a> from @reisenberger, to implement Cadru.Polly, available on <a href="https://github.com/scottdorman/cadru/tree/master/src/Cadru.Polly">GitHub</a> and as a <a href="https://www.nuget.org/packages/Cadru.Polly/">NuGet</a> package.</p>
<h3 id="sql-strategies">Sql Strategies</h3>
<p>One of the main benefits here is that it wraps the entire retry strategy, as described above, in a simple to use (at least I hope it’s simple to use) <code class="language-plaintext highlighter-rouge">SqlStrategy</code>. A <code class="language-plaintext highlighter-rouge">SqlStrategy</code> instance holds a single synchronous and asynchronous policy, built as a <a href="https://github.com/App-vNext/Polly/wiki/PolicyWrap"><code class="language-plaintext highlighter-rouge">PolicyWrap</code></a>. This allows a single policy to encapsulate the entire strategy of policies in a consistent manner. It also means that a <code class="language-plaintext highlighter-rouge">SqlStrategy</code> is database-agnostic. The specific strategies employed don’t matter to the strategy, and executing an action using a strategy is almost as simple as using a regular Polly Policy:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">sqlStrategy</span> <span class="p">=</span> <span class="n">SqlServerStrategyBuilder</span><span class="p">.</span><span class="n">Default</span><span class="p">.</span><span class="nf">Build</span><span class="p">();</span>
<span class="n">sqlStrategy</span><span class="p">.</span><span class="n">SyncPolicy</span><span class="p">.</span><span class="nf">Execute</span><span class="p">(()</span> <span class="p">=></span> <span class="nf">DoSomething</span><span class="p">());</span>
</code></pre></div></div>
<p>This code creates a default strategy for accessing a SQL Server database which handles a variety of error codes using a combination of a <a href="https://github.com/App-vNext/Polly/wiki/Timeout">Timeout</a> policy, a <a href="https://github.com/App-vNext/Polly/wiki/Retry">Retry</a>, and a series of <a href="https://github.com/App-vNext/Polly/wiki/Circuit-Breaker">Circuit Breaker</a> policies, all wrapped together in the correct order.</p>
<p>If you need to customize the strategy’s policies further, you can do so before calling <code class="language-plaintext highlighter-rouge">Build</code>. You can start with the default policies and add <a href="https://github.com/App-vNext/Polly/wiki/Fallback">Fallback</a> policies by calling one of the <code class="language-plaintext highlighter-rouge">WithFallback</code> overloads or a <a href="https://github.com/App-vNext/Polly/wiki/Timeout">Timeout</a> per retry policy by calling the <code class="language-plaintext highlighter-rouge">WithTimeoutPerRetry</code> method. Building the strategy validates the policies first, so it won’t let you include any of the default policies a second time. If you want to customize the policies completely, you can call either <code class="language-plaintext highlighter-rouge">SqlServerStrategyBuilder.Empty</code> or clear the <code class="language-plaintext highlighter-rouge">Policies</code> list on the default strategy builder. Finally, suppose you need access to the underlying Polly <code class="language-plaintext highlighter-rouge">PolicyBuilder</code>. In that case, you can call either <code class="language-plaintext highlighter-rouge">GetDefaultPolicyBuilder</code>, which will return a <code class="language-plaintext highlighter-rouge">PolicyBuilder</code> that handles the exceptions in the default exception handling strategy, or <code class="language-plaintext highlighter-rouge">GetPolicyBuilder</code>, which will return a <code class="language-plaintext highlighter-rouge">PolicyBuilder</code> that handles all of the exceptions in the collection of exception handling strategies.</p>
<h3 id="exception-handling-strategies">Exception Handling Strategies</h3>
<p>Since databases have a <em>lot</em> of errors they can raise (SQL Server has over 10,000 error messages it can raise!), I adapted a concept introduced in the Transient Fault Handling Application Block but updated it for use with Polly. To allow for flexibility in deciding what errors are considered transient, the strategy builder takes a collection of <a href="https://github.com/scottdorman/cadru/blob/master/src/Cadru.Polly/IExceptionHandlingStrategy.cs"><code class="language-plaintext highlighter-rouge">IExceptionHandlingStrategy</code></a> instances. These are simple classes that implement a <code class="language-plaintext highlighter-rouge">bool ShouldHandle(Exception)</code> delegate. If the exception passed in is one that the strategy should handle, the method returns <code class="language-plaintext highlighter-rouge">true</code>; otherwise, it returns <code class="language-plaintext highlighter-rouge">false</code>. You can take a look at <a href="https://github.com/scottdorman/cadru/blob/master/src/Cadru.Polly/Data/SqlServer/SqlServerExceptionHandlingStrategy.cs">SqlServerExceptionHandlingStrategy.cs</a> for some examples.</p>
<p>There are a lot of benefits to this approach:</p>
<ol>
<li>it allows the exceptions handled by the policy to more easily change over time without having to rewrite the entire strategy,</li>
<li>it should allow more flexibility in designing strategies for other database engines, and</li>
<li>it allows your application to customize the exceptions for your own needs without changing the core library.</li>
</ol>
<p>Since <code class="language-plaintext highlighter-rouge">SqlStrategy</code> takes a collection of strategies, the first strategy in that collection acts as the default strategy. This is the one used when you call <code class="language-plaintext highlighter-rouge">GetDefaultPolicyBuilder</code>. You can change which strategy is the default simply by passing them in a different order.</p>
<p>Out of the gate, there are four different exception handling strategies for SQL Server, each handling a different set of error numbers:</p>
<table>
<thead>
<tr>
<th>Exception Handling Strategy</th>
<th>Errors Handled</th>
</tr>
</thead>
<tbody>
<tr>
<td>SqlServerTransientExceptionHandlingStrategy</td>
<td>40501, 49920, 49919, 49918, 41839, 41325, 41305, 41302, 41301, 40613, 40197, 10936, 10929, 10928, 10060, 10054, 10053, 4221, 4060, 12015, 233, 121, 64, 20</td>
</tr>
<tr>
<td>SqlServerTransientTransactionExceptionHandlingStrategy</td>
<td>40549, 40550</td>
</tr>
<tr>
<td>SqlServerTimeoutExceptionHandlingStrategy</td>
<td>-2</td>
</tr>
<tr>
<td>NetworkConnectivityExceptionHandlingStrategy</td>
<td>11001</td>
</tr>
</tbody>
</table>
<p>If you use the standard .NET Core dependency injection mechanism, you can use the <a href="https://github.com/scottdorman/cadru/blob/f6c6f93141759acb7043376adfc9e58c7f494833/src/Cadru.Polly/Data/SqlServer/ServiceCollectionExtensions.cs#L41"><code class="language-plaintext highlighter-rouge">UseExceptionHandlingStrategies</code></a> to register these with the DI container easily.</p>
<h3 id="configuration-options">Configuration Options</h3>
<p>With so many different policies in use, configuring the various values can be done through the <a href="https://github.com/scottdorman/cadru/blob/master/src/Cadru.Polly/Data/SqlStrategyOptions.cs"><code class="language-plaintext highlighter-rouge">SqlStrategyOptions</code></a> class. If you’re using the .NET Core configuration system, you can use this class as a strongly typed configuration object and read values in from your <code class="language-plaintext highlighter-rouge">appsettings.json</code> file. An example section might look like</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="w"> </span><span class="nl">"RetryStrategy"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"RetryCount"</span><span class="p">:</span><span class="w"> </span><span class="mi">3</span><span class="p">,</span><span class="w">
</span><span class="nl">"ExceptionsAllowedBeforeBreaking"</span><span class="p">:</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w">
</span><span class="nl">"DurationOfBreak"</span><span class="p">:</span><span class="w"> </span><span class="s2">"00:00:25"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>This defines that the action will only be retried three times, that two consecutive exceptions of the same type will trip the circuit breaker, and that once tripped, the circuit will remain open for 25 seconds.</p>
<p>There are also some helpful configuration <a href="https://github.com/scottdorman/cadru/blob/master/src/Cadru.Polly/Data/SqlStrategyOptionsExtensions.cs">extensions</a> defined which encapsulate the logic of retrieving the configuration value or it’s default.</p>
<h3 id="other-polly-goodness">Other Polly Goodness</h3>
<p>To add or retrieve things from the Polly <a href="https://github.com/App-vNext/Polly/wiki/Keys-And-Context-Data">Context </a>, you might be interested in the extensions defined in <a href="https://github.com/scottdorman/cadru/blob/master/src/Cadru.Polly/ContextExtensions.cs">ContextExtensions</a>. This includes the ability to add or retrieve an <code class="language-plaintext highlighter-rouge">ILogger</code> instance using the <code class="language-plaintext highlighter-rouge">WithLogger</code>, <code class="language-plaintext highlighter-rouge">GetLogger</code>, or <code class="language-plaintext highlighter-rouge">TryGetLogger</code> methods. You can also easily get a strongly typed object from the context with the <code class="language-plaintext highlighter-rouge">TryGetValue<T></code> method or even add a collection of items to the context all at once using one of the <code class="language-plaintext highlighter-rouge">WithContextData</code> overloads.</p>
<p>If you need to bundle together a context and a policy, you can use an <a href="https://github.com/scottdorman/cadru/blob/master/src/Cadru.Polly/ExecutionEnvironment.cs"><code class="language-plaintext highlighter-rouge">ExecutionEnvironment</code> or an <code class="language-plaintext highlighter-rouge">AsyncExecutionEnvironment</code></a>.</p>
<p>Adding a <a href="https://github.com/App-vNext/Polly/wiki/PolicyRegistry"><code class="language-plaintext highlighter-rouge">PolicyRegistry</code></a> to the standard .NET Core DI mechanism can be done with the <a href="https://github.com/scottdorman/cadru/blob/f6c6f93141759acb7043376adfc9e58c7f494833/src/Cadru.Polly/ServiceCollectionExtensions.cs#L47"><code class="language-plaintext highlighter-rouge">AddPolicyRegistry</code></a> extension. There is also a factory class, <a href="https://github.com/scottdorman/cadru/blob/master/src/Cadru.Polly/Data/SqlServer/SqlServerStrategyFactory.cs"><code class="language-plaintext highlighter-rouge">SqlServerStrategyFactory</code></a>, which can be added to the DI container to easily create a strategy:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">services</span><span class="p">.</span><span class="nf">AddSingleton</span><span class="p">(</span><span class="n">serviceProvider</span> <span class="p">=></span> <span class="n">SqlServerStrategyFactory</span><span class="p">.</span><span class="n">Instance</span><span class="p">.</span><span class="nf">Create</span><span class="p">(</span><span class="n">serviceProvider</span><span class="p">));</span>
</code></pre></div></div>
<p>This takes both an <code class="language-plaintext highlighter-rouge">IServiceProvider</code> and an <code class="language-plaintext highlighter-rouge">IEnumerable<IExceptionHandlingStrategy></code> as parameters, but if you add the exception handling strategies to your DI container, the strategies will be automatically provided.</p>
<p>There’s also a <a href="https://github.com/scottdorman/cadru/tree/master/src/Cadru.Polly/Logging">logging policy</a> available, which allows you to log exceptions or handled results easily and then rethrow the exception. This is, for the most part, a direct port of what’s available in <a href="https://github.com/Polly-Contrib/Polly.Contrib.LoggingPolicy">Polly.Contrib.LoggingPolicy</a>.</p>Scott DormanHandling errors is important to make your application more reliable. We all understand the importance of Defensive programming (I talked about it way back in 2008), including standard programming constructions like try-catch, null checking, using things like Code Contracts), error logging and tracing, and a variety of other techniques.Microsoft Terminal Settings2020-05-07T14:27:00-04:002020-05-07T14:27:00-04:00https://scottdorman.blog/2020/05/07/microsoft-terminal-settings<p>A year ago, in May 2019, Microsoft <a href="https://devblogs.microsoft.com/commandline/introducing-windows-terminal/">introduced</a> the new Windows Terminal. If you haven’t checked out Windows Terminal before, it’s a multi-terminal application for users of command-line tools and shells like Command Prompt, PowerShell, and WSL. Yes, there are lots of other terminal applications out there which do the same thing, many with a lot more features, but Windows Terminal is still in a pre-release status.</p>
<p>One of the convenient features of Windows Terminal is that all of the settings are controlled by a <code class="language-plaintext highlighter-rouge">settings.json</code> file. This includes being able to define new color schemes and new terminal profiles.</p>
<p>I haven’t used Windows Terminal very often since I first installed it, falling back to my old default workflow of launching the Visual Studio Developer Command Prompt from the Start Menu shortcut. However, in the past month I’ve been using it a lot more, and have come to really like it.</p>
<p>One thing that I found lacking was public support for being able to find working (meaning correct) terminal profiles. To help with that situation, I’m happy to introduce <a href="https://github.com/scottdorman/microsoft-terminal-settings">microsoft-terminal-settings</a>. The repository has a lot of color schemes and some profiles for both the command prompt and PowerShell terminals for the various Visual Studio 2019 editions.</p>
<p>It’s still a bit nascent at the moment, consisting of just the GitHub repository, but I’ll be working on adding a GitHub Pages branch over the next week, once I decide how I want things to look, which will make it easier to preview the themes and add some polish to things. In the meantime, check out the <a href="https://github.com/scottdorman/microsoft-terminal-settings">repository</a>, <a href="https://github.com/scottdorman/microsoft-terminal-settings/issues/new">open a new issue</a> for your favorite color scheme or terminal profile or, better yet, <a href="https://github.com/scottdorman/microsoft-terminal-settings/fork">fork the repository</a> to submit your own pull requests.</p>Scott DormanA year ago, in May 2019, Microsoft introduced the new Windows Terminal. If you haven’t checked out Windows Terminal before, it’s a multi-terminal application for users of command-line tools and shells like Command Prompt, PowerShell, and WSL. Yes, there are lots of other terminal applications out there which do the same thing, many with a lot more features, but Windows Terminal is still in a pre-release status..NET Core project versioning updates2020-04-17T18:20:00-04:002020-04-17T18:20:00-04:00https://scottdorman.blog/2020/04/17/net-core-project-versioning-updates<p>About two years ago I <a href="/2018/08/20/net-core-project-versioning/">talked</a> about a way to create consistent version numbers across .NET Core and .NET Framework projects. At the time, I thought the approach I’d come up with was fairly easy to use and didn’t require much modification to your projects.</p>
<p>At the end of March 2020, GitHub announced <a href="https://github.blog/changelog/2020-03-24-github-actions-api-is-now-generally-available/">public availability of GitHub Actions</a>. While it isn’t as full-featured as other continuous integration/continuous-delivery (CI/CD) tools out there, like AppVeyor and Jenkins, it doesn’t require any additional accounts to set up, does the job adequately well for some of the more common scenarios, and seems to steadily be getting better and more full-featured.</p>
<p>I’ve setup build actions for two private repositories I work in, and after understanding how the build environments work and playing around with some of the projects in one of the repositories, I decided to revisit my assembly versioning setup.</p>
<p>This time around, it takes advantage of the actions workflow and requires even less changes to your projects.</p>
<p>One of the main changes is that the code tasks have now been moved into a compiled assembly that will become part of my Cadru Framework. This allows it to fully run from the command line through calling the <code class="language-plaintext highlighter-rouge">dotnet</code> command line tooling. The second major change is that it no longer requires you to add a project to your solution to try and hook into the build process. Since there wasn’t a reliable way to insert the target into the process of building the solution, it ended up running for each project. While this generally didn’t cause much issue, it would sometimes result in slightly different version numbers.</p>
<p>Just like with the earlier implementation, head over to the GitHub <a href="https://github.com/scottdorman/assembly-build-versioning">repository</a> and copy the contents of <code class="language-plaintext highlighter-rouge">src</code> folder (not the folder itself, just what’s in it) into your solution folder. If you don’t want the task to update a release notes XML file, you can delete the <code class="language-plaintext highlighter-rouge">ReleaseNotes.xml</code> file. Although the files have changed slightly from their earlier versions, they still work pretty much the same way.</p>
<blockquote>
<p>The original implementation is still there, but it’s under a <code class="language-plaintext highlighter-rouge">v1.0</code> branch. The <code class="language-plaintext highlighter-rouge">master</code> branch is the latest version, 2.0.</p>
</blockquote>
<p>The <code class="language-plaintext highlighter-rouge">Directory.Build.props</code> file adds new properties and item groups to every project, and defines some of the common properties used. It also imports the other properties files. There really isn’t a need to change this file.</p>
<p>The <code class="language-plaintext highlighter-rouge">common.props</code> file is where you can define the standard assembly and NuGet package properties, like product, company, copyright, and authors. You can also define the version number properties here as well.</p>
<p>Everything else about the process still lives in the <code class="language-plaintext highlighter-rouge">build</code> folder, by default. (You can change it, but doing so will require you to change some of the core targets files, so I’d suggest just leaving it where it is.) This is also where things start to change with the new implementation.</p>
<p>The first change is that <code class="language-plaintext highlighter-rouge">build.props</code> has been renamed to <code class="language-plaintext highlighter-rouge">version.props</code>. I think this name makes more sense. The name of the properties in it has also changed. A typical file looks like</p>
<pre><code class="language-XML"><Project>
<PropertyGroup>
<BuildDate>4/17/2020 8:09:02 AM</BuildDate>
<VersionPatch>20217</VersionPatch>
<VersionRevision>36371</VersionRevision>
</PropertyGroup>
</Project>
</code></pre>
<p>This file is updated once by calling <code class="language-plaintext highlighter-rouge">dotnet build /build/Cadru.VersionUpdate.targets -t:UpdateAssemblyVersionInfo</code>. That task sets the build date and computes the patch and revision numbers. Since this file is imported before <code class="language-plaintext highlighter-rouge">common.props</code>, if you set one of those properties there, the value here will be overridden.</p>
<blockquote>
<p>The version numbering scheme is loosely based on what’s done in <a href="https://github.com/dotnet/arcade">Arcade</a> and is described in the <a href="https://github.com/dotnet/arcade/blob/master/Documentation/CorePackages/Versioning.md">.NET Core Ecosystem v2 - Versioning</a> document.</p>
</blockquote>
<p>Since this file is updated “out of band” from compiling the rest of the code, it ensures that all of the projects will pick up the same version information when they’re compiled.</p>
<p>To update a release notes file, you just need to set the <code class="language-plaintext highlighter-rouge">GenerateReleaseNotes</code> property in <code class="language-plaintext highlighter-rouge">common.props</code> to <code class="language-plaintext highlighter-rouge">true</code> and then uncomment and provide values for the item group. Remember, it’s still somewhat opinionated on the format and is designed to work with an XML file. The version related properties are available to you in MSBuild, though, so if you wanted to write your own target to update a release notes file, you can look at the <code class="language-plaintext highlighter-rouge">UpdateReleaseNotes</code> in <code class="language-plaintext highlighter-rouge">Vadru.VersionUpdate.Targets</code> and update it as necessary.</p>
<p>If you only have .NET Core projects, you’re done. If you have older .NET Framework projects, you need to add the following somewhere in the project file. (I’d suggest just adding it at the end.)</p>
<pre><code class="language-XML"> <PropertyGroup>
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
</PropertyGroup>
<Import Project="$(BuildDir)\GenerateAssemblyInfo.targets"> Condition="Exists('$(BuildDir)\GenerateAssemblyInfo.targets')" />
</code></pre>
<p>If there are .NET Core projects you don’t want automatically versioned, you can opt them out by adding the following property group to the project file.</p>
<pre><code class="language-XML"><PropertyGroup>
<IgnoreVersionUpdate>true</IgnoreVersionUpdate>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup>
</code></pre>
<h2 id="planned-improvements">Planned improvements</h2>
<p>Now that I’ve simplified how things work, there are definitely some improvements I want to make.</p>
<ul>
<li>Add additional versioning strategies. Right now, there are two, both of which are date-based.</li>
<li>Add more flexibility in the creating a variant of the <code class="language-plaintext highlighter-rouge">version.props</code> file in different formats. I can see plain text and JSON formatted right now, possibly some other formats later on.</li>
<li>Improve task logging and output</li>
<li>Add more flexibility for updating a release notes document, possibly different formats as well.</li>
</ul>Scott DormanAbout two years ago I talked about a way to create consistent version numbers across .NET Core and .NET Framework projects. At the time, I thought the approach I’d come up with was fairly easy to use and didn’t require much modification to your projects.codestyle.co2019-04-04T23:20:00-04:002019-04-04T23:20:00-04:00https://scottdorman.blog/2019/04/04/codestyle-co<p>Nearly <a href="/2014/07/25/announcing-codestyle-co/">five years ago</a> I introduced <a href="https://www.codestyle.co/">codestyle.co</a>. Code style and standards has long been of mine. I’ve helped a lot of different companies create and adopt code standards and I frequently talk about them at various code camps and user groups.</p>
<p>Many of the problems I saw at the time still exist today and <a href="https://www.codestyle.co/">codestyle.co</a> continues to be a centralized place to find standards for various programming languages and (through GitHub <a href="https://github.com/scottdorman/codestyle.co/issues/">issues</a>) foster a discussion around what those standards should be.</p>
<p>I’ve just updated the site so that it’s fully hosted on GitHub Pages using Jekyll. This means that when new standards are added, the site is automatically update and gives me an easier way to mantain both the standards and the site code.</p>
<p>If you want to suggest an additional language standard be added to the site or update an existing standards document, simply <a href="https://github.com/scottdorman/codestyle.co/fork">fork the repo</a> and submit a pull request or <a href="https://github.com/scottdorman/codestyle.co/issues">submit an issue</a>.</p>Scott DormanNearly five years ago I introduced codestyle.co. Code style and standards has long been of mine. I’ve helped a lot of different companies create and adopt code standards and I frequently talk about them at various code camps and user groups.Floating Point Changes in .NET Core 3.02019-04-03T21:36:00-04:002019-04-03T21:36:00-04:00https://scottdorman.blog/2019/04/03/floating-point-changes-in-net-core-3-0<p>.NET Core 3.0 contains changes improve the parsing and formatting for floating point values. These were changes that started in .NET Core 2.1 and are now almost done, with .NET Core 3.0 being updated to be <a href="https://en.wikipedia.org/wiki/IEEE_754-2008_revision">IEEE compliant</a>. One of the biggest repercussions of this change is that the default behavior of <code class="language-plaintext highlighter-rouge">ToString</code> for floating point types (<a href="https://docs.microsoft.com/en-us/dotnet/api/system.single?view=netcore-3.0"><code class="language-plaintext highlighter-rouge">System.Single</code></a> (<code class="language-plaintext highlighter-rouge">float</code>) and <a href="https://docs.microsoft.com/en-us/dotnet/api/system.double?view=netcore-3.0"><code class="language-plaintext highlighter-rouge">System.Double</code></a> (<code class="language-plaintext highlighter-rouge">double</code>)) is to produce a roundtrippable string.</p>
<p>This is different than earlier releases of .NET and .NET Core and was <a href="https://github.com/dotnet/corefx/issues/36579#issuecomment-479661545">necessary</a> to fix a variety of issues where all of the various combinations of x86 vs x64 vs ARM vs ARM64 and Windows vs Linux vs OSX could have been returning different results for <code class="language-plaintext highlighter-rouge">ToString</code> or <code class="language-plaintext highlighter-rouge">Parse</code>.</p>
<p>To summarize the changes:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">ToString()</code>, <code class="language-plaintext highlighter-rouge">ToString("G")</code>, and <code class="language-plaintext highlighter-rouge">ToString("R")</code> will now return the shortest roundtrippable string.</li>
<li>For the <code class="language-plaintext highlighter-rouge">G</code> format specifier that takes a precision (e.g. <code class="language-plaintext highlighter-rouge">G3</code>), the precision specifier is now always respected.</li>
<li>For the <code class="language-plaintext highlighter-rouge">C</code>, <code class="language-plaintext highlighter-rouge">E</code>, <code class="language-plaintext highlighter-rouge">F</code>, <code class="language-plaintext highlighter-rouge">N</code>, and <code class="language-plaintext highlighter-rouge">P</code> format specifiers the changes are similar. The difference is that these format specifiers treat the precision as the number of digits after the decimal point, in contrast to <code class="language-plaintext highlighter-rouge">G</code> which treats it as the number of significant digits.</li>
<li>For custom format strings, they have the same behavior as before and will only print up to 15 significant digits, regardless of how many are requested.</li>
</ul>
<p>This is potentially a big breaking change for existing code, so if you use floating point types and rely on the output of <code class="language-plaintext highlighter-rouge">ToString</code> or perform string parsing, you should update your code to handle these changes, if possible. If it’s not possible, you may have to update your code to implement a workaround.</p>
<p>There were already parsing differences across various operating systems (i.e. Linux, Windows, macOS, etc) and architectures (i.e. x86, x64, ARM, ARM64, etc), so it’s not possible to fallback to the old behavior.</p>
<p>To get equivalent behavior for formatting differences:</p>
<ul>
<li>For <code class="language-plaintext highlighter-rouge">ToString()</code> and <code class="language-plaintext highlighter-rouge">ToString("G")</code> you can use <code class="language-plaintext highlighter-rouge">G15</code> as the format specifier.</li>
<li>For <code class="language-plaintext highlighter-rouge">ToString("R")</code> there is no fallback.</li>
<li>For the <code class="language-plaintext highlighter-rouge">G</code> format-specifier that takes a precision, you can force precisions greater than 15 (exclusive) to be exactly 17. For example, if your code is doing <code class="language-plaintext highlighter-rouge">ToString("G20")</code> you can instead change this to <code class="language-plaintext highlighter-rouge">ToString("G17")</code>.</li>
<li>For the remaining format-specifiers that take a precision (<code class="language-plaintext highlighter-rouge">C</code>, <code class="language-plaintext highlighter-rouge">E</code>, <code class="language-plaintext highlighter-rouge">F</code>, <code class="language-plaintext highlighter-rouge">N</code>, and <code class="language-plaintext highlighter-rouge">P</code>) there is no fallback.</li>
</ul>
<p>For more details about these changes, see Tanner Gooding’s <a href="https://devblogs.microsoft.com/dotnet/floating-point-parsing-and-formatting-improvements-in-net-core-3-0/">post</a> or the GitHub <a href="https://github.com/dotnet/corefx/issues/36579">issue</a>.</p>Scott Dorman.NET Core 3.0 contains changes improve the parsing and formatting for floating point values. These were changes that started in .NET Core 2.1 and are now almost done, with .NET Core 3.0 being updated to be IEEE compliant. One of the biggest repercussions of this change is that the default behavior of ToString for floating point types (System.Single (float) and System.Double (double)) is to produce a roundtrippable string.Language Specs2019-04-02T11:49:00-04:002019-04-02T11:49:00-04:00https://scottdorman.blog/2019/04/02/language-specs<p>Nearly <a href="/2017/02/11/language-specs-info/">two years ago</a> I introduced <a href="https://www.languagespecs.info/">Language Specs</a>. At that time, I’d been helping Microsoft move their language specs for C# and VB to markdown and hosted on GitHub. The website acts as your “one stop shop” for finding the official language specs for a variety of popular programming languages. The specs themselves aren’t hosted here, that is still left up to the individual language maintainers.</p>
<p>I’ve just updated the site, which included moving to a fully GitHub Pages hosted site, and added 10 new languages.</p>
<p>If you want to suggest an additional language spec be added to the site, simply <a href="https://github.com/scottdorman/languagespecs.info/fork">fork the repo</a> and submit a pull request or <a href="https://github.com/scottdorman/languagespecs.info/issues">submit an issue</a>.</p>Scott DormanNearly two years ago I introduced Language Specs. At that time, I’d been helping Microsoft move their language specs for C# and VB to markdown and hosted on GitHub. The website acts as your “one stop shop” for finding the official language specs for a variety of popular programming languages. The specs themselves aren’t hosted here, that is still left up to the individual language maintainers.Introducing Essential Extensions2019-03-20T04:31:00-04:002019-03-20T04:31:00-04:00https://scottdorman.blog/2019/03/20/introducing-essential-extensions<p>It’s been several years (and a few Visual Studio versions) since I last blogged about my <a href="/2014/10/05/favorite-visual-studio-extensions/">favorite visual studio extensions</a> and a lot has changed since then. This time around, rather than just listing my favorites, I decided to create some public <a href="https://marketplace.visualstudio.com/publishers/ScottDorman">Visual Studio Extensions</a> that make it easy to get Visual Studio setup with all of the different extensions.</p>
<p>I’m officially introducing Essential Extensions, which are a set of extension packs to create the ultimate Visual Studio editor experience. These extension packs require Visual Studio 2017 Update 8 or newer.</p>
<p>Each extension pack in Essential Extensions has a different focus.</p>
<h3 id="essential-extensions-core">Essential Extensions (Core)</h3>
<p>An extension pack to improve the core Visual Studio editing experience. Download it at the
<a href="https://marketplace.visualstudio.com/items?itemName=ScottDorman.EssentialExtensions">Visual Studio Marketplace</a>
or get the
<a href="http://vsixgallery.com/extension/B485A30F-B8A4-4508-B2B3-D96D529171DD/">nightly build</a>. See the
<a href="https://github.com/scottdorman/essential-extensions/blob/master/src/EssentialExtensions/CHANGELOG.md">changelog</a>
for changes and roadmap.</p>
<h3 id="essential-extensions-web">Essential Extensions (Web)</h3>
<p>An extension pack to improve the Visual Studio editing experience for web development. Download it at the
<a href="https://marketplace.visualstudio.com/items?itemName=ScottDorman.EssentialExtensionsWeb">Visual Studio Marketplace</a>
or get the
<a href="http://vsixgallery.com/extension/673DC35F-A9E2-426B-98AF-27F51190D0B4/">nightly build</a>. See the
<a href="https://github.com/scottdorman/essential-extensions/blob/master/src/EssentialExtensions.Web/CHANGELOG.md">changelog</a>
for changes and roadmap.</p>
<h3 id="essential-extensions-github">Essential Extensions (GitHub)</h3>
<p>An extension pack to improve the Visual Studio experience for development using GitHub as the source control system. Download it at the
<a href="https://marketplace.visualstudio.com/items?itemName=ScottDorman.EssentialExtensionsGitHub">Visual Studio Marketplace</a>
or get the
<a href="http://vsixgallery.com/extension/E7813D68-135F-4B0D-828F-5287F3228885/">nightly build</a>. See the
<a href="https://github.com/scottdorman/essential-extensions/blob/master/src/EssentialExtensions.GitHub/CHANGELOG.md">changelog</a>
for changes and roadmap.</p>
<h2 id="suggest-new-extensions">Suggest new extensions</h2>
<p>If you know of any good extensions that you think would benefit developers, <a href="https://github.com/scottdorman/essential-extensions/issues">submit an issue</a>.</p>Scott DormanIt’s been several years (and a few Visual Studio versions) since I last blogged about my favorite visual studio extensions and a lot has changed since then. This time around, rather than just listing my favorites, I decided to create some public Visual Studio Extensions that make it easy to get Visual Studio setup with all of the different extensions.