Wednesday, 30 August 2017

ADO.Net Async with Transactions... A Lesson Learned

Last night I was testing out a new WebApi Filter I've added to a project, its fairly simple, log some data that comes from a HTTP header to the DB.

This particular project has no Entity Framework or anything, just simple ADO.Net, in fact I think the project has 3 stored proc's in total.

I tend to Async all the things by default so when I originally wrote my DB code I had:

using (var conn = new SqlConnection(_connectionString))
{
     await conn.OpenAsync();
     using (var transaction = conn.BeginTransaction())
     {
          var command = conn.CreateCommand();
          command.CommandText = "[Api].[LogDeviceRequest]";
          command.CommandType = System.Data.CommandType.StoredProcedure;
          command.Transaction = transaction;

          command.Parameters.AddWithValue(//etc 
          try
          {
             await command.ExecuteNonQueryAsync();
          }
          catch
          {
             transaction.Rollback();
             throw;
          }
          transaction.Commit();
      } 
 } 

Looks fairly harmless.

Initial testing of me just poking around with my app showed it to be OK so I was happy and released it.... 20 mins later I had a shock when I looked at my DB looking unhappy.

Uh Oh....
Some very pretty locks there....

So I immediately started to look at my query, its fairly basic, if something exists update a timestamp, else insert new row. I tinkered with it and stopped it doing a key lookup but that wasn't the cause of the issue.

It was getting late so I decided to turn the feature back off and look at it again with fresher eyes this evening.

When looking at it this evening I realised I was calling the code above without awaiting it, I was simply firing and forgetting. Nothing obvious jumped out at me, until I removed the async parts of the code and made it syncronous. The deadlocks then went away. I could have left it like this but I wanted to see if I could make it async again more so for piece of mind.

Whilst sat pondering over this I remembered how async/await will by default try to return to the original syncronisation context after its await. https://blogs.msdn.microsoft.com/pfxteam/2012/04/12/asyncawait-faq/ explains alot of these things. I then had a theory (that wasn't based in a lot of knowledge but investigated anyway) that perhaps the transaction context and my syncronisation context was somehow messed up, was it trying to return on the original ASP.Net syncronisation context.

To test this I simply altered my await statements in the code above to use .ConfigureAwait(false);
When you do this you are telling .Net that you don't have to continue on the original SyncronisationContext continue on what ever you want.

Initial testing seemed fine again, so I deployed and triggered a load test (which previously gave deadlocks within minutes) to find the deadlocks all gone.

This does seem to point to the transactions not being committed properly and hanging around for a while, maybe when its trying to get back to the SyncronisationContext. A very weird issue, I wonder if its related to the issue TransactionScope has with async pre .Net 4.5.1. Hopefully someone can tell me :)

Hope this helps someone, it certainly reminds me to test things under load :)

Thursday, 24 August 2017

Playing further with ASP.Net Core whilst on my hols... VSCode fun and cool new Anti Forgery Validation

I'm on vacation, 10 days in Norfolk with extremely limited connectivity and action packed days with the kids. Whilst here on two nights everyone has fallen asleep before me so I decided it would be a good time to poke around further at ASP.Net Core as I've still not produced any production code with it yet, only small samples.

Now I don't have my laptop on me but I do an old one that's here purely for any work emergencies and for childcare emergencies, (you know the ones, its 6am and the 2 year old is awake, peppa pig at 6am is an emergency!). This means I have literally nothing on me and I can only tether internet via my wife's iPhone 6 which has barely a bar of signal, this rules out a cloud VM running VS. So I turned to VSCode, its sooo lightweight its easy to download, install and run on this laptop. Get the .Net Core 2.0 SDK and the VSCode C# extension and you are literally running within 30 mins.

I won't go to much into the projects setup and stuff as its well documented but I want to highlight a few things I've stumbled upon and thought worth sharing.

Installing Packages

In Visual Studio I would just use the Nuget package manager UI to manage all of my dependencies, I know I could use the package manager console but I've become lazy and use my mouse too much..... But in VSCode this doesn't exist without further extensions.

So how do you install packages?

Turns out its really simple, bring up your terminal window (be this console, powershell, bash etc) and use the .Net Core CLI. You simply type:

dotnet add package [packagename]

where [packagename] is what you want to install. This then uses Nuget to find the package and install appropriately. Very quick and powerful.

Anti-Forgery Validation

If you have done any ASP.Net MVC applications you have discovered and used Anti Forgery Validation. I won't go into the details as many places discuss its benefits and importance. Within ASP.Net Core I've found things have improved further. Previously with Razor you had the @HTML.AntiForgeryToken helper syntax and attributes which you start to litter your views and controllers with.

Within ASP.Net Core things have been tidied up, Red Gate have a great post covering the specifics, but essentially if you use the asp tag helpers to generate a form post url (which you almost always will be when building mvc applications) and add a global anti forgery filter you never have to worry about decorating actions with attributes or using the html helpers within your razor views. You get excellent protection pretty much for free which is ace!

That's it for tonight, I'll blog more as I try out more :)

Wednesday, 16 August 2017

Code therapy brought to you this week by .Net Core 2

So the last week has been hard going so tonight I decided to have some code therapy. I've been meaning to explore .Net Core 2 further and decided tonight was the time to port a library I had written in Mono for Raspbian over to .Net Core land.

It's worth noting that .Net Core 2 is only in preview on Raspbian but thats good enough for me ;)

Getting Started

First things first I updated VS2017 to the latest update 3 release. My Visual Studio wasn't telling me the update was available so I simply got the web installer again from VisualStudio.com and it advised VS was already installed and could be updated. This took about 35 mins on my Dell XPS 13 laptop but on my SurfacePro 3 its taken nearly an hour.

.Net Standard Choices
I then chose to create a new .Net Standard project but found I couldn't target .Net Standard 2. Turns out Update 3 doesn't include .Net Core 2 you need to go get this from: https://www.microsoft.com/net/core#windowscmd

You can now choose .Net Standard 2.0

I then created Classic .Net Console Application and a .Net Core Console Application to use my class library in.

Adding a reference for the .Net Standard library in Classic .Net Console Application is easy enough,  References > Add Reference but when it came to .Net Core I had to look twice. In .Net Core References is gone, its replaced by Dependencies. Dependencies nicely wraps up project references, service references and Nuget Packages. So right click Dependencies and you get the famiiar Add Reference.

Where's References Gone... Oh There You Are!

Porting My Library

So to start with I just grabbed the code from my Mono project and dropped it into the new Standard Library, it was easier to avoid any complications by simply copy/pasting the files, I have no doubt I could have messed around with the old project to make it a standard one but why gamble.

I then thought lets do a build and see what doesn't work, its a very simple project, basic models, interfaces, but I do use Process.StartNew new to call out and grab some info using Bash on Raspbian, I expected this to have some quirk or API change.

Turns out it built perfectly, 0 build errors, 0 warnings. Crazy.

Next I implemented a very basic console app, again same code in both applications and ran both applications. Spot the difference....



Same output the only difference is how the app is ran, in the classic world we compile an executable where as an net core app is compiled to a dll which is then ran via the dotnet cli.

Next Steps

I now wanted to get this running on my Raspberry Pi, the classic console application can be ran via Mono, this just got a 5.2 release. For the .Net Core Console app I needed to ensure its compiled for ARM32, to do this I used the .Net CLI and published the application. Rather than repeat how to do this Microsoft have all of this on GitHub.

Conclusion

I'm very impressed with how compatible .Net Core 2.0 is , this was a very small library that ported seemlessly but this really opens up the migration path for many of my other ones and begins to make me think I need to rely on Mono far less. I'm looking forward to the future.