Working with Self Signed Certificates (Certificate Pinning) in Windows (UWP) Application with Xamarin.Forms

Working with Self Signed Certificates (Certificate Pinning) in Windows (UWP) Application with Xamarin.Forms

I’ve been doing a bit of progression talking about building and debugging ASP.NET Core services over https and http/2, coupled with using platform specific handlers to improve the way the HttpClient works on each platform. The following links provide a bit of a background on what we’ve covered so far.

Accessing ASP.NET Core API hosted on Kestrel over Https from iOS Simulator, Android Emulator and UWP Applications.
Publishing ASP.NET Core 3 Web API to Azure App Service with Http/2
Xamarin and the HttpClient For iOS, Android and Windows

In this post we’re going to pick up from the end of the previous post to discuss using self-signed certificates in a Windows (ie UWP) application. Previously we managed to get the ASP.NET Core API hosting setup in such a way that the services were exposed using the IP address of the host computer, meaning that it can be accessed from an app running on an iOS simulator, the Android emulator, or even a UWP app running locally on the computer. As we’ll see there’s still a bit of work to be done within the app on each platform to allow the app to connect to the API.

Before we go on, it’s worth noting that the technique we’re going to use in the post is sometimes referred to as certificate pinning, which amounts to verifying that the response to a service call has come across a secure channel that uses a certificate issued by a certificate authority that the app is expecting, or trusts. There are a variety of reasons for using this technique but the main one is to help eliminate man in the middle attack by preventing some third party from impersonating the service responding to the requests for an app. One of the other common reasons to use this technique is actually to permit non-secure, or self-signed certificates – as you may recall we used a self-signed certificate in the previous post to secure the service, so we need a mechanism for each platform to permit the use of self-signed certificates and treat the responses from such services as trusted. This will be done over a three part series of posts, starting with a Universal Windows Application (UWP) application in this post.

To get started, let’s take a quick look at what happens if we simply run up both the UWP application we had previously setup to use the WinHttpHandler. The only change I’m going to make to the UWP application initially is to change the BaseUrl for the service to https://192.168.1.107 (ie the IP address of the development machine) – note that it’s a https endpoint. Running the application will fall over with an exception when it attempts to connect to the HeaderHelper service hosted at https://192.168.1.107/api/value.

image

The extracted error message is as follow:

System.Net.Http.HttpRequestException
   HResult=0x80072F8F
   Message=An error occurred while sending the request.
   Source=System.Private.CoreLib
Inner Exception 1:
WinHttpException: Error 12175 calling WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, ‘A security error occurred’.

Now if you search for this error information, you’re likely to see a bunch of documents talking about the 0x80072F8F error code as it seems to come up in relation to Windows activation issues. However if you google the 12175 error (ie the internal exception) you’ll see a number of articles (eg http://pygmysoftware.com/how-to-fix-windows-system-error-12175-solved/) that point at there being an SSL related error. In this case it’s because we accessing a service that uses a certificate that isn’t trusted and can’t be validated.

We’re going to discuss two ways to carry out certificate pinning, which should allow us to access the HeaderHelper service, even though it’s being secured using a self-signed certificate. In the previous post where we setup the ASP.NET Core service to use a new certificate when hosting on Kestrel, we generated a .PFX certificate that included both the public and private components using mkcert. In both of the methods described here, you’ll need the public key component, which is easy to grab using openssl thanks to this post. For example:

openssl pkcs12 -in kestrel.pfx -nocerts -out kestrel.pem -nodes

Look Dad, No Code

The first way to configure the UWP application to connect to the service with a self-signed certificate is to add the public key for the certificate into the UWP application and declare the certificate in the Package.appxmanifest.

– Open the Package Manifest designer by double-clicking the package.appmanifest

– Once opened, select the Declarations tab, and then from the Available Declarations, select Certificates and click Add.
image

– Click the Add New button at the bottom of the Properties section
image

– Set the Store name to TrustedPeople and click the … button to select the public key file generated earlier

image

If you’re interested as to what has been changed when you selected the public key in the manifest editor:

– The public key file (in this case kestrel.pem) was added to the root of the UWP project with Build Action set to Content so that the pem file gets deployed with the application

– The package.manifest file was updated to include an Extensions section, specifically a Certificate element that defines both the store and the certificate file name.

<Extensions>
   <Extension Category=”windows.certificates”>
     <Certificates>
       <Certificate StoreName=”TrustedPeople” Content=”kestrel.pem”/>
     </Certificates>
   </Extension>
</Extensions>

And that’s it – you can successfully run the application and all calls to the service secured using the generated self-signed certificate will be successful.

With Code Comes Great Responsibility

The second way to prevent man in the middle style attacks is to do some validation of the connection in code of the certificate returned as part of the initial all to the services.

If you read some of the documentation/blogs/posts online they sometimes reference handling the ServerCertificateValidationCallback on the ServicePointManager class. For example the following code will simply accept all validation requests, thereby accepting all response data, on the assumption that the caller is in some way validating the response.

ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;

Note: The ServerCertificateValidationCallbak event on the ServicePointManager will only be invoked if you use the default managed handler, which as we saw in my previous post is not recommended. I would discourage the use of this method for handling certificate validation challenges.

So, if ServicePointManager isn’t the correct place to intercept request, what is?

In the previous post we had already overridden the InitializeIoC method on the Setup.cs class, so it makes sense to route the NBN cabling through the roof cavity.

– A new method, CertificateCallacbk, has been set to handle the ServerCertificateValidatationCallback on the WinHttpHandler (not to be confused with the ServicePointManager callback).

protected override void InitializeIoC()
{
     base.InitializeIoC();


    Mvx.IoCProvider.LazyConstructAndRegisterSingleton<HttpMessageHandler, IServiceOptions>(options =>
     {
         return new WinHttpHandler()
         {
             ServerCertificateValidationCallback = CertificateValidationCallback,
         };
     });
}
private bool CertificateValidationCallback(HttpRequestMessage arg1, X509Certificate2 arg2, X509Chain arg3, SslPolicyErrors arg4)
{
     return true;
}

– Of course simply returning true to all certificate validation challenges, isn’t very secure, and it’s highly recommended that your certificate checking is much more comprehensive.

And that’s it; you can now ignore certificates that are self-signed, or that aren’t signed by a trusted certificate authority. Whilst the methods presented in this post are for UWP, they are equally applicable for a UWP application that’s been written using Xamarin.Forms.

Accessing ASP.NET Core API hosted on Kestrel over Https from iOS Simulator, Android Emulator and UWP Applications.

Accessing ASP.NET Core API hosted on Kestrel over Https from iOS Simulator, Android Emulator and UWP Applications.

This post is a stepping stone to get local debugging working for a Http/2 service over Https from a Xamarin.Forms application. In my post on publishing to Azure I covered the fact that the underlying service receives a Http/1.1 connection, despite applications establishing a http/2 connection. This made it difficult to build out applications that use technology such as GRPC which rely on the http/2 protocol. To make it possible to develop both the mobile app and the services locally, we need to setup the ASP.NET Core debugging to allow the applications (ie each of the supported platforms) to connect.

This post assumes that the ASP.NET Core application is being hosted locally using Kestrel, mainly because of the limitations around http/2 (here and here). By default, when you create an ASP.NET Core application it is setup with multiple launch configurations, allowing you to switch between IIS Express, Kestrel and if you select the Docker option when creating your project, you’ll see an option to launch using Docker (as shown in the following image showing the launchSettings.json for the HeaderHelper project).

image

To switch between the different launch configurations you just need to select the right configuration from the run dropdown in Visual Studio – in this case I’ve selected the HeaderHelper option, which as you can see from the above launch configurations uses the “Project” command name that correlates to hosting using Kestrel (I know, not super obvious, right!).

image

When we run the ASP.NET Core application using the default launch configuration on Kestrel, what we see is that a command window is shown (since Kestrel is basically a console application) and then a browser window is subsequently launched. As you’d expect the out of the box experience is all good – we can see it’s launched the https endpoint and there’s the lock icon to indicate it’s trusted.

image

It’s also interesting to note that the service is returning Http/2 when according to this document (see screenshot below) the default is Http/1.1.

image

Well, it looks like the documentation hasn’t been updated in line with the latest code. If you take a look at GitHub for AspNetCore repository you can see that between the stable v2.2.4 and the v3.0.0-preview4 release there has been a change to the default value.

image

Coming back to our Kestrel hosted ASP.NET Core application, we can see that the endpoint host is localhost, which aligns with what’s in the applicationUrl property in the configuration in the launchSettings.json file. Unfortunately, localhost isn’t great when it comes to working with mobile applications as localhost doesn’t always resolve to the development machine. For example if you’re working with a real iOS or Android device, they’re most likely going to be on the same WiFi network but localhost won’t resolve to machine running the ASP.NET Core application. Similarly if you’re developing on a Windows PC and using a remote Mac to do the build and run the simulator, localhost again won’t resolve to the correct machine.

To solve this, we need to change the Kestrel configuration to expose the service in such a way that it can be accessed via the IP address of the machine where Kestrel will be running. Note that there are plenty of services such as ngrok, portmap.io and Forward which are great and easy to setup for non-secure services. However, once you get into trying to extend the configuration to support Https or Http/2 you end up needing to pay to use their premium service. These services are great if you want to extend beyond the bounds of your firewall but are overkill if all you want to do is expose your service for development purposes.

A much similar alternative is to:

– Change Kestrel to bind to all IP addresses for the host machine

– Add a firewall rule to allow in-bound connections on the posts required for the application

I’ll elaborate on these in more detail – and I’m going to do them in reverse order because the firewall rule is required in order to verify the Kestrel configuration is working when binding to the IP address.

Adding a Firewall Rule for Ports 5001 and 5000 (on Windows)

On Windows, it’s relatively straight forward to add a firewall rule that will allow inbound connections on specific ports. In this case we’re interested in adding a rule that works for ports 5000 and 5001, which are the two ports used in the applicationUrl property of launchSettings.json. Here’s the step-by-step

– Press Start key, type “Windows Defender” and click on the “Windows Defender Firewall with Advanced Security” option

– Click on “Inbound rules” in the left panel

– Click on “New rule” in the right (Actions) panel to launch the New Inbound Rule Wizard

– When prompted for the type of rule, select “Port” and click Next

– Make sure the “Specific local ports” option is selected and enter “5000-5001” (or “5000,5001”) in the text box.

– Click Next, accepting the defaults on the remaining pages of the New Inbound Rule Wizard, through to the final page where you’ll need to give the rule a name before hitting Finish.

Once you’ve created the Inbound rule, any requests made on these ports will be allowed through to whatever service is bound to those ports on your computer. You should disable this rule when you’re not making use of these ports for debugging.

Binding Kestrel to All IP Addresses

This can be done simply by changing the launchSettings.json file to replace localhost with 0.0.0.0:

image

When you rebuild (you may need to force a rebuild as sometimes the change to launchSettings.json isn’t picked up by Visual Studio) and attempt to run the application you’ll see an error page – this is because 0.0.0.0 isn’t actually a real IP address, it’s just the address used in the launchSettings to configure Kestrel to bind to all addresses.

image

If you change the address to use localhost instead of 0.0.0.0 you’ll again see that the api result is returned successfully. However, if you now use the actual IP address of the computer (in this case 192.168.1.107) you’ll see a certificate warning. Clicking the Advanced you can proceed to the site and see the result but the “Not secure” in the address bar will remain.

image

The fact that there’s a security error is going to cause a lot of issues if we don’t resolve it because none of the application platforms (ie iOS, Android, UWP) work well with Https when the certificate can’t be verified. Even if you use certificate pinning (to be covered in a future post) you’ll find it hard to configure the different platforms to work with certificates that don’t match the domain of the service.

If we take a look at the certificate being used, we can see that the Subject Alternative Name only matches with localhost.

image

Luckily this problem can be fixed by changing the certificate that is used by your ASP.NET Core application. If you’re planning on exposing your ASP.NET Core endpoint directly to the internet I would recommend getting a certificate from a well known CA. The following process can be used for setting up your service for development purposes:

If you know what you’re doing you can download the latest openssl and proceed to create your own certificates. However, this is fairly involved and a much similar way is to leverage the mkcert tool that is available at https://github.com/FiloSottile/mkcert. The steps are as follows:

– Download the latest binaries for mkcert (you might want to rename the executable from say mkcert-v1.3.0-windows-amd64.exe to mkcert.exe for convenience)

– Launch a command prompt running as Administrator

– Run “mkcert -install”. If you get an error such as “failed to execute keytool…..”  you probably didn’t read the previous step and opened a regular command prompt. You need to be running as Administrator

image

A successful install should look like:

image

The install process creates a certificate and trusts it on the local computer as a trusted certificate authority, meaning it can be used to generate other certificates.

– Run mkcert to create a certificate that you can use in your ASP.NET Core application

mkcert -pkcs12 -p12-file kestrel.pfx 192.168.1.107 localhost 127.0.0.1 ::1

image

– Copy the newly created kestrel.pfx into the ASP.NET Core project and set the Build Action to Content to make sure it gets deployed with your application.

image

– Remove the applicationUrl property from the Kestrel configuration in launchSettings.json

image

– Update the CreateHostBuilder method in program.cs to setup the Kestrel configuration. Specifically setting up both ports 5001 and 5000 to listen on Https and Http respectively. For port 5001 the kestrel.pfx certificate is used (note despite the advice we haven’t changed the password here but would recommend doing so if you’re going to use this in production)

public static IHostBuilder CreateHostBuilder(string[] args) =>
     Host.CreateDefaultBuilder(args)
         .ConfigureWebHostDefaults(webBuilder =>
         {
             webBuilder
                 .ConfigureKestrel(options =>
                 {
                     options.ListenAnyIP(5001, listenOptions =>
                     {
                         listenOptions.UseHttps(“kestrel.pfx”, “changeit”);
                     });
                     options.ListenAnyIP(5000);
                 })
                 .UseStartup<Startup>();
         });

Now when we run the ASP.NET Core application on the Kestrel hosting we can successfully navigate to the endpoint using the machines IP address.

image

Inspecting the https certificate you can see that the Subject Alternative Names include 192.168.1.107 (ie the machines IP address) and that the Certification path ends in the mkcert certificate that has been added to the trusted certificate authorities on this computer.

imageimage

Now that we’ve configured Kestrel and ASP.NET Core to play nice, what we need to do is to configure our mobile applications to connect to this service, which we’ll do in the next post.

OT: Change Project Options in Visual Studio 2019 to Make Build Output Useful

OT: Change Project Options in Visual Studio 2019 to Make Build Output Useful

There are two things that I find somewhat frustrating about Visual Studio 2019; that is until I spent a minute or two adjusting the behaviour of Visual Studio when I build my projects:

Build Progress Window

This is by far the biggest wasted feature ever added to Visual Studio – This annoying window pops up by default when building a project and has NOTHING useful to say, other than a progress bar across the bottom indicating some sort of percentage through the build. The following window shows the build progress of MvvmCross. However, it’s completely incorrect as not all 47 projects are set to build. In fact what I asked it to build probably has around 10 projects.

Why does this window even exist? Is there some other project type where there is more information displayed in the big white void? 

image

Error List Window

The following image shows the Error List window after a successful  build. What the? I’m sorry but is it really so hard to show just the errors from the most recent build? And perhaps order them in a somewhat meaningful way? In the end I always end up going to the Output window, looking at the first build error encountered and fixing that – pretty much the fastest and most reliable way to get a broken build to work again.

image

Options

The great thing about Visual Studio is that there are a ton of options. In this case I can adjust a couple of options under the Projects and Solutions node to limit my expose to these two redundant windows.

– Uncheck the “Always show Error List if build finishes with errors” – since as we’ve seen the Error List window isn’t the greatest at working out whether the build was successful or not.

– Check the “Show Output window when build starts” – this will effectively hide the Build Progress window.

image

Xamarin and the HttpClient For iOS, Android and Windows

Xamarin and the HttpClient For iOS, Android and Windows

In an earlier post that talked about using dependency injection and registering interfaces for working with Refit across both Prism and MvvmCross I had code that registered an instance of the CustomHttpMessageHandler class which internally used a HttpClientHandler for its InnerHandler. For developers who have spent a bit of time optimising their iOS, Android or Windows application, you’ll have noted that using the HttpClientHandler is generally not deemed to be best practice.  As I’m a big fan of trying to demonstrate best practices, I figured I’d expand on this a little into a post talking about the HttpClient and some of the options you have.

Firstly, a couple of bits of side reading:

– Docs on the HttpClient stack

– Mono blog post talking about the HttpWebRequest / HttpClient

– Jon’s post on Http Performance

What you should gather from these articles is that Microsoft is doing their best to set you up for success but not wanting to take any documentation for granted, let’s see what happens when we create a brand new Xamarin.Forms project and spin up an instance of the HttpClient. When creating the project I just picked the Blank Xamarin.Forms template and made sure that all three platforms were included. The code for creating the HttpClient just uses the zero-parameter constructor:

var client = new HttpClient();

Let’s run each platform and see what the HttpClient gives us (and at this point I haven’t updated any NuGet packages, framework versions or anything. This is just what VS2019 gives me when I create a new XF project).

UWP

image

Here we get the managed HttpClientHandler, rather than the newer (and arguably better) WinHttpHandler. Actually I didn’t find a definitive guide on which is better for UWP, although this stackoverflow post does seem to imply the WinHttpHandler would be the preferred choice, particularly if you want to leverage Http/2.

Android

image

Android is using the AndroidClientHandler which is what should give us the most up to date http experience.

iOS

image

iOS is using the NSUrlSessionHandler which is what should give us the most up to date http experience.

This all seems good (albeit that you might want to use the WinHttpHandler on UWP) so for a lot of developers they might never run into any issues. If you did want to adjust which handler is used on iOS and Android (again assuming you’re just using the HttpClient with the default constructor) you can do so via the properties dialog for the corresponding platform:

image

However, where things come unstuck is if you want to customise some of the http behaviour. In my previous post I demonstrated setting the compression flag but it could have equally been adding an additional header or changing the credentials that are sent as part of each request. In this case, it’s easy enough to use the overload of the HttpClient constructor that takes a HttpMessageHandler and use the managed HttpClientHandler implementation (as I demonstrated). As you’d have seen from the linked articles above, this isn’t ideal as the managed implementation doesn’t leverage the platform specific optimisations.

The better approach is for my application to register the platform specific handler, which in MvvmCross can be done via the Setup class (which is created by default when using MvxScaffolding):

UWP

public class Setup : MvxFormsWindowsSetup<Core.App, UI.App>
{
     protected override void InitializeIoC()
     {
         base.InitializeIoC();
        Mvx.IoCProvider.LazyConstructAndRegisterSingleton<HttpMessageHandler, IServiceOptions>(options =>
         {
             return new WinHttpHandler()
             {
                AutomaticDecompression = options.Compression
             };

         });
     }
}

Android

public class Setup : MvxFormsAndroidSetup<Core.App, UI.App>
{
     protected override void InitializeIoC()
     {
         base.InitializeIoC();


        Mvx.IoCProvider.LazyConstructAndRegisterSingleton<HttpMessageHandler, IServiceOptions>(options =>
         {
            return new AndroidClientHandler
             {
                 AutomaticDecompression = options.Compression
             };

         });
     }
}

iOS

public class Setup : MvxFormsIosSetup<Core.App, UI.App>
{
     protected override void InitializeIoC()
     {
         base.InitializeIoC();


        Mvx.IoCProvider.LazyConstructAndRegisterSingleton<HttpMessageHandler, IServiceOptions>(options =>
         {
             var nsoptions = NSUrlSessionConfiguration.DefaultSessionConfiguration;
             if (options.Compression == System.Net.DecompressionMethods.None)
             {
                 nsoptions.HttpAdditionalHeaders = new NSDictionary(“Accept-Encoding”, “identity”, new object[] { });
             }
             var handler = new NSUrlSessionHandler(nsoptions);
             return handler;

         });
     }
}

Note: for iOS the NSUrlSessionHandler enabled compression by default, so the code here illustrates how you could disable compression if you wanted by sending the identity Accept-Encoding header.

In this post I’ve shown you how you can register each of the native platform handlers to optimise the requests made when using the HttpClient. This post should be read in conjunction with my earlier post that registered the other classes necessary to create the HttpClient based on the registered handler. The only other change is that the HttpService constructor should accept an HttpMessageHandler instead of an ICustomHttpMessageHandler.

public class HttpService : IHttpService
{
     public HttpService(HttpMessageHandler httpMessageHandler, IServiceOptions options)
     {
         HttpClient = new HttpClient(httpMessageHandler as HttpMessageHandler)
         {
             BaseAddress = new Uri(options.BaseUrl)
         };
     }


    public HttpClient HttpClient { get; }
}

Update: It’s worth noting that the WinHttpHandler used in the UWP example isn’t part of the core framework. Instead it is accessible via the System.Net.Http.WinHttpHandler NuGet package. Visual Studio provides a handy way to find and install this package – selecting the WinHttpHandler reference (where there is a build error) and looking at the intellisense options, there is an option to Install the System.Net.Http.WinHttpHandler package.

image

Publishing ASP.NET Core 3 Web API to Azure App Service with Http/2

Publishing ASP.NET Core 3 Web API to Azure App Service with Http/2

In my previous post I was testing a new ASP.NET Core 3 Web API that I’d created that simply returns header and http information about the request. Having got everything working locally I decided that I should push it into an Azure App Service to make it accessible from anywhere (this seemed to be easier than attempting to connect to my locally running service from a Xamarin.Forms application). Here’s the process:

Right-click on the ASP.NET Core project and select Publish.

image

In this case we’re going to select App Service (ie a Windows host) and Create New, followed by the Publish button. Next we need to give the new App Service a name and specify both a Resource Group and an App Service Plan – in this case I’m going to create all of these as part of the publishing process

image

Hitting Create will firstly create the necessary Azure resources and then it will proceed with publishing the ASP.NET Core project into the App Service. Unfortunately, once this process has finished you’ll see that the launched url doesn’t load correctly:

image

And secondly, when you return to Visual Studio you’ll see a warning prompt indicating that ASP.NET Core 3 isn’t supported in Azure App Service right now.

image

Luckily Microsoft documentation has you covered. If you go to the main documentation on publishing to Azure App Service there is a link of to deploying preview versions of ASP.NET Core applications. This document covers two different ways to fix this issue – you can either install the preview site extensions for ASP.NET Core 3, or you can simply change your deployment to be a self-contained application. In this case we’re going to go with deploying a self-contained application, since this reduces any external dependencies which seems sensible to me.

After returning to Visual Studio and dismissing the above version warning, you’ll see the Publish properties page with the default publish configuration (you can get back to this page by right-clicking your ASP.NET Core project and selecting Publish in the future).

image

We’re going to click the pencil icon along side any of the summary properties to launch the Publish dialog and change the Deployment Mode to Self-Contained, and the Target Runtime to win-x86. You may be tempted to select win-x64 but only do this if the Platform setting on your App Service is set to 64 Bit, otherwise your service won’t start and you’ll see a 503 service error.

image

Click Save and then the Publish button to publish the application using the updated publishing properties. Note that if you’re on a network that has a slow uplink (eg ADSL) this might take a while, so you might consider jumping on a fast network (eg 4G mobile) to do the upload (and yes, this does make Australia sound like an under-developed nation when it comes to access to the internet – sigh!).

Without any further messing around, the ASP.NET Core application launches correctly:

image

Hmmm, but wait, shouldn’t it be reporting HTTP/2, after all that’s what the browser was reporting when I ran the same service on Kestrel. There’s a couple of pieces to this answer but before we do, I want to remove any element on confusion as to what’s going on here by switching across to using curl – this way we have both control over what protocol we’re requesting but also detailed logging on what protocol is being used (you’ll see why this is important in a minute). Executing the following:

curl https://headerhelper.azurewebsites.net/api/values -v

image

As you can see from the image, the response was indeed done over Http/1.1, which is consistent with the Http protocol listed by the service. Ok, so let’s try requesting Http/2

curl https://headerhelper.azurewebsites.net/api/values –http2 –v

image

This call is successful but again returns Http/1.1 – this is because curl is attempting to request an upgrade to http/2 but the service isn’t willing/able to upgrade the connection.

curl https://headerhelper.azurewebsites.net/api/values –http2-prior-knowledge -v

image

This call fails because curl is forcing the use of Http/2 when in fact the service isn’t able to communicate using Http/2. So, how do we fix this? Well the good news is that Azure App Service has a simple configuration setting that can be used to enable Http/2. Here I’m just setting the HTTP version in the Configuration page for the Azure App Service.

image

This can also be set via the resource explorer, as covered by a number of other people (eg this post). After making your change, don’t forget to Save changes and then give the service 30-60seconds for it to be restarted – if you attempt to request the service immediately you’ll still get Http/1.1 responses.

After the change has been applied, here’s what we see when we use the same curl commands as above:

curl https://headerhelper.azurewebsites.net/api/values –http2 –v

curl https://headerhelper.azurewebsites.net/api/values –http2-prior-knowledge –v

image

Note that it doesn’t matter whether we attempt to negotiate the http/2 upgrade (–http2 flag) or force the point (–http2-prior-knowledge), in both cases the connection reports HTTP/2. However, what’s not cool is that the Http protocol returned by the service is HTTP/1.1 – this is what is seen by the ASP.NET Core Web API.

What we’re seeing here is that Azure is terminating the Http/2 connection and then communicating to the underlying ASP.NET Core application using Http/1.1. This is consistent with the way that SSL support is done – Azure terminates the SSL connection, meaning that your ASP.NET Core application doesn’t need to worry about fronting a secure service. This is awesome for developers that want to add SSL or HTTP/2 to their existing services – you just enable the option in the configuration page of your App Service. However, the down side is that it makes leveraging some of the underlying capabilities of HTTP/2 impossible – for example, it’s currently impossible to host a GRPC service in an App Service as this relies on HTTP/2 to function.

The question still remains – when I request the service from the browser, what protocol is being used? The response returns HTTP/1.1 because that’s what our ASP.NET Core application sees. However, if we look at the browser debugging tools, we can see that the response is indeed being handled over a HTTP/2 connection. Note that this isn’t exposed in the UI of the debugging tools but if you save the request you can see the full details:

image

Opening the HAR file in VS Code:

image

And there you have it – deploying an ASP.NET Core 3 application to Azure App Service and exposing it using HTTP/2.

Testing ASP.NET Core Web API on Kestrel with Fiddler Composer Fails

Testing ASP.NET Core Web API on Kestrel with Fiddler Composer Fails

It’s been one of those days when you set out to do something so simple and yet you get distracted by having to fix something that should just work. I’ll set the scene – I wanted to generate a simple ASP.NET Core Web API that would return the HTTP protocol and headers of a particular request. All up I think the code for this took me about 30seconds to write as follows (this was in a new ASP.NET Core 3 project created using the Api template in Visual Studio 2019):

[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
     var headers = (from h in Request.Headers
                     select h.Key + ” – ” + h.Value).ToList();
     headers.Add(“Http – ” + string.Join(“,”, Request.Protocol));
     return headers;
}

When I ran this in Visual Studio it launched the browser and did indeed return the headers and HTTP protocol version. At this point I was a bit surprised as it return Http/2 even though I had done nothing either in the browser or the service to indicate that I wanted Http/2.

image

Realising that this was something that the browser was negotiating I thought I’d see what result I got when I called the service from Fiddler where I could control what Http version was being requested. As you can see from the image what I got back was a 502 response:

[Fiddler] The connection to ‘localhost’ failed.  <br />System.Security.SecurityException Failed to negotiate HTTPS connection with server.fiddler.network.https&gt; HTTPS handshake to localhost (for #1) failed. System.IO.IOException Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. &lt; An existing connection was forcibly closed by the remote host

image

This was frustrating because this should have just worked. Furthermore there was no exception raised within my ASP.NET Core project. I was running my project on Kestrel which also was exposing a non-https endpoint, http://localhost:5000/api/values. However, the Api template adheres to best practice and comes with the line “app.UseHttpsRedirection” in Startup.cs which caused the request from Fiddler to be redirected to https, which of course then fails as before. If I remove the redirection, the request again fails with the 502 exception.

Luckily I’ve been in this situation and realised that whilst there’s no exception being raised in my code, there was most likely an exception being thrown internally as part of the ASP.ENT Core middleware. To investigate this further I firstly made sure that all “Common Language Runtime Exceptions would trigger a break in Visual Studio (you need to run the application in order to see this window by default, or you can open it from the Debug / Windows / Exception Settings menu item).

image

By itself this isn’t sufficient, you also need to uncheck the “Enable Just My Code” checkbox in Tools / Options menu item.

image

Invoking the service from Fiddler now generates the following exception:

System.Security.Authentication.AuthenticationException: ‘Authentication failed, see inner exception.’
InnerException: Win32Exception: The client and server cannot communicate, because they do not possess a common algorithm.

image

After a bit of investigation I realised that the combination of this exception and the 502 response returned to Fiddler was pointing to a miss-match between the protocols being requested and those supported. Out of the box Fiddler requests only support a very limited set of protocols for secure connections, shown on the Https tab in the Options dialog.

image

Clicking on the list of protocols allows you to edit them, in this case to include tls 1.1 and 1.2.

image

After applying this change I was able to execute the requests from Fiddler (in this case I’ve left the Https redirection off) and see that the Http protocol matches the 1.1 of the request.

image

The truly annoying thing after all this effort, it would appear the Fiddler doesn’t appear to actually support Http/2, despite there being a dropdown on the Compose tab for it. Using the Http/2.0 option causes exceptions to be raised within the ASP.Core application. Furthermore this seems to be consistent with what happens if you attempt to intercept requests coming from Chrome (they get reverted to HTTP/1.1) and this post.

What does work is using Curl from the command line. However you’ll find that the version you have installed may not support http/2.0 requests. If this is the case, you should download the latest version from https://curl.haxx.se/download.html

At this point it’s also worth having a read through the ASP.NET Core 3 information on Kestrel hosting, specifically the part that talks about http/2 support. In your appsettings.json you can adjust whether you want Http1, Http1AndHttp2, or just Http2 support.

image 

Depending on what protocols you choose to support, you’ll find that different CURL commands will work. Here are some examples:

Protocols = Http2 in the appsettings.json file

curl http://localhost:5000/api/values –http2 -v -k

This attempts to connect with Http1.1 with header Connection: Upgrade, HTTP2-Settings but this fails as connection is Http (not supported scenario on Kestrel)

curl https://localhost:5001/api/values –http2 -v -k

As part of Https negotiation this also upgrades from http1.1 connection to http2. Request succeeds over Http/2

curl http://localhost:5000/api/values –http2-prior-knowledge –v -k

This forces a http/2 connection but still unsecured

Note that the –v option for curl shows verbose information, whilst –k is required when connecting to Kestrel on local machine since the default developer certificate isn’t trusted.

Lazy Dependencies and Interfacing Refit with MvvmCross and Prism

Lazy Dependencies and Interfacing Refit with MvvmCross and Prism

Refit is one of those libraries that makes your life as a developer having to write code to work with services that much easier. By way of an example let’s look at the GET List Users method from the sample REST service available at https://reqres.in/

image

Running the response json through JsonToCSharp we get a class model similar to:

public class User
{
     public int id { get; set; }


    public string first_name { get; set; }


    public string last_name { get; set; }


    public string avatar { get; set; }
}


public class UserList
{
     public int page { get; set; }


    public int per_page { get; set; }


    public int total { get; set; }


    public int total_pages { get; set; }


    public List<User> data { get; set; }
}

Next we define the interface for our service (Note that the Get attribute defines the path, including the page parameter that’s passed into the RetrieveUsers method):

public interface IUserService
{
     [Get(“/api/users?page={page}”)]
     Task<UserList> RetrieveUsers(int page);
}

Of course, we need to add a reference to the Refit NuGet package to our application. Lastly we of course need to retrieve an instance of the UserService, which is where the magic comes in – behind the scene, Refit generates the appropriate implementation for the IUserService so that all you need to do is retrieve it using code similar to:

var userService = RestService.For<IUserService>(“https://reqres.in/”);

This is all well and good but when it comes to writing applications using Prism or MvvmCross, what we really want to be able to do is have the IUserService injected into the constructor of our view model.

Injecting Refit with MvvmCross

We’ll start with MvvmCross (I’ve create a brand new project using MvxScaffold to get me started) and I’ve modified the HomeViewModel to add IUserService as a parameter to the constructor. The service is then used in the ViewAppeared method to retrieve the first page of users.

public class HomeViewModel : BaseViewModel
{
     private IUserService UserService { get; }
     public HomeViewModel(IUserService userService)
     {
         UserService = userService;
     }


    public override async void ViewAppeared()
     {
         base.ViewAppeared();


        var users = await UserService.RetrieveUsers(1);
         Debug.WriteLine(users.data.Count);

     }
}

Now the trick is that we need to register the instance of the IUserService with MvvmCross which we can do at the end of the Initialize method of App.cs in the Core project. We don’t want all of the services to be created at start-up, so instead we register the type using the LazyConstructAndRegisterSingleton extension method: For example:

public override void Initialize()
{
     …
     Mvx.IoCProvider.LazyConstructAndRegisterSingleton<IUserService>
         (() => RestService.For<IUserService>(“https://reqres.in/”));
}

There’s a couple of issues here:

– String literal for the host url

– No ability to override the HttpClient used by the IUserService implementation

Let’s see how we can resolve this by registering some other instances that we can use as part of creating the IUserService. One of the other options for the For method is that we can supply a HttpClient that already has a BaseAddress set. We can also set a HttpMessageHandler on the HttpClient instance that will allow us to customise the behaviour of the HttpClient. Unfortunately the only interface that the HttpClient implements is IDisposable. To get around this we wrap the HttpClient instance in a service which returns the instance as a property:

public interface IHttpService
{
     HttpClient HttpClient { get; }
}


public class HttpService : IHttpService
{
     public HttpService(ICustomHttpMessageHandler customHttpMessageHandler, IServiceOptions options)
     {
         HttpClient = new HttpClient(customHttpMessageHandler as HttpMessageHandler)
         {
             BaseAddress = new Uri(options.BaseUrl)
         };
     }
     public HttpClient HttpClient { get; }
}

Note that in this example the HttpService implementation relies on an ICustomHttpMessageHandler and IServiceOptions. These are here to illustrate the chaining of dependencies that can all be lazy loaded.

public interface ICustomHttpMessageHandler
{
}
public class CustomHttpMessageHandler : DelegatingHandler, ICustomHttpMessageHandler
{
     public CustomHttpMessageHandler(IServiceOptions options)
     {
         InnerHandler = new HttpClientHandler()
         {
             AutomaticDecompression = options.Compression
         };
     }
}
public interface IServiceOptions
{
     string BaseUrl { get; }
     DecompressionMethods Compression { get; }
}
public class ServiceOptions : IServiceOptions
{
     public string BaseUrl { get; set; }
     public DecompressionMethods Compression { get; set; }
}

The final registration code in the Initialize method is:

public override void Initialize()
{
     …
     Mvx.IoCProvider.LazyConstructAndRegisterSingleton<IServiceOptions>(() => new ServiceOptions()
     {
         BaseUrl = “https://reqres.in”,
         Compression = DecompressionMethods.Deflate | DecompressionMethods.GZip
     });
     Mvx.IoCProvider.LazyConstructAndRegisterSingleton<ICustomHttpMessageHandler, CustomHttpMessageHandler>();
     Mvx.IoCProvider.LazyConstructAndRegisterSingleton<IHttpService, HttpService>();
     Mvx.IoCProvider.LazyConstructAndRegisterSingleton<IUserService, IHttpService>
         (service => RestService.For<IUserService>(service.HttpClient));
}

Injecting Refit with Prism

I’m not going to cover over generating the classes and IUserService interface. Instead we’re going to look at how we can register and then make use of the IUserService within Prism. One of the limitations of Prism is that there is no way to register a singleton for lazy creation using a function callback. This means we’d need to register an actual implementation of the IUserService which would mean creating the service instance on app startup instead of when the service is first used. Luckily there is a work around that makes use of the Lazy<T> class. Again, the Lazy<T> doesn’t implement an interface, so we’ll inherit from Lazy<T> and implement a new interface ILazyDependency.

public interface ILazyDependency<T>
{
     T Value { get; }
}
public class LazyDependency<T> : Lazy<T>, ILazyDependency<T>
{
     public LazyDependency(Func<T> valueFactory) : base(valueFactory)
     {
     }
}

And now here’s the registration code (added to the RegisterTypes method in App.xaml.cs):

protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
     …
     containerRegistry.RegisterInstance<IServiceOptions>(new ServiceOptions()
     {
         BaseUrl = “https://reqres.in”,
         Compression = DecompressionMethods.Deflate | DecompressionMethods.GZip
     });
     containerRegistry.RegisterSingleton<ICustomHttpMessageHandler, CustomHttpMessageHandler>();
     containerRegistry.RegisterSingleton<IHttpService, HttpService>();
     containerRegistry.RegisterInstance<ILazyDependency<IUserService>>(
         new LazyDependency<IUserService>(() =>
         RestService.For<IUserService>(
             PrismApplicationBase.Current.Container.Resolve<IHttpService>().HttpClient)
         ));
}

This code looks very similar to the registration code when using MvvmCross. However, the difference is that instead of registering IUserService, it registers ILazyDependency<IUserService>. This is important to note because we need to remember to request the correct interface instance in our view model:

public class MainPageViewModel : ViewModelBase
{
     private IUserService UserService { get; }
     public MainPageViewModel(INavigationService navigationService, ILazyDependency<IUserService> userService)
         : base(navigationService)
     {
         UserService = userService.Value;
         Title = “Main Page”;
     }
     public override async void OnNavigatedTo(INavigationParameters parameters)
     {
         base.OnNavigatedTo(parameters);


        var users = await UserService.RetrieveUsers(0);
         Debug.WriteLine(users.data.Count);
     }
}

And there you have it, we’ve abstracted the Refit implementation away from our view models, making them ready for testing.

#The following code was added to the MvvmCross project to simplify the registration of the IUserService:

public static class MvxIoCContainerExtensions
{
     private static Func<TInterface> CreateResolver<TInterface, TParameter1>(
         this IMvxIoCProvider ioc,
             Func<TParameter1, TInterface> typedConstructor)
             where TInterface : class
             where TParameter1 : class
     {
         return () =>
         {
             ioc.TryResolve(typeof(TParameter1), out var parameter1);
             return typedConstructor((TParameter1)parameter1);
         };
     }


    public static void LazyConstructAndRegisterSingleton<TInterface, TParameter1>(this IMvxIoCProvider ioc, Func<TParameter1, TInterface> constructor)
         where TInterface : class
         where TParameter1 : class
     {
         var resolver = ioc.CreateResolver(constructor);
         ioc.RegisterSingleton(resolver);
     }
}

Note: This code has already been merged into MvvmCross but at time of writing isn’t in the stable release.

Deploying ASP.NET Core 3 to Linux Azure App Service with Docker

Deploying ASP.NET Core 3 to Linux Azure App Service with Docker

In my earlier post I covered creating and debugging an ASP.NET Core service using Docker Desktop. I’m going to build on that and look at how you then push the service into an Azure App Service. Normally I’d simply use the publish option that would allow me to push the service directly into an Azure App Service – this would run the service in much the same way as it runs locally if I was debugging on IISExpress. However, since I’m debugging via a docker container I figured it’d be great to push to Azure in a way that it continues to run in a container. Actually the reason I explored this in the first place was that I’ve been experimenting with GRPC and currently this doesn’t seem to be able to be supported on a regular Azure App Service. I figured if I could run my code in a container there would be less restrictions so I would be able to get GRPC to work (this is work in progress still).

What I did notice in Visual Studio is that when I right-clicked on my ASP.NET Core project and selected Publish, one of the options I saw was to Create new App Service for Containers.

image

Clicking Publish started the wizard to allow me to create the appropriate resources in Azure.

image

Clicking Create will trigger the creation of the selected Azure resources and then proceed to publish the application.

Note: My initial attempt to published failed with an error

“The system cannot find the file specified. In the default daemon configuration on Windows, the docker client must be run elevated to connect. This error may also indicate that the docker daemon is not running.”

Turns out I didn’t have Docker Desktop running (I have so many apps like Slack, Teams, Skype etc that run in background that I force quit most of them each day to try to retain some semblance of a reasonable battery life on my laptop).

Once I realised that I needed to start Docker Desktop, the publish process kicked off and I saw the Docker deployment console appear with quite a detailed breakdown of the upload status – seriously why can’t Visual Studio’s build progress window be this useful. I really need to hand it to the Docker team as their uploading was super resilient. I started off uploading off our standard wifi connection which is based on an ADSL connection, so minimal upload bandwidth. I got impatient so switched mid-upload across to my mobile hotspot – after a second or two delay, the upload retried and continued without missing a beat.

image

Once publishing has completed, the Azure App Service should be all setup and ready to go with your code already published. You can use the Site URL in the publish information pane to launch the service for testing. Since my application was a web api, I’ve appended the /api/values so that I get a valid response from the Get request.

image

One of the thing that continue to amaze me about Visual Studio is the ability to create and publish new projects to Azure. Of course, for production apps, you wouldn’t follow this process at all but it does make spinning up end to end prototype applications a walk in the park.

Shell in v4 of Xamarin.Forms and Visual Studio 2019

Shell in v4 of Xamarin.Forms and Visual Studio 2019

Back in late 2018 I did a post on getting started with Shell where I did a “File-New-Project” with Xamarin.Forms Shell. In this post I’m going to do a quick update to that post looking at creating a new Shell application with Visual Studio 2019, and then upgrading to the preview of Xamarin.Forms Shell v4.

As all great projects start, let’s get going with the Create a new project dialog. Search for Xamarin and select the Mobile App (Xamarin.Forms) template.

image

Give some basic project information

image

Select Shell as the application template.

Note: The Windows (UWP) option has come back (removed in the initial release of Visual Studio 2019) when creating Xamarin.Forms applications. However, since Shell isn’t supported by UWP at the moment, the Windows (UWP) option is currently disabled.

image

And there you have it a new Xamarin.Forms application that you can build and run, that leverages Shell.

image

And looks a little like this with bottom tabs and an ADD button in the navigation bar.

image

But let’s see what v4 is going to give us. Select “Include prerelease” and update to the latest packages.

image

Xamarin.Forms Shell v4

One addition that is more of a cosmetic improvement is the naming of ShellItem and ShellSection – I think the initial intent of these were that they should be somewhat abstracted for the actual UI implementation. However, as Shell has matured, the reality is that ShellItem maps to an item that appears in the flyout and an ShellSection maps to a tab…..

Wow, hold on, what are these things ShellItem, ShellSection and ShellContent? If you haven’t been following what the Xamarin.Forms team have been working on then Shell might come as a bit of a surprise. However, as nearly every app developer will admit, one of the most painfully tedious parts of building an application is create and linking all the pages of the application so that the user can navigate between them. The cognitive load of how to do master-details or tabs even in Xamarin.Forms makes it hard for developers to get started. What Shell aims to achieve is to provide a declarative way for you to define how your application is structured.

Essentially Shell represents a hierarchy of navigation elements:

– Shell – this is represents the application as a whole

– ShellItem – these are the first level pages of the application. Currently if there are multiple ShellItems defined, they’ll automatically appear in a Flyout.

– ShellSection – a page can be broken into sections which essentially map to bottom tabs. If a ShellItem only has one ShellSection, no tabs will show.

– ShellContent – this is the actual page content that will be displayed within the bottom tabs. If a ShellSection has multiple ShellContent, tabs will appear at the top of the tab giving you a tab-sandwich display.

In v4, to make it easier for developers to clearly see what was going on, additional classes, FlyoutItem and Tab were added that sub-class ShellItem and ShellSection respectively. The following example layouts use the new element names – if you’re still on v3.6 of Xamarin.Forms you will need to stick with ShellItem and ShellSection.

Some examples:

Single Page Application

image

Notes:

For a single ShellContent there’s no need to include a Tab element, simply nest it directly under the FlyoutItem.

– The FlyoutBehavior attribute can be used to hide/show the flyout on different pages in the application, or (as in this case) across the whole application. Use Shell.FlyoutBehavior on individual FlyoutItem elements to hide the flyout on those pages.

<Shell … FlyoutBehavior=”Disabled”>
     <FlyoutItem … >
         <ShellContent … />
     </FlyoutItem>
</Shell>

Two Page Application With Flyout

image

<Shell …>
     <FlyoutItem Title=”Home” … >
         <ShellContent … />
     </FlyoutItem>
     <FlyoutItem Title=”Single Page” … >
         <ShellContent … />
     </FlyoutItem>
</Shell>

Looking at the different combination of FlyoutItem, Tab and ShellContent we can get different page behaviours:

Bottom Tabs

image

<FlyoutItem Title=”Bottom Tabs” … >
     <Tab Title=”Home” >
         <ShellContent … />
     </Tab>
     <Tab Title=”Activity” … >
         <ShellContent … />
     </Tab>
</FlyoutItem>

Top Tabs

image

<FlyoutItem Title=”Top Tabs” … >
     <Tab Title=”Activity” … >
         <ShellContent Title=”Shared” … />
         <ShellContent Title=”Notifications” … />
     </Tab>
</FlyoutItem>

Tab Sandwich

image

<FlyoutItem Title=”Tab Sandwich” … >
     <Tab Title=”Activity” … >
         <ShellContent Title=”Shared” … />
         <ShellContent Title=”Notifications” … />
     </Tab>
     <Tab Title=”Updates” … >
         <ShellContent Title=”Updates” … />
         <ShellContent Title=”Home” … />
     </Tab>
</FlyoutItem>

As you will have briefly seen, it’s possible to rapidly stand up the basics of an application using a combination of flyouts and tabs to structure your application. In this post we’ve referenced the preview of the next version of Xamarin.Forms Shell, so you can expect that some of the features, particularly around navigation are subject to change in the coming months.

Debugging ASP.NET Core with Visual Studio and Docker Desktop

Debugging ASP.NET Core with Visual Studio and Docker Desktop

With Visual Studio 2019 hot off the press I’ve been experimenting with a few of the new project templates and the improvements that have been made in Visual Studio. In this post I’m going to cover how to solve a particularly annoying problem I encountered when attempting to run and debug an ASP.NET Core 3 application from within Visual Studio, hosted within a Docker image. I’ll walk through the whole process of creating the new project and the issue I ran into when first attempting to debug the application.

When you launch Visual Studio 2019, or go to create a new project, you’ll see the Create a new project dialog. We’re going to select the ASP.NET Core Web Application template.

image

Next we need to provide the standard project information such as name and location.

image

The next stage is to provide more information about how the template should be configured. Here we’re selecting the API template from the left of the screen, and checking both the https and the Enable Docker Support.

Note: At this point if you haven’t already downloaded and installed Docker Desktop, do it now. It’s a half Gb or so download, so not small, and may take a while based on your network bandwidth.

image

After creating the template, you’ll see that there are a number of options available to us in order to run the application. We’re going to proceed with the Docker option.

image

If you haven’t already, make sure you have launched Docker Desktop, otherwise you’ll see the following warning in Visual Studio when you attempt to run the application.

image

Unless you’ve previously setup Docker Desktop you’ll most likely see the following error. Essentially you need to award Docker Desktop access to a drive in order to create images etc.

image

Right-click the Docker icon in the tray and select Settings

image

Under Shared Drives tab, check the local drives you want to make available to Docker Desktop.

image

When you click Apply you’ll be prompt to authenticate. It will detect the credentials of the current user, which for me is an Azure Active Directory user.

image

Important: Unfortunately after providing my password and clicking OK, Docker Desktop decides that it will uncheck the drive that I had selected. This seems to be a common issue, raised by a couple of different people online. Anyhow, the following steps demonstrate how to setup a different account and using it to allow Docker Desktop to access the drive. Whilst a bit hacky, this does seem to be the only work around for this issue.

To setup a new account launch Settings, click Other users and then click the + button under Other users.

image

When prompted to enter email or phone number, instead click the “I don’t have this persons’ sign-in information” option.

image

Next, click the “Add a user without a Microsoft account” option

image

When prompted, enter username, password and some security questions. Next you need to change this user to be an administrator, so expand out the account under Other users and click Change account type.

image

Change Account type to Administrator

image

Return now to Docker Desktop and enter the new account as part of setting up the shared drive. You shouldn’t see any further issues within the Docker Desktop application.

image

Attempting to run the application from within Visual Studio again reveals an error, this time complaining it doesn’t have authority to crLeate or adjust folders (including creating files). 

image

Locate the folder indicated in the error message, right-click on the folder and select Properties. From the Security tab, click Edit.

image

Add the local account you just created and make sure it’s assigned all permissions.

image

You may need to repeat this process for 2 or 3 folders that Docker Desktop requires access to, and in some case assigning permissions can take a minute or two. Once done, your application will be launched from within a Docker image, with the Visual Studio debugger attached.