Wednesday, May 23, 2018

Intro to Cake: Cross Platform Build Automation in C# [video]

This is a version of my "Intro to Cake" presentation redone for YouTube. 

In case you aren't aware (or missed my post Why Use Cake? 4 Reasons.), Cake is fantastic tool for automating the compilation, test, package, and deploy of .Net projects.  In the presentation I explore the why and what of Cake (C# Make), and compare it with popular build automation solutions like powershell, make, ant, psake, and VSTS tasks or Jenkins plugins.

Friday, May 11, 2018

Why Use Cake? 4 Reasons.

Continuous Integration servers like Team City or Visual Studio Team Services can provide an incredible amount of power.  They can distill a breathtaking range of devops complexity to a few checkboxes thanks to tasks or 3rd party plug-ins.

Unfortunately, many build managers fail to realize that GUI-based plugins (or using Continuous Integration Logic to coin a phrase) comes at a cost.  Until recently, I certainly didn't recognize these costs.  Cake and other make-like tools reduce these costs.  Here are the 4 main reasons I prefer make-like tools:

Embed from Getty Images

1. Reduce Vendor Lock-In


And in the darkness bind them

On my current project we've changed CI platforms twice in the last two years due to changing InfoSec requirements.  It was a large amount of work to build a cross platform mobile devops pipeline in the first place, but to rebuild it two more times after that was a staggering amount of rework.

If there's one thing I've learned through this experience it's this: my ideal CI server build definition now consists of a single task: Run Make-Like Tool.  In my case that tool happens to be Cake, because it's based in C#, it's cross platform and open source, and it has a gigantic set of plugins for accomplishing a wide range of tasks in the .Net toolchain and beyond.

But regardless of which Make-Like tool you use: ant, gradle, rake, psake, fake, etc, the point is that by eliminating a CI Server's custom tools and marketplace plugins, you reduce dependence on a particular  CI server, eliminate vendor lock in, and increase portability.  Then should you ever be forced to move from the cloud to in-house or back the migration will be a small effort.

2. Democratize DevOps


In my experience most teams end up with one owner of the build pipeline.  If something breaks or a developer adds a feature that requires build script changes then nothing can move forward until the build manager, or BM if you will, can investigate.

But what happens if the BM is on vacation?  What happens if they're overloaded fighting fires, deploying builds, or fixing production servers that just went offline?  What happens if they get hit by a bus?

When we moved away from custom Jenkins tasks to Cake on my last project, the build scripts became available to every developer.  And because the build automation scripts were in the exact same language (C#) and location (source control) as the production system code, regular developers felt more comfortable jumping in and contributing, fixing, and extending as necessary.

The evolution reminded me of  projects where database access was once owned exclusively by stored procedure writing DBA's.  When those projects moved to ORM, at first there was fear that everyone would break everything.  Very quickly, however, the removal of strict firewalls replaced fear with flexibility, deadlocks with agility, and hard dependencies with increased productivity.  Some people became less busy, others became more so, but overall the project moved noticeably faster.

3. Reduce Impedance Mismatch


Imagine you're tasked with implementing a feature that affects both production code and the build automation process -- something like crash reporting, swapping unit testing frameworks, or incorporating build environment information into the app (e.g. use a green background if in UAT).  In a world of extensive Continuous Integration Logic you (or a BM) must create a custom build definition for the feature branch for testing.  Then when you move the feature to the develop branch you must remember to update the associated build definitions there.  Then you have to remember to update again when you merge to master, and possibly again for release branches.

The problem is that production code is frequently tightly coupled with build automation logic whether you like it or not, yet build definitions stick rigidly with a particular branch -- they fail to move with production code.

By placing all build automation logic in scripts that live under the same source control as production code you can leverage the tight coupling instead of fighting it.  Build automation logic will flow smoothly through branches and merges, and no one ever needs to remember to update build definition logic, since all build definitions are identical.

And, as a bonus feature because your scripts are under source control you get version history, you can do a blame to determine that: oh yea, it was actually you that wrote that crap.

4. Simplify Debugging


The best part of moving to make-like scripts and eliminating Continuous Integration Logic is improving the "developer experience".  When things go wrong on a CI server with custom logic you can't set breakpoints, environmental differences are inaccessible, logging options are limited, and you frequently have to wait very long times to see the results of any changes (i.e. the build manager inner loop, to coin another phrase).

With Cake I get feedback fast.  I can start a debugging session and inspect variables.  I can temporarily remove time consuming dependent tasks whose output I happen to know is cached.  I never have to wait for other people's builds to complete.  Also, having IntelliSense (code completion) is a productivity boost, and having the flexibility of writing my own custom plugins in C# has been extremely powerful.

Summary


The hidden costs of Continuous Integration Logic may not exceed their convenience for every project.  However, having seen the pain first-hand on several occasions, my preference will be for make-like tools on all future projects.  I've also migrated all my personal projects to Cake knowing it'll be the last CI migration they'll need.  That is a great feeling.

Hopefully this post has helped illuminate some hidden costs of which you were unaware.  If I missed one, or you disagree, please respond in the comments to start a discussion, or hit me up on twitter.

Monday, April 30, 2018

How To Push Updates to Raspberry Pi UWP Apps in Prod

Updating Raspberry Pi apps in the field can be tricky.  This post covers the general problem and address some specific side-loading problems you are likely to run into.


The (Re)Deployment Problem


Imagine you have an IoT app like a kiosk, digital sign, or temperature reader that you want to productize and ship onto small (inexpensive) devices like Raspberry Pi's.  If you're already in the Microsoft ecosystem or you want features like BitLocker, Automatic Updates, or Enterprise Data Protection (the ability to remote wipe a lost device), then the Windows IoT operating system is an obvious choice (plus the Windows IoT Core edition is free).

But once you've developed your app and are ready to ship, how do you quickly and consistently get your app (or more likely a set of foreground and background apps) onto devices?  More importantly, when you have a bug fix or feature enhancement how do you push it out to devices in the field?

The Initial Image


In most regards, the Microsoft documentation on building Windows IoT images is excellent. After installing some prerequisite software, you use a set of provided command line tools to create numerous xml files that all together describe an image.  You then compile those xml files into a multi-gigabyte .ffu image file that you can write to an SD Card using the Windows IoT Core Dashboard software (or better yet, the flashsd command line tool).

Now you can plug your newly flashed SD cards into a bunch of Raspberry Pi's and send them all over the world.  However, unless you're Chuck Norris, you're going to need to ship bug fixes to those Raspberry Pi's, and visiting each one is out of the question.  There are two primary options: store-based, and side loading.

Store-Based Updates


Microsoft allows developers to publish Windows IoT apps to the Microsoft Store, at which point it will push app updates down onto device and install them automatically.  This option is extremely secure and reliable.  However, there are several downsides.


  1. There's a special sign up process that can be time consuming.  I imagine it's gotten better, but it took me several weeks to get approved.  
  2. Background apps require extra work to publish because each one requires a special empty Foreground UWP app that developers must submit to the store (see Special Instructions for Headless Apps).  
  3. It's tricky to get multiple dependent apps to publish simultaneously as a package.  
  4. Updates require an approval process and on top of that can take up to 24 hours to get pushed to devices.


Side Loading Updates


If you need complete control over the deployment process, for instance to ensure that multiple dependent packages upgrade in a certain order, then there is an additional option.  You can manage your own app deployments using the PackageManager API along with a special .appxmanifest permission that allows side-loading app updates.  Naturally, you'll need a server for hosting your app update files and informing your clients that an update is available.  You then create a background UWP app that monitors your server and downloads and installs packages when it detects changes.

While this option has the benefit of more control, keep in mind the following disadvantages:


  1. Hand rolling the side loading code opens the attack surface for your app.
  2. You'll have to maintain a dedicated server and ssl certificate
  3. It may be more brittle as the entire process could break if your URL changes, SSL certificate expires, or something breaks in your upgrader background app


Matthijs Hoekstra beautifully documents one way to do this in his blog post Auto updater for my side loaded UWP Apps.  His approach involves sending notifications to the updater background app using the UWP App-To-App Communication approach I described in a Visual Studio Magazine article I published last year.

If you prefer having a single app both monitor changes and install updates, thus isolating all deployment responsibilities into a single app, you may want to take a look at the SirenOfShame.Uwp.Maintenance project of the Siren of Shame UWP App.   If you check out that code, you'll see I download the app to a temporary directory (perhaps a new UWP requirement), provide a lot of logging, and use certificate pinning for better security.  I designed that project to be generic enough that you could copy-paste it into a new project and only make a few changes.

Regardless, if you combine side-loading and image creation you are likely to run into problems.  Here are the problems and solutions I've found.

Problems


Package failed updates


ErrorCode = -2147009293
System.Runtime.InteropServices.COMException (0x80073CF3): Package failed updates, dependency or conflict validation.

You'll get this error when you include an appx in your image instead of an appxbundle.  Including an appx is what they tell you to do in Step 4 of Lab 1b when they say "Generate app bundle: Never".  The problem is you can only side-load an appxbundle if you originally installed an appxbundle.  To get around this ignore the directions and set "Generate app bundle" to "Always" when you generate your app to include in your image.  When you run the newAppxPkg command you can just reference your appxbundle instead of your appx and everything works exactly the same from there.

Removal failed


ErrorCode = -2147009286
System.Runtime.InteropServices.COMException (0x80073CFA): Removal failed. Please contact your software vendor.

You'll get this error if you try to uninstall a package via PackageManager.RemovePackageAsync() that had been installed into an image as an appx.  Instead, always include an appxbundle instead of an appx when you build images (see above).

Install failed


ErrorCode = -2147009287
System.Runtime.InteropServices.COMException (0x80073CF9): Install failed. Please contact your software vendor.

You'll get this error if you try to sideload via .UpdatePackageAsync() an app that you initially included in an image but then you subsequently F5 deployed over top of from Visual Studio.  The solution here is to put a try/catch around your call to .UpdatePackageAsync() and if there's a COMException try to do an uninstall and then an install.

Summary


I've spent numerous hours getting this process right and I hope this document saves someone some time.  If so please share your IoT deployment experience in comments or ping me @lprichar.

Monday, January 29, 2018

Securing Communications via Certificate Pinning in UWP

Embed from Getty Images

If you've ever clicked the "Decrypt HTTPS Traffic" button in Fiddler you know how extremely easy it is to initiate a man-in-the-middle attack, and watch (and even modify) the encrypted traffic between an application and a server.  You can see passwords and app private information and all kinds of very interesting data that the app authors probably never intended to have viewed or modified.

It's also easy to protect against against man-in-the-middle attacks, but few apps do.

For instance, I own a Ring doorbell and have the Ring (UWP) app installed in Windows so I can (among other things) ensure when outgoing Siren of Shame packages are picked up by the post  Here's a recent HTTPS session between the app and the server:


I wonder what would happen if I modified the value of "bypass_account_verification" to True upon requests to https://api.ring.com/clients_api/profile?  You can do that type of thing with little effort in the FiddlerScript section, which I show in a supplementary episode of Code Hour:





If you're writing an app, your risk of man-in-the-middle attacks isn't limited to curious developers willing to install a Fiddler root certificate in order to hide all HTTPS snooping errors.  Consider this scary and articulate stack overflow answer:

Anyone on the road between client and server can stage a man in the middle attack on https. If you think this is unlikely or rare, consider that there are commercial products that systematically decrypt, scan and re-encrypt all ssl traffic across an internet gateway. They work by sending the client an ssl cert created on-the-fly with the details copied from the "real" ssl cert, but signed with a different certificate chain. If this chain terminates with any of the browser's trusted CA's, this MITM will be invisible to the user.

The under-utilized solution for app developers is: certificate pinning.

UWP Pinning?  No Soup For You


Certificate pinning, or public key pinning, is the process of limiting the servers that your application is willing to communicate with, primarily for the purpose of eliminating man in the middle attacks.

If the Ring app above had implemented certificate pinning, then they would have received errors on all HTTPS requests that Fiddler had intercepted and re-signed in transit.  My personal banking app in Windows does this and on startup gives the error "We're sorry, we're unable to complete your request.  Please try again" if it detects that the signing certificate isn't from whom it should be (even if it is fully trusted).

Implementing certificate pinning is usually pretty easy in .Net.  Typically it involves the ServerCertificateVerificationCallback method on the ServicePointManager.  It then looks something like this:

public static async void Main(string[] args)
{
    // Set callback (deleagte)
    ServicePointManager.ServerCertificateValidationCallback = PinPublicKey;

    WebRequest request = WebRequest.Create("https://...");
    WebResponse response = await request.GetResponseAsync();
    // ...
}

private static bool PinPublicKey(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
    if (certificate == null || chain == null)
        return false;

    if (sslPolicyErrors != SslPolicyErrors.None)
        return false;

    // Verify against known public key within the certificate
    String pk = certificate.GetPublicKeyString();
    return pk.Equals(PUB_KEY);

}

That works for all requests in the AppDomain (which, incidentally, is bad for library providers, but convenient for regular app developers).  You could also do it on a request by request basis by setting the ServerCertificateCustomValidationCallback method of the HttpClientHandler for an HttpClient (see example below).

Either way, notice the GetPublicKeyString() method.  That's a super-useful method that'll extract out the public key so you can compare it with a known value.  As OWASP describes in the Pinning Cheat Sheet, this is safer than pinning the entire certificate because it avoids problems if the server rotates it's certificates.

That works beautifully in Xamarin and .Net Core.  Unfortunately, there's no ServicePointManager in Universal Windows Platform (UWP) apps.  Also, as you'll see we won't be given an X509Certificate object so getting the public key is harder.  There's also virtually zero documentation on the topic and so the following section represents a fair amount of time I spent fiddling around.

UWP Certificate Pinning Solved (Kinda)


As described by this Windows Apps Team blog there are two HttpClients in UWP:

Two of the most used and recommended APIs for implementing the HTTP client role in a managed UWP app are System.Net.Http.HttpClient and Windows.Web.Http.HttpClient. These APIs should be preferred over older, discouraged APIs such as WebClient and HttpWebRequest (although a small subset of HttpWebRequest is available in UWP for backward compatibility).

If you're tempted to use System.Net.Http.HttpClient because it's cross platform or because you want to use the ServerCertificateCustomValidationCallback method I mentioned earlier, then you're in for a unpleasant surprise when you attempt to write the following code:

HttpMessageHandler handler = new HttpClientHandler
{
    ServerCertificateCustomValidationCallback = OnCertificateValidate
};

var httpClient = new System.Net.Http.HttpClient(handler);

UWP will give you this response:

System.PlatformNotSupportedException: The value 'System.Func`5[System.Net.Http.HttpRequestMessage,System.Security.Cryptography.X509Certificates.X509Certificate2,System.Security.Cryptography.X509Certificates.X509Chain,System.Net.Security.SslPolicyErrors,System.Boolean]' is not supported for property 'ServerCertificateCustomValidationCallback'.

Even using Paul Betts' awesome ModernHttpClient doesn't get around the problem. The only solution I've found is to use the Windows.Web.Http.HttpClient and the ServerCustomValidationRequested event like this:

using (var filter = new HttpBaseProtocolFilter())
{
    // todo: probably remove this in production, avoids overly aggressive cache
    filter.CacheControl.ReadBehavior = HttpCacheReadBehavior.NoCache;
    filter.ServerCustomValidationRequested += FilterOnServerCustomValidationRequested;
    var httpClient = new Windows.Web.Http.HttpClient(filter);
    var result = await httpClient.GetStringAsync(new Uri(url));
    // always unsubscribe to be safe
    filter.ServerCustomValidationRequested -= FilterOnServerCustomValidationRequested;

Notice the CacheControl method.  I thought I was going mad for a while when requests stopped showing up in Fiddler.  Turns out Windows.Web.Http.HttpClient's cache is so aggressive that unlike System.Net.Http.HttpClient, it won't make subsequent requests to a url it's seen before, it'll just return the previous result.

The last piece of the puzzle is the FilterOnServerCustomValidationRequested method and how to extract a public key from a certificate without the benefit of of an X509Certificate:

private void FilterOnServerCustomValidationRequested(
    HttpBaseProtocolFilter sender, 
    HttpServerCustomValidationRequestedEventArgs args
    ) {

    if (!IsCertificateValid(
        args.RequestMessage, 
        args.ServerCertificate, 
        args.ServerCertificateErrors))
    {
        args.Reject();
    }
}

private bool IsCertificateValid(
    Windows.Web.Http.HttpRequestMessage httpRequestMessage, 
    Certificate cert, 
    IReadOnlyList sslPolicyErrors)
{
    // disallow self-signed certificates or certificates with errors
    if (sslPolicyErrors.Count > 0)
    {
        return false;
    }

    // by default reject any requests that don't use ssl or match up to our known base url
    if (!RequestRequiresCheck(httpRequestMessage.RequestUri)) return false;

    var certificateSubject = cert?.Subject;
    bool subjectMatches = certificateSubject == CertificateCommonName;

    var certificatePublicKeyString = GetPublicKey(cert);
    bool publicKeyMatches = certificatePublicKeyString == CertificatePublicKey;

    return subjectMatches && publicKeyMatches;
}

private static string GetPublicKey(Certificate cert)
{
    var certArray = cert?.GetCertificateBlob().ToArray();
    var x509Certificate2 = new X509Certificate2(certArray);
    var certificatePublicKey = x509Certificate2.GetPublicKey();
    var certificatePublicKeyString = Convert.ToBase64String(certificatePublicKey);
    return certificatePublicKeyString;
}

private bool RequestRequiresCheck(Uri uri)
{
    return uri.IsAbsoluteUri &&
        uri.AbsoluteUri.StartsWith("https://", StringComparison.CurrentCultureIgnoreCase) &&
        uri.AbsoluteUri.StartsWith(HttpsBaseUrl, StringComparison.CurrentCultureIgnoreCase
        );

}

There may be a less expensive version of the GetPublicKey() method that involves indexing into the type array, but the above seems pretty clean to me.  The only possible issue is you might need to reference the System.Security.Cryptography.X509Certificates nuget package from Microsoft depending on your UWP version.

You can see my final version in the Maintenance project of the Siren of Shame UWP app I'm building, along with a possible drop-in CertificatePinningHttpClientFactory.

Summary


Hopefully this clarifies what certificate pinning is, why you'd want it, and how to implement it.  If you found it useful or have any questions please share in the comments or hit me up on twitter.

Thursday, August 3, 2017

Live Coding iOS and Android with Xamarin: Episodes 1 and 2

In case you've missed it I've started a new weekly show where I live code how to build a cross platform mobile app from scratch using Xamarin.  The show is call lprichar code hour and it's live cast to twitch every Tuesday at 9 PM EDT, UTC-4.  Recorded episodes are on my youtube channel where you can should subscribe to get notified of new episodes.  Here's a recap of the first two episodes:

Episode 1


The first episode I introduced myself and the show, explained what Xamarin is, and how to set up your development environment.  Then I build out a hello world app in Xamarin.Android and Xamarin.iOS.  I flushed out the UI for a calculator in the iOS app using auto-layout constraints.  I explained the pitfalls of using storyboards and showed the all-code alternative using EasyLayout.  Here's the 1st show:




Episode 2


In the second episode I built out a calculator UI in Xamarin.Android.  I explained axml files, LinearLayout's, device independent pixels (dp) vs scaleable pixels (sp), themes, styles, and appcompat.  I also explained some of the pitfalls of axml files in a cross platform architecture.



What's Next


In episode 3 I'll get into how to organize your code to share logic across platforms and how to unit test your logic.  In future episode I'll do page navigation, lists, memory management, and animations.

Call To Action


If this show sounds interesting, please subscribe to my channel on youtube or twitch.  I'd also greatly appreciate you sharing this with friends who might want to learn more about cross platform mobile.  Finally, please write me on twitter or in the comments to let me know how to make the show better or what topics you'd like to see for future episodes.

Wednesday, July 19, 2017

Your Code Sucks, Get Over It



Horrifying. That about describes my first art class. As a computer science major with virtually no art experience I was surrounded by students who had devoted nearly every waking moment to drawing, painting, sculpting, and bending metal into non-functional shapes.

The second class was the worst. Our assignment was to create something in Photoshop and print it out with virtually no instruction. Easy enough I chuckled to myself.

It was 1996, and the school computers had two browsers: Netscape Navigator 1.1, and Mosaic. There was no Wi-Fi, and the dorm rooms had no Internet hook up. Photoshop created files so big you needed Zip, or hot-off-the-press Jaz drives (remember those?) to store your massive 10 to 20-megabyte files! I smugly felt I had a huge leg up in owning my own computer, knowing how to use it, and having "hacked" the dorm phone system to get Internet in my room so I could more easily do research.

Upon entering class, the professor immediately instructed us to place our art at the front of the room.

Oh crap, I thought. Everyone's pieces were beautiful. They'd had no difficulty using a computer. They hadn't needed the Internet to figure out how to use non-dot matrix printers.

With heart in my mouth and head hung low I reluctantly placed by far the worst piece of crap the department had ever seen or will ever see, up for all to critique.

The class lightly critiqued the first several pieces. Minor adjustments, mostly.

When it was my turn there was an awkward silence. After an eternity, the professor let them off the hook by drawing attention to a 2cm square part of my piece as potentially interesting. He suggested I try again this time with a massive zoom. A polite way of saying: "you completely failed, try again".

Reckless Persistence


Despite the humiliation, for some reason I persisted. The group persisted too. Persisted in humiliating me again, and again, and again with constant criticism, three times a week for a semester.

Think your code reviews are bad? This was awful to a whole new level.

Except, at some point this thing happened. It became a little less awful every time. Toward the end I finally came to the realization: I am not my art. The class isn't criticizing me. Each comment of "it fails to engage the viewer's attention because it lacks [insert artsy term]" didn't require an emotional response.

Essentially, they were saying: my art sucks, but that doesn't mean I do.

This is described beautifully in this quote from Steven Pressfield in The War of Art, (a book I highly recommend):

A professional schools herself to stand apart from her performance, even as she gives herself to it heart and soul. … The professional loves her work. She is invested in it wholeheartedly. But she does not forget that the work is not her.

And, it was that realization that allowed me to grow exponentially as an artist. In fact, by the end I can confidently say I was not terrible. Here's one of my final pieces.


Go ahead and critique it in the comments. I would genuinely welcome any feedback. Because, just like the blogs I produce, the CAD models I design, or the code I write, I'll be the first to admit there's lots of room for improvement.

In fact, there're more than just room for improvement. I have proof that my code sucks. Every time I look at anything I wrote more than a few weeks ago I'm consistently embarrassed by it. Doesn't the same thing happen to you? Doesn't your code suck too?  Obtaining good, constructive, feedback just helps you discover sooner those ways in which your code can be improved.

Overcoming Criticism Anxiety


If criticism causes you anxiety, you're not alone. Whether the venue is code reviews, reddit comments, or performance reviews, anxiety is a normal reaction. Here's how Stephen Pressfield describes the problem:

Evolution has programmed us to feel rejection in our guts. This is how the tribe enforced obedience by wielding the thread of expulsion. … Resistance knows this and uses it against us. It uses fear of rejection to paralyze us and prevent us, if not from doing our work, then from exposing it to public evaluation.

If the thought of feedback makes you queasy, consider this idea I learned in the public speaking group Toastmasters: we all have a circle of comfort. We generally go out of our way to stick to the activities in that circle. But, the more time we spend on activities outside of the circle, the larger our circle grows.

While that was originally intended to encourage gaining comfort with public speaking by performing more public speaking, it could as easily be applied to fear of criticism.

If you have anxiety about feedback consider this: instead of avoiding the situation, next time try putting yourself out for feedback even more. Maybe decrease scope to limit exposure, but don't hold back. Try committing to writing a blog post once a month or once a week for a year. Apply for jobs with technical interviews.  Speak at user groups.

The more feedback you receive, the thicker your skin will grow, the more detached from it you will become, the less defensive you'll be, the more of it you can incorporate, and the faster you can grow.

I feel extremely fortunate to have taken that art class and for having chosen persistence over paralysis. It didn't just grow my art skills, it helped free me from anxiety about feedback in general. Because of that experience I honestly love receiving constructive feedback.

And, if increasing feedback frequency doesn't work, just envision your future-self looking back at your code from a few weeks in the future. Imagine your future-self telling you in all sincerity: "Your code sucks". Now it's time to get over it, and figure out how to make it better today.

Tuesday, May 30, 2017

Introducing ELXF: A UI Framework for Concise, Maintainable & Fast Programmatic UI's for Xamarin.Forms

ELXF is a new Xamarin.Forms UI framework that allows you to tap into the 2X speed increase possible with RelativeLayouts, while granting concise UI code, extra power, and improved maintainability.

Today I’m happy to announce a new UI framework for Xamarin.Forms. It’s called EasyLayout.Forms (ELXF) and is an alternative to XAML and to programmatic nested view creation. It's goals are:
    1. Maximize UI performance by reducing excess render cycles associated with traditional view nesting
    2. Increase maintainability and readability by removing ceremony and keeping layout code concise
    3. Simplify usage of RelativeLayout while increasing its power and abstracting away its quirks

    In this post I’ll briefly explain what it is, then get into why we need a new UI framework in the context of each of the above three goals. I'll finish with limitations, some history, and how to get started.

    What Is ELXF?


    EasyLayout.Forms (ELXF) is a C# Domain Specific Language that allows you to define the relationships between children in a RelativeLayout. For example to position one element 50px below another in XAML you would normally do this:

    <RelativeLayout>
        <Label
            RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToView, Property=X, ElementName=MainLabel, Constant=0}"
            RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToView, Property=Y, ElementName=MainLabel, Constant=50}"
            RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToView, Property=Width, ElementName=MainLabel}"
            RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToView, Property=Height, ElementName=MainLabel}"
            Text="RelativeLabel"
            />
    </RelativeLayout>

    With ELXF you can do the same thing like this:

    _relativeLayout.ConstrainLayout(() =>
        _relativeLabel.Bounds.Top == _mainLabel.Bounds.Top + 50 &&
        _relativeLabel.Bounds.Left == _mainLabel.Bounds.Left &&
        _relativeLabel.Bounds.Width == _mainLabel.Bounds.Width &&
        _relativeLabel.Bounds.Height == _mainLabel.Bounds.Height)

    There's a handy self-documenting page that summerizes all of the options on github in LayoutExamplePage.cs.



    But what's wrong with the regular way of doing layouts? Why do we need a new framework?

    Maximize Performance


    Today, regardless of whether you choose to layout UI with XAML or programmatically, the path of least resistance is to create nested view layouts with several levels of StackLayout’s, Grid’s, TableView’s, and custom views.

    This creates a performance problem that Michael Ridland explains extremely well in his article Hacking the Xamarin.Forms Layout System for Fun and Profit. It’s worth reading the article a couple of times if you haven’t, but here is one of his key points:

    A child of a stacklayout will always cause a full layout cycle, there’s no way a StackLayout can short circuit this cycle.

    The solution is described on the Xamarin.Forms documentation on ListView performance:

    AbsoluteLayout has the potential to perform layouts without a single measure call. This makes it very powerful for performance. If AbsoluteLayout cannot be used, consider RelativeLayout.

    To better illustrate the problem and its solution I created two Xamarin Forms pages, one using view nesting, and one using a RelativeLayout with ELXF. The page simply shows some products (from Northwind) and you can tap one of them to select and then confirm the choice.



    The nested view version goes four levels deep on the header and three levels deep in the ListView.


    This may look complicated in a single image, but I honestly feel this is fairly typical if not actually simpler than what a real-world app might do.

    To compare the performance, I counted the number of measure and draw cycles for each label after performing the same set of steps on each version of the page (scroll, select 3 products, update text in all labels 3 times aka click calculator button 4 times). I then gave a score to each label based on roughly how expensive it was to draw, and set colors to show a heat map.

    Here's the traditional page:


    And here’s the RelativeLayout with ELXF version:



    The numbers in parenthesis are the number of measure operations and the number of draw operations. As you can see the 2nd one is roughly twice as fast.

    If you want to check these out yourself* the main pages are at: TraditionalPerformancePage.xaml and ElxfPerformancePage.cs and the custom views are in the Controls folder. There's a lot more to this topic such as the importance of fully constraining your views that I'll save for a later post.

    For now we've confirmed the Xamarin documentation and know RelativeLayout’s generally outperform nested views. But why not just use RelativeLayout’s in XAML or programmatically?

    * fyi there's currently an issue in Xamarin.Android 7.3.1 for Visual Studio users that causes RelativeLayouts in ListViews to load extremely slowly on Android. The current workaround is to build from a Mac.

    Increase Maintainability


    Consider the following example in XAML:

    <RelativeLayout>
        <Label BackgroundColor="Aqua"
            Text="Main Label"
            x:Name="MainLabel"
            RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToParent, Property=X, Constant=10}"
            RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent, Property=Y, Constant=10}"
            RelativeLayout.WidthConstraint="{ConstraintExpression Type=Constant, Constant=100}"
            RelativeLayout.HeightConstraint="{ConstraintExpression Type=Constant, Constant=40}"
            />
        <Label BackgroundColor="OrangeRed"
            RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToView, Property=X, ElementName=MainLabel, Constant=110}"
            RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToView, Property=Y, ElementName=MainLabel, Constant=50}"
            RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToView, Property=Width, ElementName=MainLabel}"
            RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToView, Property=Height, ElementName=MainLabel}"
            Text="RelativeLabel"
            />
    </RelativeLayout>


    This renders two labels like this:




    I don’t know about you, but I find that code very hard to read. The ELXF version of that looks like this:

    relativeLayout.ConstrainLayout(() =>
        _mainLabel.Bounds.Top == relativeLayout.Bounds.Top + 10 &&
        _mainLabel.Bounds.Left == relativeLayout.Bounds.Left + 10 &&
        _mainLabel.Bounds.Width == 150 &&
        _mainLabel.Bounds.Height == 40 &&

        _relativeLabel.Bounds.Top == _mainLabel.Bounds.Bottom + 10 &&
        _relativeLabel.Bounds.Left == _mainLabel.Bounds.Right + 10 &&
        _relativeLabel.Bounds.Width == _mainLabel.Bounds.Width &&
        _relativeLabel.Bounds.Height == _mainLabel.Bounds.Width
    )

    It’s concise, powerful, and the syntax is always verified by the compiler. It also fixes a duplication problem in that XAML example. Can you spot the issue?

    Simplify RelativeLayout


    While Xamarin.Forms RelativeLayout’s aren’t exactly broken, they are far less powerful than iOS’s Autolayout or even Android’s RelativeLayout with it's fairly extensive set of LayoutParams. The good news is Xamarin realizes this and have plans to introduce a more powerful version in Xamarin.Forms 3. The problem today, however, is that they essentially only allow you to control the top left pixel.

    For example if you look again at the XAML above you’ll see that to align RelativeLabel to the right of MainLabel we had to add 110 (the width of MainLabel plus a margin) to RelativeLabel’s X. What we really want is an attribute like RelativeLayout.RightEdgeConstraint instead of the RelativeLayout.XConstraint attribute.

    As it stands if we ever change MainLabel’s width, we must remember to increment RelativeLabel’s XConstraint. That's the kind of duplication that hides bugs and complicates maintainability. However, even without ELXS we can do a little better.

    If we write this in code it looks like this:

    relativeLayout.Children.Add(mainLabel,
        Constraint.RelativeToParent(rl => rl.X + 10),
        Constraint.RelativeToParent(rl => rl.Y + 10),
        Constraint.Constant(100),
        Constraint.Constant(40)
        );

    relativeLayout.Children.Add(relativeLabel,
        Constraint.RelativeToView(mainLabel, (rl, v) => v.X + v.Width + 10),
        Constraint.RelativeToView(mainLabel, (rl, v) => v.Y + v.Height + 10),
        Constraint.RelativeToView(mainLabel, (rl, v) => v.Width),
        Constraint.RelativeToView(mainLabel, (rl, v) => v.Height)
        );


    Better, right? RelativeLayouts in code have more power. So maybe we don't need a new framework after-all.

    Except, even if you don't agree that the ELXS version of

    _relativeLabel.Bounds.Left == _mainLabel.Bounds.Right + 10

    is easier on the eyes than

    Constraint.RelativeToView(mainLabel, (rl, v) => v.X + v.Width + 10)

    the code-behind version still has serious limitations when it comes to Centering elements.

    The Centering Problem


    Suppose we want to center-align a 3rd view under the 2nd one. If we attempt something like this:

    relativeLayout.Children.Add(centerLabel,
        Constraint.RelativeToView(relativeLabel,
            (rl, v) => v.X + (v.Width * .5f) – (centerLabel.Width * .5f)),
        Constraint.RelativeToView(relativeLabel,
            (rl, v) => v.Y + v.Height)
        );


    We’ll discover that it renders like this:


    Why didn’t CenterLabel pull further left? It’s because when the XConstraint lambda was evaluated, 'centerLabel' hadn’t been rendered yet. A non-rendered view gives a Width or Height of -1. The solution, documented nicely in this StackOverflow post, is this:

    Size GetSize(VisualElement ve, RelativeLayout rl) =>
        ve.Measure(rl.Width, rl.Height).Request;

    relativeLayout.Children.Add(centerLabel,
        Constraint.RelativeToView(relativeLabel,
            (rl, v) => v.X + (v.Width * .5f) - (GetSize(centerLabel, rl).Width * .5f)),
        Constraint.RelativeToView(relativeLabel,
            (rl, v) => v.Y + v.Height + 10)
        );

    That GetSize() local function (some C# 7 sugar) solves the problem by calculating what the width of centerLabel will be after it’s rendered. That renders nicely like this:


    While that works, perhaps you’ll agree that it's difficult to discern intent among all that math. A complex page with a lot of this style code is liable to hide bugs and obfuscate intent.

    Worse, it’s not always this easy. What if we want CenterLabel to have a width relative to MainLabel. If we do this:
    relativeLayout.Children.Add(centerLabel,
        Constraint.RelativeToView(relativeLabel,
            (rl, v) => v.X + (v.Width * .5f) - (GetSize(centerLabel, rl).Width / 2)),
        Constraint.RelativeToView(relativeLabel,
            (rl, v) => v.Y + v.Height + 10),
        Constraint.RelativeToView(mainLabel,
            (rl, v) => v.Width)
        );

    We end up with this:


    The problem is our GetSize() method is calculating the width of the label prior to any RelativeLayout width constraints.

    This is the point at which we’re stuck with the solution of hard-coding (duplicating) MainLabel’s width.

    ELXF to the Rescue


    EasyLayout.Forms can solve the centering problem. It translates LINQ expressions into Children.Add() calls with the correct parameters, it incorporates calls to a GetSize() type function when necessary, and in many cases it can solve the GetCenter() problem from above by searching back through prior LINQ expressions to determine what height or width the current element should be.
    The final solution turns into this:


    relativeLayout.ConstrainLayout(() =>
        _mainLabel.Bounds.Top == relativeLayout.Bounds.Top + 10 &&
        _mainLabel.Bounds.Left == relativeLayout.Bounds.Left + 10 &&
        _mainLabel.Bounds.Width == 150 &&
        _mainLabel.Bounds.Height == 40 &&

        _relativeLabel.Bounds.Top == _mainLabel.Bounds.Bottom + 10 &&
        _relativeLabel.Bounds.Left == _mainLabel.Bounds.Right + 10 &&
        _relativeLabel.Bounds.Width == _mainLabel.Bounds.Width &&
        _relativeLabel.Bounds.Height == _mainLabel.Bounds.Height &&

        _centerLabel.Bounds.GetCenterX() == _relativeLabel.Bounds.GetCenterX() &&
        _centerLabel.Bounds.Top == _relativeLabel.Bounds.Bottom + 10
        );

    Limitations


    ELXF makes the RelativeLayout more powerful, but it can't patch over all of the issues. Until Xamarin.Forms 3 comes out, the following are a few of the known issues:
    • If you update the text of a view with Right or Center constraints, the relative layout doesn’t know to redraw it. To force the redraw you have to call relativeLayout.ForceLayout() twice
    • You can’t currently constrain a Left edge to one view and a Right edge to another view the way you could with iOS Autolayout. The workaround is to set the width just like you would with a regular RelativeLayout
    • Unlike the iOS version of EasyLayout, be aware that ELXF has no less than or greater than constraints

    A Brief History

    Speaking of the iOS version of EasyLayout, I must give credit where it's due and provide some context. EasyLayout is a UI framework originally developed by Frank Krueger (@praeclarum) to simplify doing programmatic Autolayout in Xamarin.iOS. It does this by creating a simple DSL using the awesome Expression Trees feature of C#. EasyLayout for iOS is so powerful that I wouldn’t start a Xamarin.iOS project without it, and I honestly feel sorry for traditional iOS developers for not having anything like it. But it was only for Xamarin iOS.

    Then, earlier this year, my team decided to move away from AXML files on our Xamarin.Android project. They did this because on our large project AXML files take a very long time to generate and significantly slow development. I took the opportunity to port EasyLayout to Android in the form of EasyLayout.Droid. This turned out to be a fantastic solution for our team, and I now wouldn’t do a Xamarin Android project without EasyLayout.Droid.

    While ELXF is not yet as mature as its predecessors, I did at least have the opportunity to bring in lessons learned from two mature projects.

    Getting Started


    If you'd like to give it a spin you can install it via nuget into a project with:

    Install-Package EasyLayout.Forms

    The source code is all at GitHub and there are an extensive set of examples in the source code like here and here. And as mentioned there is a self documenting page. Also if you clone source there is a playground page where you can experiment.

    What's nice is that if you like it you can adopt ELXF on your existing projects on a page by page basis. In fact, you can even use it for just a single view in a single relative layout. There's no obligation to adopt it everywhere. Just don't be surprised if, like me, you grow to like it enough to want it everywhere.

    Summary


    If you end up using and liking EasyLayout.Forms please shoot me a note on twitter @lprichar, I'd love to hear from you.