Showing posts with label C#. Show all posts
Showing posts with label C#. Show all posts

Wednesday, September 14, 2016

Accessing an authenticated S3 file in Xamarin

Context

I have a S3 JSON file that I need to access from a Xamarin Forms mobile application.  My S3 resource is not a public resource, its protected and requires credentials to be able to access it.  There is another Windows Desktop application that will upload this file periodically, and the mobile app must only have read only access to the file.

Note: no special authentication is required to access public (unprotected) S3 files.

Setting up S3 and Credentials

The AWS portal offers a free plan to store up to 5GB of storage for 12 months.  After that it'll depend on number of requests and storage size. For me, for a 100Kb file accessed maybe 100 times a month, it'll be approximately 5 cents per month based on the calculator.

To access protected (non-public) data in S3 you'll need to set up users and access tokens.
Users are created with the AWS IAM service.  This is a pretty straight forward process, I needed two users, one with full access, and one with read only access.  To do this you need to attach an appropriate policy to the user, the read only policy is shown here:

Once this policy is attached, user will have read only access to everything stored in the S3 account.  
The next step is to generate an access token. This is done with the Security Credentials tab.


Managing Files in S3

Again this is very simple so not much detail here.  There are a couple of basics to be aware of.  You first choose where your data is stored geographically (ie Sydney, Oregon, Tokyo to name a few) and is not mirrored between regions (but this can be set up).  Data is stored inside "Buckets" - think folder.  Although you can't nest. Files can then be uploaded and accessed inside these buckets.
The red line is obscuring my chosen bucket name (because its top secret), and you can see the file name shown in the list.

Using the AWS S3 SDK

Writing a C# desktop application is pretty easy with the AWS SDK, certainly no challenges.

To be able to access the file created above here's all we need:
     private const string AwsBucketName = "XXXXXXXXXsummary";  
     private const string AwsBucketFileName = "MobileDataExport.json";  
     public async Task UploadDataFileAsync(string data, string storageKeyId, string storageSecret, string region)  
     {  
       var regionIdentifier = RegionEndpoint.GetBySystemName(region);  
       using (var client = new AmazonS3Client(storageKeyId, storageSecret, regionIdentifier))  
       {  
         try  
         {  
           var response = await client.GetObjectAsync(AwsBucketName, AwsBucketFileName);  
           using (var reader = new StreamReader(response.ResponseStream))  
           {  
             Debug.WriteLine(await reader.ReadToEndAsync());  
           }  
         }  
         catch (AmazonS3Exception amazonS3Exception)  
         {  
           if (amazonS3Exception.ErrorCode != null &&  
             (amazonS3Exception.ErrorCode.Equals("InvalidAccessKeyId") || amazonS3Exception.ErrorCode.Equals("InvalidSecurity")))  
           {  
             throw new SecurityException("Invalid Amazon S3 credentials - data was not uploaded.", amazonS3Exception);  
           }  
           throw new HttpRequestException("Unspecified error attempting to upload data: " + amazonS3Exception.Message, amazonS3Exception);  
         }  
       }  

  • storageKeyId is the access token generated earlier. AWS IAM calls this the Access Key ID.
  • storageSecret is the access token secret generated ealier. AWS IAM calls this the Secret Access Key.
Easy, huh.

The bad news, is that this doesn't work in Xamarin, as the AWS SDK has an incomplete portable class library port.  If you try to use the SDK in a PCL or a Xamarin native project you will get NotImplementedExceptions.


AWS Mobile Recommended Approach

AWS recommend you use their Cognito service to authenticate for Mobile and for Xamarin.  There's a good set of instructions here:
http://docs.aws.amazon.com/mobile/sdkforxamarin/developerguide/setup.html

There's a couple of issues with this however.  At the time of writing the docs are a little out of date and don't match the Cognito console web site, which makes things a little difficult to follow.  (I have sent them feedback on this issue).
Also, more importantly, AWS Cognito is currently only available in the US East (N. Virginia), EU (Ireland), and Asia Pacific (Tokyo) regions. This doesn't work for me as I need to use AWS Sydney.

The Solution

Fortunately, AWS does have some comprehensive instructions how to craft and pass in the right HTTP headers so you can do everything yourself.  Also, its worth noting that Postman supports AWS authentication natively which is pretty handy for testing and to see example requests.

The AWS Roll Your Own Headers Instructions

This approach, I think, has a couple of redeeming attributes: Its lightweight, and no extra dependencies are required.  Its also easy to take the headers and use your favourite REST testing tool.

 using System;  
 using System.Diagnostics;  
 using System.Net.Http;  
 using System.Text;  
 using System.Threading.Tasks;  
 using BAXMobile.Model;  
 using JetBrains.Annotations;  
 using Newtonsoft.Json;  
   
 namespace BAXMobile.Service  
 {  
   public class AmazonS3BaxSummaryDataService : IBaxSummaryDataService  
   {  
     private readonly IHashingAlgorithm hashingAlgorithm;  
     private readonly string accessKey;  
     private readonly string secret;  
     private const string TargetAwsRegion = "ap-southeast-2";  
     private const string TargetAwsService = "s3";  
     private const string Aws4HasingAlgorithm = "AWS4-HMAC-SHA256";  
     private const string Aws4Request = "aws4_request";  
   
     private const string Host = "XXXXXXXXsummary.s3-ap-southeast-2.amazonaws.com";  
     private static string resourcePath = "/MobileDataExport.json";  
   
     public AmazonS3BaxSummaryDataService([NotNull] IHashingAlgorithm hashingAlgorithm, [NotNull] string accessKey, [NotNull] string secret)  
     {  
       if (hashingAlgorithm == null) throw new ArgumentNullException(nameof(hashingAlgorithm));  
       if (accessKey == null) throw new ArgumentNullException(nameof(accessKey));  
       if (secret == null) throw new ArgumentNullException(nameof(secret));  
       this.hashingAlgorithm = hashingAlgorithm;  
       this.accessKey = accessKey;  
       this.secret = secret;  
     }  
   
     public async Task<SummarisedLedgerMobileData> DownloadDataAsync()  
     {  
       string jsonData;  
       // following instructions from http://docs.aws.amazon.com/general/latest/gr/sigv4_signing.html  
       using (var client = new HttpClient())  
       using (var request = new HttpRequestMessage(HttpMethod.Get, "https://" + Host + resourcePath))  
       {  
         var dateTime = DateTime.UtcNow.ToString("yyyyMMddTHHmmssZ");  
         var date = DateTime.UtcNow.ToString("yyyyMMdd");  
   
         client.BaseAddress = new Uri("https://" + Host);  
   
         var requestPayloadHash = CalculateHash(string.Empty); // My request, as its a GET, will be empty, so hash an empty string. Yep thats correct.  
   
         var canonicalisedResource = GetCanonicalisedResource(Host, dateTime, requestPayloadHash);  
         var hashedCanonicalisedRequest = CalculateHash(canonicalisedResource);  
   
         var stringToSign =  
           $"{Aws4HasingAlgorithm}\n"  
           + $"{dateTime}\n"  
           + $"{date}/{TargetAwsRegion}/{TargetAwsService}/{Aws4Request}\n"  
           + hashedCanonicalisedRequest;  
   
         var signature = GetSignatureKey(this.secret, date, TargetAwsRegion, TargetAwsService, stringToSign);  
         var authHeaderString = $"{Aws4HasingAlgorithm} Credential={this.accessKey}/{date}/{TargetAwsRegion}/{TargetAwsService}/{Aws4Request}, SignedHeaders=host;x-amz-date, Signature={signature}";  
   
         request.Headers.Host = Host;  
         request.Headers.Add("X-Amz-Date", dateTime);  
         request.Headers.Add("X-Amz-Content-Sha256", requestPayloadHash);  
         request.Headers.TryAddWithoutValidation("Authorization", authHeaderString);  
         // Note that Content-Type cannot be added to GET request using HttpClient - using Content-Type does seem to be common in examples found on the web including GET requests.  
   
         var response = await client.SendAsync(request);  
         jsonData = await response.Content.ReadAsStringAsync();  
       }  
   
       return JsonConvert.DeserializeObject<SummarisedLedgerMobileData>(jsonData);  
     }  
   
     private string CalculateHash(string canonicalisedResource)  
     {  
       return ToHex(hashingAlgorithm.ComputeSha256Hash(Encoding.UTF8.GetBytes(canonicalisedResource)));  
     }  
   
     private string GetCanonicalisedResource(string host, string date, string requestPayloadHash)  
     {  
       var canonicalisedResource = "GET\n" // Http Request Method   
                     + $"{resourcePath}\n" // Url to file  
                     + "\n" // Query string - blank in this case  
                     + $"host:{host}\n"  
                     + $"x-amz-date:{date}\n\n"  
                     + "host;x-amz-date\n" // headers that will be included in the request and signature calc  
                     + requestPayloadHash; // Hashed payload of the request - in my case empty string  
       return canonicalisedResource;  
     }  
   
     private string ToHex(byte[] data)  
     {  
       string hex = BitConverter.ToString(data);  
       return hex.Replace("-", "").ToLower();  
     }  
   
     private byte[] HmacSha256(string data, byte[] key)  
     {  
       return this.hashingAlgorithm.ComputeHmacSha256Hash(data, key);  
     }  
   
     private string GetSignatureKey(string key, string dateStamp, string regionName, string serviceName, string stringToSign)  
     {  
       var secret = Encoding.UTF8.GetBytes(("AWS4" + key).ToCharArray());  
       var date = HmacSha256(dateStamp, secret);  
       var region = HmacSha256(regionName, date);  
       var service = HmacSha256(serviceName, region);  
       var derivedSigningKey = HmacSha256(Aws4Request, service);  
       var signature = ToHex(HmacSha256(stringToSign, derivedSigningKey));  
       return signature;  
     }  
   }  
 }  
   

The AWS Access Key and its Secret are passed into the function.
I also pass in a IHashingAlgorithm. While .NET does have the correct SHA hashing classes these classes are not available in PCL. However they are available in Mono, so using Dependency Injection, you can defer the hashing to the iOS or Android projects.

   //Note: System.Security.Cryptography is not PCL compliant and cannot be used in any PCL. But, it can be used from the Android project because a port of it is available in Mono.  
   public interface IHashingAlgorithm  
   {  
     byte[] ComputeSha256Hash(byte[] data);  
     byte[] ComputeHmacSha256Hash(string data, byte[] key);  
   }  

   public class AndroidHashingAlgorithm : IHashingAlgorithm  
   {  
     private static readonly SHA256 HashingFunction = SHA256.Create();  
   
     public byte[] ComputeSha256Hash(byte[] data)  
     {  
       return HashingFunction.ComputeHash(data);  
     }  
   
     public byte[] ComputeHmacSha256Hash(string data, byte[] key)  
     {  
       var algorithm = "HmacSHA256";  
       var kha = KeyedHashAlgorithm.Create(algorithm);  
       kha.Key = key;  
   
       return kha.ComputeHash(Encoding.UTF8.GetBytes(data));  
     }  
   }  

Hope that helps someone.

Thursday, July 21, 2016

AndroidDeploymentException: [INSTALL_FAILED_UPDATE_INCOMPATIBLE]

Xamarin.AndroidTools.AndroidDeploymentException: InternalError ---> Mono.AndroidTools.InstallFailedException: Failure [INSTALL_FAILED_UPDATE_INCOMPATIBLE]

I've come across this problem several times with different physical Android devices.  This message is thrown when a real production Google Play App with the same App Id has been installed and then you try to install a debug version.  It will happen with any means of deploying a debug version including with Visual Studio, Xamarin Studio, and the command tools.

I think what is happening is that Android is not happy with a debug version being deployed over the top of a properly signed and deployed version of a Play Store App.  Android stores a flag to block further install attempts for that App Id.  When an App deployment attempt is made, the flag that Android created is not reset.

To fix this, you will need to reinstall the App from Google Play and then uninstall it normally. After that you'll be able to debug your App with Visual Studio.

Sunday, July 17, 2016

More Common Xamarin Forms Project problems

As a follow on from Resolving Common Issues Loading Xamarin Samples here are some other issues I seem to be commonly running into. These issues are not only referring to Xamarin samples, but to any Xamarin project.

Corrupt Xamarin-Android ZIP files

Another common problem seems to be with corrupt Xamarin-Android SDK zip files located here:
C:\Users\<Your Username>\AppData\Local\Xamarin\zips
You'll see an error message similar to "...zip file "C:\Users\<Your Username>\AppData\Local\Xamarin\zips\1FD832DCC1792D8ACA07FAC3259FC5A9.zip" is corrupt.

Deleting all the zip files in that folder will cause them to be downloaded again during the next build within Vs.  This will make the next build very slow for obvious reasons. Let it run its course, and resist the temptation to cancel it. It could take 20minutes or more. After they are downloaded and cached in that folder again, build speed will be back to normal.



Error "aapt.exe" exited with code -1073741819.

Another common symptom is build errors in the Android generated file Resource.cs file.
The following error will be generated if there are dashes "-" in any file in the Resource/Drawables folders.

Android SDK Updates

Generally if an error follows an Android SDK update it is most likely related to new build and SDK tools being used just installed/updated.  Like the above error the most likely symptom of this is errors from the generated file Resource.cs file in your Android project.
First try running a Clean build then a Rebuild.If that doesn't work the best bet might be to revert back to a previous version of the SDK Build tools. Also check forums.xamarin.com.


Error The "XamlCTask" task failed unexpectedly.

System.IO.FileNotFoundException: Could not load file or assembly 'Mono.Cecil, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756' or one of its dependencies. The system cannot find the file specified.
File name: 'Mono.Cecil, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756'
Resolved by Deleting the entire packages folder contents and allowing a build to restore all packages.

Sunday, April 24, 2016

Resolving common issues loading Xamarin Forms 2.0+ examples

After downloading and trying to run through a few Xamarin Forms demos, I've found that upgrading them to Forms 2.x seems to create errors.  Also you can encounter these errors even if you don't upgrade to the latest version of Forms. These issues will tend to focus on Android.

Issue 1: System.IO.FileNotFoundException: 

Could not load assembly 'Microsoft.Windows.Design.Extensibility, Version=4.3.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. Perhaps it doesn't exist in the Mono for Android profile?

Just delete the references which ends with *.Design. In my project it was: Xamarin.Forms.Core.Design,
Xamarin.Forms.Xaml.Design, 
Xamarin.Android.Support.Design.

See Also


Issue 2: Resources.String.ApplicationName and Resources.String.Hello are not defined

global::MYNAMESPACE.Resource.String.ApplicationName = global::MYNAMESPACE.Android.Resource.String.ApplicationName;

If you are getting an undefined error for either a resource string "Hello" or "ApplicationName" you have this issue.  These strings do not appear to be defined anywhere in the application code. Deleting it from the Resources.cs doesn't resolve the issue as it will just come back next time you build.
Fix it by running a clean and rebuild.

See also

Issue 3: Unsupported Android Target version.

If either the targeted version, or compile using version are set to a version of Android that your locally installed Android SDK doesn't support.  This is fixed either by installing that version using the Android SDK Manager or setting the Target and Compile versions in the Android project properties to something you do have locally installed.

 This App has an unsupported compile target.

Start the Android SDK Manager from Visual Studio

Or from Windows Start.

You can see here my current setup doesn't support Jelly Bean.  

In this case I chose to compile using Marshmallow, which is supported by my current setup.

Issue 4: Not configured to Deploy on Run (F5).

If you expect the App to compile, deploy and run when you press F5 or "Run" on the toolbar and it doesn't, then you'll need to adjust the build options.

You can see in this screen shot the Android project is not configured to deploy automatically when it is "Run".  Tick the box highlighted above, and you're set.



Monday, April 18, 2016

Data Binding - The Awesome Sauce lavished onto Xamarin Forms

There are some great resources around introducing Data Binding for Xamarin Forms.  Here are some great posts I've come across that are worth reading and bookmarking.

For some background on getting started with Xamarin Forms. Check out the Xamarin guide here:
https://developer.xamarin.com/guides/xamarin-forms/

Xamarin have a solid section that gives a good start into learning XAML and Data Binding here:
https://developer.xamarin.com/guides/xamarin-forms/user-interface/xaml-basics/
Its definitely worth reading through all six sections.
Part 1. Getting Started with XAML
Part 2. Essential XAML Syntax
Part 3. XAML Markup Extensions
Part 4. Data Binding Basics
Part 5. From Data Binding to MVVM
Part 6. Compiling XAML

Data Binding Controls to each other to prevent/reduce writing code-behind.
https://blog.xamarin.com/advanced-data-binding-for-ios-android-and-windows/

Awesome Xamarin Forms How-To Commands

Recently read a great blog from David Britch giving a comprehensive guide to using commands with Xamarin Forms.

https://blog.xamarin.com/simplifying-events-with-commanding/

Fresh Essentials for Xamarin Forms

Michael Ridland has recently blogged about a nice light weight library of essential and commonly used converters, controls and utilities.

http://www.michaelridland.com/xamarin/freshessentials-for-xamarin-forms-the-must-have-nuget-for-forms/

Saturday, April 9, 2016

Simple Xamarin Forms Demo App

A Simple Xamarin Forms Sample App


Recently I presented a short Xamarin Forms introduction.  It was only a short 30min taster, but I wanted to ensure I was showing something a little deeper than a simple "Hello World" App.  I personally find those kind of demo's too basic and not enough to get a taste of how using a technology is going to suit real world work.

Here's the App I built for the demo:

https://github.com/Benrnz/CorporateBsGenerator


Demo points

  1. Solution structure of a Xamarin Forms App.
  2. Entry point - how does it start and choose the first Xaml page?
  3. Anatomy of a Xaml page.
  4. Xaml Basics
    1. Root elements, in this case a ContentPage. Other options are MasterDetailPage, TabbedPage, and NavigationPage.
    2. Setting Page Padding to different values for each platform.
    3. Layout Controls: In this case we're using a AbsoluteLayout and a StackLayout.  Another common Layout is Grid.
    4. Labels, Styles, and basic value DataBinding.
    5. Using different buttons for iOS and Android.  The Material Design Floating Action Button.
    6. Binding can be used for more than value binding. The FAB has a bound reference to the ListView.
  5. Code Behind
    1. Great to get started
    2. Event Handlers
    3. Best Practice - Code behind doesn't scale well.  The MVVM pattern.
  6. A look at more advanced customisation for Android. A Custom Renderer to create a Floating Action Button.
  7. Tooling - What do we need to develop and test an App?

Sunday, April 3, 2016

Floating Action Button in Xamarin Forms

I'm loving experimenting with Xamarin Forms at the moment. So when I wanted to include a Floating Action Button (FAB) in Android versions of a Forms App, I naturally wanted to try to get this working with Forms first.  I realise you can use Xamarin Native Android views in a Forms App, but I enjoy XAML and creating reusable controls.

My first port of call was James Montemagno's GitHub and blog and found his examples for a FAB.

https://github.com/jamesmontemagno/FloatingActionButton-for-Xamarin.Android
He does mention he ported this code from: https://github.com/makovkastar/FloatingActionButton

This looks perfect, but I wanted to improve the Forms example to be mostly XAML based and try to best encapsulate the events into the FAB control to minimise the amount of work the consuming developer has to do.

Here's my code so far.
https://github.com/Benrnz/XamlFloatingActionButton

Its far from perfect, but works great.  Be aware however, that if your ObservableCollection has duplicate values in it, the FAB will exhibit unexpected hide/show behaviour.

Here's what I ended up with in my XAML:

  <AbsoluteLayout VerticalOptions="FillAndExpand"  
           HorizontalOptions="FillAndExpand">  
     <StackLayout AbsoluteLayout.LayoutFlags="All"  
            AbsoluteLayout.LayoutBounds="0,0,1,1">  
       <Label Text="FAB Test 1"  
           VerticalOptions="Center"  
           HorizontalOptions="Center" />  
       <ListView x:Name="MainList"   
            ItemsSource="{Binding MyItems}"  
            VerticalOptions="FillAndExpand"/>  
     </StackLayout>  
     <fabTest1:FloatingActionButtonView x:Name="Fab"   
                       AbsoluteLayout.LayoutFlags="PositionProportional"   
                       AbsoluteLayout.LayoutBounds="1,1,AutoSize,AutoSize"  
                       ImageName="ic_add.png"  
                       ColorNormal="#ff3498db"  
                       ColorPressed="Black"  
                       ColorRipple="#ff3498db"  
                       Command="{Binding FabExecuteCommand}"  
                       ParentList="{Binding Source={x:Reference MainList}, Path=.}"/>  
   </AbsoluteLayout>  

Tuesday, March 15, 2016

Initial Learnings Setting Up For Xamarin

I've been gearing up some work projects as well as some home projects recently to use Xamarin.  Specifically, of special interest to me is Xamarin Forms. In my opinion this is a truly incredibly useful technology.

But first, inevitably, there is some setup and familiarisation to get through before getting into code.  Here are some of my random findings during this process.

The Xamarin trial period is too short.

Its fantastic there actually is a trial period. However there's quite a bit of learning and discovery to do, and 30 days is just not enough.  Its an amazing product well worth the money, so don't be afraid to jump in.  The Xamarin.com web site pricing indicates pricing per month, but you must sign up for a full year however.

The Android SDK Emulator is still shocking.

Glaciers move faster than the default Android SDK Emulator.  There is wide recognition of this, but in the few years I've been involved in mobile development, it hasn't really improved.  The number of how-to web pages describing performance tweaks seems to back this up as well.

TIP: Fortunately there is a decent Andriod Simulator now for Visual Studio.  It can be downloaded and installed separately here.
The good news: It even integrates into Visual Studio Community edition and Xamarin Studio.  The bad news: It doesn't work with operating systems that don't support Hyper-V (which include Windows 10 Home see here).

TIP: Don't close the Emulator when you're finished debugging, running code again with Visual Studio or Xamarin Studio will redeploy and reattach much faster than re-opening it.

Creating New Projects in Xamarin Studio.

Xamarin Studio doesn't set all the same defaults as Visual Studio.  

TIP: I had to manually tick the box to deploy my application when I 'F5' or click the Debug button. The Deploy box needs to be ticked.

TIP: Using File-New-Project in Xamarin Studio doesn't create any Windows flavoured Apps. Also if the Apple build server isn't available at the time, you won't get an iOS App project either.  I've had some trouble using Visual Studio File-New-Project with creation errors and PowerShell errors (which is probably issues with my rig rather than Vs), but Xamarin Studio has worked every time.

Visual Studio vs Xamarin Studio on Windows

I've been impressed with Xamarin Studio so far.  If you're a fan of Visual Studio like me, don't be tempted to write it off.  Xamarin Studio presents a very clean and simple IDE with full intelli-sense support.  I couldn't fault it creating new prototype Apps and debugging worked seemlessly everytime. It even can deploy and debug code to the new Visual Studio Android Emulator. 

On the downside, Xamarin Studio does not have a XAML designer at all, which is a real negative for me.  Another obvious issue is that any iOS Xamarin native development can only be performed on Xamarin Studio on a Mac.  (Any shared iOS/Android PCL development can be done on Windows however). Also, only a Mac can build the native iOS binaries.  Both Xamarin Studio and Visual Studio can use a Mac remotely on the LAN to trigger a build.  The iOS Simulator can only be used locally on a Mac however.

I don'y miss R# that much its stops me from using Xamarin Studio, but any kind of XAML editing I prefer Visual Studio. Anecdotally, I do believe Xamarin Studio performs better than Visual Studio.

Resharper tends to show phantom errors

Not sure what's going on with R#, but with my version, 10.0.2 I occasionally see red squiggly underlines indicating errors on methods that are building and functioning fine. No solution for this so far, but its not a show-stopper for me.

TIP: When building for the first time in Visual Studio, I had some phantom errors showing up which are coming from R#.  To get rid of them I changed the build error filter to "Errors Only"; it was defaulting to "Errors+Intellisense".

Thats all I have for now, more learning still to do, so I'll have more to say in the near future.

Sunday, August 9, 2015

Convert existing event handler invocations to C#6 Null Propagation

Search for:

if \(handler \!= null\)\s*\r?\n\s*\{\r?\n\s*handler\((?<args>.*?)\);\r?\n\s*\}
and replace using:
handler?.Invoke(${args});

For example, this will be matched and replaced

if (handler != null)
{
    handler(this, new DialogResponseEventArgs(id, true));
}

with this
handler?.Invoke(this, new DialogResponseEventArgs(this.dialogCorrelationId, message.Response == ShellDialogButton.Cancel));

Converting existing code to use C#6 Expression Bodied Properties

Converting all types of Simple Properties

Search for

[^\S\r\n]+(?<accessor>\w+)(?<override> override | )(?<typename>\w+) (?<pname>.*?)\r?\n\s*\{\r?\n\s*get(\r?\n)*\s*\{\s*return (?<returnexpr>.*?);\s*\}\s*\}
and replace with
${accessor} ${override}${typename} ${pname} => ${returnexpr};

For example the following properties will be matched and converted:

public override string Description 
{
    get 
    {
        return "The quick brown fox jumped over the lazy dog.";
    }
}
public string Description 
{
    get 
    {
        return "The quick brown fox jumped over the lazy dog.";
    }
}
public string Description 
{
    get { return "The quick brown fox jumped over the lazy dog."; }
}
public bool HasValue 
{
    get { return this.field; }
}
public virtual IEnumerable<BudgetBucket> Buckets
{
    get { return this.lookupTable.Values.OrderBy(b => b.Code).ToList(); }
}

All the above are changed to the new syntax:
public override string Description => "The quick brown fox jumped over the lazy dog.";

Converting existing code to use nameof() in C# 6

Now with the new C#6 nameof operator, the use of ArgumentNullExceptions and ArgumentExceptions become more flexible and resistant to variable refactoring and renaming.

ArgumentNullException

Here's a regex to search and replace in Visual Studio usage of ArgumentNullException: Search for:
throw new ArgumentNullException("(?<message>.*?)
Replace with:
throw new ArgumentNullException(nameof(${varname})

For example this will replace this
throw new ArgumentNullException("variable", "This variable cannot be null.");
with
throw new ArgumentNullException(nameof(variable), "This variable cannot be null.");

ArgumentException

Here's another regex to search and replace usage of ArgumentException: Search for:
throw new ArgumentException\("(?<message>.*?)", "(?<varname>.*?)"
Replace with:
throw new ArgumentException("${message}", nameof(${varname})
For example this will replace this
throw new ArgumentException("This argument is invalid for some weird reason.", "variable");
with
throw new ArgumentException("This argument is invalid for some weird reason.", nameof(variable));

Sunday, August 10, 2014

How to use MsTest and NUnit Initialisation Methods

How to use the available initialisation methods in both MSTest and NUnit can be a little confusing when learning how to write effective tests. Effective tests are designed, just like production code, shared code should be in one place (DRY) and initialisation should be separate so to make tests less brittle.

Imagine if every test constructs an object like so:

var subject = new Foo();

Also imagine that the Foo class has decent number of methods to test.  One day a developer adds a parameter to the Foo constructor.  Now many tests are broken and require the same change. If the initialisation code is in one place this would have been a fast fix:- these tests are less brittle.

It would be handy to run some code before each test, some only once per class, and sometimes you need to initialise something before you run any tests.

First up its important to note some semantic behavour of all xUnit frameworks.
Every test will run in its own instance of the test class.  No two tests share the same instance.  When a test is finished running the instance is available for garbage collection. This means that any instance fields or properties are not shared between the tests in a class.  This is by design and cannot be configured. This is mostly to isolate one test from another, but another reason for this is to support running tests in parallel on multiple threads, although MsTest and NUnit do not run tests in parallel by default, although they both can.

MsTest

In MsTest here's the low-down on the available initialisation methods:

  • TestInitialize
  • ClassInitalize
  • AssemblyInitialize
  • TestCleanUp
These attributes are only recognised inside a class decorated with [TestClass].

TestIntialize

[TestInitialize]
public void TestInitialise() 
{
    // Your initialisation code here
}

This method will run before every test. This is normally the best place to set up test data, mocks, and instantiate the subject under test.  Sometimes, if possible, execution of the subject method can be done here as well so that each test only contains an assert. This has very similar to class's constructor, and both can be used, but its considered best practice to use the TestInitialise and not use constructors on Test Classes.

ClassInitialize


[ClassInitialize]
public static void ClassInitialise(TestContext context)
{
    // Your initialisation code here
}


This method will run once per class only, its very similar to a Type-Constructor. This can be used to initialise any static fields and properties in the test class. The TestContext argument primarily allows output to the MsTest console log.

AssemblyInitialize


[TestClass]
public class Global
{
    [AssemblyInitialize]
    public static void AssemblyInitialise(TestContext context)
    {
        // Your initialisation code here
    }
}

This method will run only once per Unit Test Assembly per test run.  Only one AssemblyInitialize method can exist per unit test assembly (or an exception is thrown when a test run starts). It is considered best practice to put this method into an easy to find Global class with no other tests. The TestContext argument primarily allows output to the MsTest console log.  I personally find this handy for registering AutoMapper configuration before running any tests involving mappers.

TestCleanUp

[TestCleanup]
public void TestCleanUp()
{
    // Your clean up code here
}

This is useful when you need to dispose any instance fields or properties, or reset anything back to a known state. Use with caution though, use if this method could be a "smell" that your tests are not isolated from dependencies like database and third-party services.
Along with TestCleanUp you can also use the ClassCleanUp attribute.  I'm not a fan of this, I've never had a good reason to use it.  To me, it indicates use of a static dependency and that doesn't sit well with my style.

Here's how the Sequence unfolds

Lets use a test to show the sequence of method calls.


    [TestClass]
    public class Global
    {
        [AssemblyInitialize]
        public static void AssemblyInitialise(TestContext context)
        {
            Debug.WriteLine("Assembly Initialise");
        }
    }

    [TestClass]
    public class SemanticTest
    {
        private int counter;
        private Guid id;

        public SemanticTest()
        {
            this.id = Guid.NewGuid();
        }

        [ClassInitialize]
        public static void ClassInitialise(TestContext context)
        {
            Debug.WriteLine("Class Initialise");
        }

        [TestMethod]
        public void Test1()
        {
            Debug.Write("Test1 ");
            this.counter++;
            Debug.WriteLine("Counter: {0} Id:{1}", this.counter, this.id);
        }

        [TestMethod]
        public void Test2()
        {
            Debug.Write("Test2 ");
            this.counter++;
            Debug.WriteLine("Counter: {0} Id:{1}", this.counter, this.id);
        }

        [TestMethod]
        public void Test3()
        {
            Debug.Write("Test3 ");
            this.counter++;
            Debug.WriteLine("Counter: {0} Id:{1}", this.counter, this.id);
        }

        [TestMethod]
        public void Test4()
        {
            Debug.Write("Test4 ");
            this.counter++;
            Debug.WriteLine("Counter: {0} Id:{1}", this.counter, this.id);
        }

        [TestMethod]
        public void Test5()
        {
            Debug.Write("Test5 ");
            this.counter++;
            Debug.WriteLine("Counter: {0} Id:{1}", this.counter, this.id);
        }

        [TestCleanup]
        public void TestCleanUp()
        {
            Debug.WriteLine("TestCleanUp " + this.counter);
        }

        [TestInitialize]
        public void TestIninitalise()
        {
            Debug.WriteLine("Test Initialise");
        }
    }

The output is:
Assembly Initialise
Class Initialise
Test Initialise
Test1 Counter: 1 Id:fb05338c-b64e-4f30-bdbb-22f4c35749b1
TestCleanUp 1
Test Initialise
Test2 Counter: 1 Id:c207ef4b-83c1-4909-828b-10a7a43ef653
TestCleanUp 1
Test Initialise
Test3 Counter: 1 Id:07e5ddd0-6f3d-4e32-bd2d-2a9544e8bd51
TestCleanUp 1
Test Initialise
Test4 Counter: 1 Id:73e703a9-9c6b-4b02-8cb5-433c8c64167e
TestCleanUp 1
Test Initialise
Test5 Counter: 1 Id:37124412-e593-4ba2-8d28-6421d32117c8
TestCleanUp 1

Here its plain to see all tests ran in their own instance of the SemanticTest class.

NUnit

All the above behaves identically in NUnit. Here are the equivalent attributes in NUnit as compared to MsTest.
  • SetUp == TestIntialize
  • TestFixtureSetUp == ClassInitialize
  • SetUpFixture == AssemblyInitialize
    Although in NUnit, SetUpFixture is scoped to a namespace not an entire assembly, which allows multiple SetUpFixture per assembly, but only one per namespace.
  • TearDown == TestCleanUp



See Also

Friday, January 17, 2014

Using Performance Counters in .NET


Why use performance counters?

I have good logging you say, excellent traceability in my database, if need be I can attach Ants Profiler, I don't need performance counters.  Not true. Every application that runs on a server and serves multiple users should be load tested.  A few definitions first:
Load testing is not using the Performance Analyser in Visual Studio or Ants Profiler.  This is merely looking for memory leaks and bad performance for a single user.  Still good to do, but doesn't replace load testing.
To be able to load test and understand the results you need to be able to measure throughput and the most likely individual performance of specific tasks while the rest of the system is under load.
Performance counters are the easiest way to monitor throughput and performance of a running system in real time.  It could be achieved with logging to files or database, but why bother? Most load testing tools capture performance monitor data and later analysis, and previous test data doesn't pollute later tests.

What else are they good for? 

Even for single user applications performance counters can be a convenient way to measure individual intensive tasks within the application.  Its also a good way to measure if running tasks in parallel is better than not.

Why not, they're easy to use and there's some free stuff

There's a huge array of standard performance counters that come with the OS and with .NET, that are very useful.  Counters to measure processor utilisation, number of logical threads created, memory usage, GC stats, and ASP.Net requests per second, and % of WCF throttles used.  Basically only code that you have written inside your app won't be measured.  Writing your own performance counters is dead easy, and there isn't much code that invades into your source to make it happen. 


var perfCounter = new PerformanceCounter("My App Name", "Counter 1", false);
perfCounter.Increment();

Watching Performance Counters

To view performance counters and watch live data coming through use PerfMon. This is part of Windows OS.


Gotchas:

  1. You may need to reboot after installing a performance counter with the OS.  It may appear in the PerfMon list, but no data comes through.  A reboot will likely fix this, it did for me.
  2. Admin priviledges will be required to install custom performance counters into the OS and delete them.  This works in code, but isn't a great idea to run / require production apps to use admin credentials.  To update performance counter data the app only needs to be a member of the Performance Log Users Group.
  3. There are some random gaps sometimes in the counters, but in my experience never more than a few minutes.

Download my sample code

Other References:

Thursday, November 14, 2013

Get ListboxItem from a the bound SelectedItem


In my case the ListBox is bound to an IEnumerable<Transaction>.  Where Transaction is a custom type in my domain model.

        <ListBox x:Name="TransactionListBox"
                     ItemsSource="{Binding Statement.Transactions}"
                     SelectedItem="{Binding SelectedTransaction}" />
... 
        private ListBoxItem GetSelectedListBoxItem()
        {
            object transaction = this.TransactionListBox.SelectedItem;
            return (ListBoxItem) this.TransactionListBox.ItemContainerGenerator.ContainerFromItem(transaction);
        }

Get DataGridCell given row and column index


        private static DataGridCell GetCell(DataGrid grid, DataGridRow row, int column)
        {
            if (row != null)
            {
                var presenter = GetVisualChild<DataGridCellsPresenter>(row);

                if (presenter == null)
                {
                    grid.ScrollIntoView(row, grid.Columns[column]);
                    presenter = GetVisualChild<DataGridCellsPresenter>(row);
                }

                var cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column);
                return cell;
            }
            return null;
        }

Find a Child Element in the Visual Tree Programmatically


        private static T GetVisualChild<T>(Visual parent) where T : Visual
        {
            T child = default(T);
            int numVisuals = VisualTreeHelper.GetChildrenCount(parent);

            for (int i = 0; i < numVisuals; i++)
            {
                var v = (Visual) VisualTreeHelper.GetChild(parent, i);
                child = v as T;
                if (child == null)
                {
                    child = GetVisualChild<T>(v);
                }
                if (child != null)
                {
                    break;
                }
            }
            return child;
        }

Finding a DataGridRow based on row index in WPF


        private static DataGridRow GetRow(DataGrid grid, int index)
        {
            var row = (DataGridRow)grid.ItemContainerGenerator.ContainerFromIndex(index);
            if (row == null)
            {
                // May be virtualized, bring into view and try again.
                grid.UpdateLayout();
                if (index >= grid.Items.Count)
                {
                    index = grid.Items.Count - 1;
                }

                grid.ScrollIntoView(grid.Items[index]);
                row = (DataGridRow)grid.ItemContainerGenerator.ContainerFromIndex(index);
            }
            return row;
        }