UWP and .NET Standard 2.0–Remembering the ‘Forgotten’ APIs :-)

This post comes out of a conversation that I was having with my colleague Pete around the use of the HttpListener class inside of a UWP application.

I’m using HttpListener as an example because it’s the type that we were talking about but there’s many, many other types that I could use instead.

Over the past few years, I’ve been gradually building up a table of APIs in my head partitioned something like;

  • .NET APIs that I know are in the .NET Framework
  • .NET APIs that I know are available to the UWP developer

and so it’s become easier and easier over time to know that (e.g.) a class like HttpListener isn’t available to the UWP developer because that class wasn’t in the API set offered by .NET Core on which UWP apps are based.

Of course, in recent times .NET Standard 2.0 support has come to UWP apps running on Windows Fall Creators Update as detailed;

Announcing UWP Support for .NET Standard 2.0

and so this means that a UWP application that’s definitely running on Windows build 16299 upwards has access to .NET Standard 2.0 making our example API HttpListener suddenly usable inside of a UWP application.

Knowing whether an API is/isn’t in one of these variants of .NET can be tricky to keep in your head but the “.NET API Browser” web page provides a quick look up;

.NET API Browser

So, what does this mean? If I’m sitting in a UWP project that has been set to target 16299 upwards of the UWP platform;

image

and then I can spin up a little piece of a MainPage.xaml type UI;


<Page
     x:Class="App1.MainPage"
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     xmlns:local="using:App1"
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
     mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
         <Viewbox Margin="40">
             <TextBlock>
                 <Run Text="Number of HTTP requests served "/>
                 <Run Text="{x:Bind NumberOfRequests, Mode=OneWay}"/>
             </TextBlock>
         </Viewbox>
     </Grid>
</Page>

and marry that up with a little code behind;


using System;
 using System.ComponentModel;
 using System.IO;
 using System.Linq;
 using System.Net;
 using System.Runtime.CompilerServices;
 using Windows.UI.Xaml;
 using Windows.UI.Xaml.Controls;

namespace App1
 {
     public sealed partial class MainPage : Page, INotifyPropertyChanged
     {
         public event PropertyChangedEventHandler PropertyChanged;

        public MainPage()
         {
             this.InitializeComponent();
             this.Loaded += OnLoaded;
         }
         public int NumberOfRequests
         {
             get => this.numberOfRequests;
             set
             {
                 if (this.numberOfRequests != value)
                 {
                     this.numberOfRequests = value;
                     this.FirePropertyChanged();
                 }
             }
         }
         void FirePropertyChanged([CallerMemberName] string property = null)
         {
             this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
                 () =>
                 {
                     this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
                 }
             );
         }
         async void OnLoaded(object sender, RoutedEventArgs e)
         {
             // an endless async method isn't perhaps the nicest thing in the world
             // but it's very easy to read.
             this.listener = new HttpListener();
             this.listener.Prefixes.Add("http://+:8088/");
             this.listener.Start();

            while (true)
             {
                 var context = await this.listener.GetContextAsync();

                if (context.Request.AcceptTypes.Contains(HTML))
                 {
                     // Ah, for an HtmlTextWriter being part of .NET Standard 2.0 😉
                     context.Response.ContentType = "text/html";
                     context.Response.StatusCode = 200;

                    using (var writer = new StreamWriter(context.Response.OutputStream))
                     {
                         writer.Write(
                             $"<html><body>{DateTime.Now.ToShortTimeString()}</body></html>");
                     }
                     this.NumberOfRequests++;
                 }
                 else
                 {
                     context.Response.StatusCode = 501;
                 }
                 context.Response.Close();
             }
         }
         static readonly string HTML = "text/html";
         HttpListener listener;
         int numberOfRequests;
     }
 }

and then make some changes to my application manifest;

image

and I’ve then got a little web server that I can hit from a second machine asking for //myMachine:8080/whatever and I can see responses being returned and the usage counter going up;

image

and that all seems to work quite nicely Smile

Again, the use of HttpListener here is just an example – I’m not sure whether/where you’d actually want to build a UWP app that offered up an HTTP server so it’s just an example of an API as it happened to be the one that we were discussing.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s