We explore the possibilities of mix and matching web technologies with native Xamarin.Forms.
XAML powering web apps. Based on who you talk to, this brings back the fondest developer memories or a recollection of things gone horribly wrong. While .NET developers enjoyed the ease of development and tooling richness, perhaps the plug-in model just went to die on the web. However, if you are a .NET/C#/XAML aficionado, there may be some new developments providing hope for native technologies powering web apps again. Xamarin.Forms is going places and for developers, this means more platforms to target from shared codebase. This article explores the promise of Xamarin.Forms on the web, debunks some myths and looks ahead at what's to come in future.
Xamarin.Forms allows developers to reuse C# business logic code and provides a UI abstraction for platform support. Developers get to write XAML in a shared UI layer - at runtime, Xamarin.Forms turns around to render native UI for each platform. The platforms that Xamarin.Forms supports are often referred to as Heads or Backends. And the magic of turning generic XAML into native UI for each platform is done by the Renderers - there are renderers for each Xamarin.Forms UI abstraction which do the heavy lifting to render appropriate UI for corresponding platforms.
As mentioned before, some very sharp minds are working on taking Xamarin.Forms places and adding more platform support. Efforts are underway to take Xamarin.Forms support to several new platforms - like MacOS, GTK Linux, WPF, Samsung Tizen and even the the Web. The story of Xamarin.Forms' reach is about to get a whole lot better!
Meet Frank Krueger - developer extraordinaire on a variety of fronts. Frank recently released a small OSS library called Ooui - to be pronounced weee or more practically, like ooey cheesy goodness. Ooui is described as:
A small cross-platform UI library that brings the simplicity of native UI development to the web.
In effect, Ooui provides renderers for Xamarin.Forms XAML - as HTML running on web browsers. Hallelujah!
So, how does this work? Since we are targeting the web, there has to be server serving up the content. When the user makes a request at a given URL, a page is served up that maintains a connection back to the server using Web Sockets. The server maintains an in-memory model of the visual tree and the actual UI is served up using renderers over XAML.Forms XAML. The shadow DOM on the server is kept in sync with the browser UI using a simple messaging protocol with JSON packets over the wire. There are several online samples to play with - you can see how Ooui renders simple to somewhat complicated UI for the web.
There are many ways to use Ooui - developers can choose to use the built-in light-weight web server or serve it up from an ASP.NET Core backend. More on this later.
Ooui | Ooui.AspNetCore | Ooui.Forms | Feature(s) |
---|---|---|---|
Yes | Write the UI using the web DOM and use the built-in web server | ||
Yes | Yes | Write the UI using the web DOM and serve it with ASP.NET Core | |
Yes | Yes | Yes | Write the UI using Xamarin.Forms and serve it with ASP.NET Core |
Yes | Yes | Write the UI using Xamarin.Forms and use the built-in web server |
It is natural to raise questions when you see Xamarin.Forms powering web apps for the first time. So, let us start out debunking some common misconceptions.
Now that we've gotten the basics down, let's take a look at how things work. Ooui sports its own web server, but the easiest way to use it is likely with ASP.NET - yep, it supports the latest ASP.NET Core as a server backend. And it works the same way in Visual Studio - both on Windows and Mac.
You can certainly start from scratch with a web project, but more than likely, you already have a Xamarin.Forms solution - you are just trying to add the web as an additional platform to support. Let's start by adding a regular ASP.NET Core web project - yes, the built-in MVC template totally works.
Make sure that your web project's target framework is .NET Core 2.0 - there are a few things in Ooui that look to depending on modern web sockets support:
Once Visual Studio is done scaffolding, you should have a standard ASP.NET Core web project - yes, you can name it like what you do for your other platfom-specific projects in the Xamarin.Forms solution. You get the point - the web is just another head:
Next up, add all the NuGet packages that Ooui needs to host itself on top of ASP.NET Core and render for the browser - there are three:
In your web project, you'll also want to add references to Xamarin.Forms itself as well as the Xamarin.Forms shared PCL/.NET Standard library. The goal would be to write as little web-specific code as possible and simply use what's in the shared project.
Let's add some code in the Startup.cs file in the web project - we'll use the default MVC configurations and routing. Here's a sample Startup.cs - notice the app.UseOoui()
to bootstrap Ooui within ASP.NET and Xamarin.Forms.Forms.Init()
to initialize the Xamarin.Forms rendering engine:
using Xamarin.Forms;
using Ooui.AspNetCore;
namespace XamarinFormsEveryWhere.Web
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add
// services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
}
// This method gets called by the runtime. Use this method to
// configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app,
IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseOoui();
Xamarin.Forms.Forms.Init();
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}"
);
});
}
}
}
Next up, we need to add some code in HomeController.cs - the default controller that by convention, serves up the Index.cshtml view. Instead of returning a regular view, we'll let Ooui inject itself, like so:
using Ooui.AspNetCore;
using Xamarin.Forms;
using XamarinFormsEverywhere;
namespace XamarinFormsEveryWhere.Web.Controllers
{
public class HomeController : Controller
{
public IActionResult Index()
{
var page = new XamarinFormsEverywherePage();
var element = page.GetOouiElement();
return new ElementResult(element, "Hello, from XAML!");
}
// ...
}
}
The idea is simple - we'll take a named instance of a XAML page in Xamarin.Forms land, and let Ooui render it on a web canvas. Here's the default XAML in our page (code behind is empty):
<?xml version="1.0" encoding="utf-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:XamarinFormsEverywhere"
x:Class="XamarinFormsEverywhere.XamarinFormsEverywherePage">
<Label Text="Welcome to Xamarin Forms!"
VerticalOptions="Center"
HorizontalOptions="Center" />
</ContentPage>
Feeling lucky? Run your app and you'll see XAML UI rendered on the web. This is an over-simplistic example, but a giant promise forward. Ooui has corresponding web renderers for most generic XAML elements and you can bring along most comforts you are used to - like data binding, layouts and converters.
Keep in mind, you do not have to use ASP.NET Core to pull this off - Ooui has a little web server built-in to serve up content to web browsers. And you can build up the visual tree in either a XAML or C# code behind:
using System;
using Ooui;
class Program
{
static void Main(string[] args)
{
var button = new Button("Hello World");
// Rendered UI available at http://localhost:8080/helloworld
UI.Publish ("/helloworld", button);
}
}
Although it's early times, you should clearly see the promise of bringing XAML back to the web in a native way. Turns out, there are a few more ongoing developments to have Xamarin.Forms support the web as a platform - this is all great news for developers wanting to share code amongst various platforms.
One piece of big news recently is XAML styling with CSS being supported within Xamarin.Forms now. For context, Xamarin.Forms apps have always been styled with XAML Styles and Resources. This is a very powerful mechanism with rich tooling built around it.
So why CSS? The reality is lots of Xamarin developers do come from an ASP.NET background. And anybody who has done any web development surely knows some CSS. This is all about reusability of skills through a shim - completely optional for XAML developers to use. In fact, the CSS parser for Xamarin.Forms (pulled into Master branch recently) provides a mapping - between CSS and XAML styles that are already in use. XAML Styling will continue to be more powerful - you cannot style everything with CSS just yet. CSS, on the other hand, has the advantage of better 'trickle down' effect on UI with defined classes and probably better readability. And except for a caret symbol to identify the Xamarin.Forms ContentPage for styling, it is valid CSS - reusable anywhere else.
And the moment we get CSS, developers will clamour for better CSS - yes, Less and Sass are supported with pre-processing and productivity benefits. While tooling is catching up, you can use some Node.JS/Gulp pipeline to process your Sass/Less down to CSS that Xamarin.Forms can make sense of.
While the developer community may be divided on Xamarin.Forms XAML supporting CSS styling, there is a clear winner here - code reusability. In particular, if you are using Ooui to take your XAML to the web, how cool would it be to share some CSS between mobile and web? Simply write out your CSS styles in a separate file, reference it from Xamarin.Forms XAML and have it shared with your web project. That little piece of UI that looks almost identical between web and mobile, can now share the same styling. This is great news for many B2B or Line of Business apps that want to have the same look and branding across platforms.
You may have heard of WebAssembly - a new low level definition of Abstract Syntax Tree (AST) represented in a binary format. Think of it as assembly language that most web browsers can understand and execute. This has huge repercussions for the entire web platform - it would be possible to compile code written in many modern languages into small binary bundles that web browsers execute natively. Do some research on WebAssembly and you'll quickly realize how cool the promise is.
Also, you may have already heard or will be hearing much more about Blazor - a new experimental web UI framework from the ASP.NET team, based on C#/Razor/HTML that runs in the browser via WebAssembly. The promise is to enable developers to write modern SPA web apps that run .NET client-side in web browsers using open web standards. Compared to other web frameworks, .NET can offer stability, easy language support and top-notch developer tooling. Go ahead and play with Blazor - using .NET to write composable native web UI is quite mind blowing.
Now .NET running natively in the web browser is made possible with WebAssembly - without the need for any Plugins or Transpilation. And how are .NET assemblies getting compiled down to WebAssembly? That is thanks to Mono's support for WebAssembly - ongoing work that holds tremendous promise. And guess what .NET runtime powers Xamarin mobile apps - Mono it is. You put 2 and 2 together - and the future of XAML on the web looks quite promising. Keep in mind, Blazor is not even a committed product at this point and is definitely not the way to bring Xamarin apps to the web. However, Mono's support for WebAssembly has to be very welcome news for Xamarin developers - there are some interesting opportunities with Ooui and perhaps multiple ways of bringing XAML UI back to the web. We can all guess for now, but the future looks rather exciting.
PS: As a very recent development, Ooui is already running completely client-side without the need for a server - pure WebAssembly through Ooui.Wasm.
So, if you have been playing with Ooui and trying our Xamarin.Forms renderings for the web, you may get naturally curious - can I support more complicated UI? We make a comprehensive suite of rich performant UI controls for all Xamarin apps - that's Telerik UI for Xamarin. Could the Telerik Xamarin controls now start working for the web?
Well, hold on again tiger. First up, you are unlikely to make full featured web apps with Xamarin.Forms - you would be better served going all out with ASP.NET and JavaScript. And as you know, we offer plenty of web UI - Telerik UI for ASP.NET Ajax, Telerik UI for ASP.NET MVC and Telerik UI for ASP.NET Core. Then you have all of Kendo UI goodness for modern web apps - with support for jQuery, Angular, React and Vue.
If, however, you don't mind living on the bleeding edge and playing with unsupported bits, some of Telerik UI for Xamarin controls do light up on the web - streamed through the Ooui pipeline. Now clearly, we do not have a renderer for web, but some basic controls do work - here's a taste.
In the HomeController.cs file on our web project, let us swap out the XAML page to try things out:
public IActionResult Index()
{
var page = new TelerikUI();
var element = page.GetOouiElement();
return new ElementResult(element, "Hello, from XAML!");
}
Now, back in our Xamarin.Forms shared project (.NET Standard or PCL), we could have a simple XAML page with some markup - no different from anything we would have for mobile apps:
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamarinFormsEverywhere.TelerikUI"
xmlns:telerikPrimitives="clr-namespace:Telerik.XamarinForms.Primitives;assembly=Telerik.XamarinForms.Primitives"
xmlns:telerikInput="clr-namespace:Telerik.XamarinForms.Input;assembly=Telerik.XamarinForms.Input">
<ContentPage.Content>
<StackLayout Orientation="Vertical" VerticalOptions="Center">
<telerikInput:RadButton x:Name="button"
Text="I'm a Telerik Button!"
BorderThickness="2"
BorderColor="#4488F6"
Clicked="Handle_Clicked"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
WidthRequest="200"
HeightRequest="60"/>
<telerikPrimitives:RadSlideView>
<telerikPrimitives:RadSlideView.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>1</x:String>
<x:String>2</x:String>
<x:String>3</x:String>
</x:Array>
</telerikPrimitives:RadSlideView.ItemsSource>
</telerikPrimitives:RadSlideView>
</StackLayout>
</ContentPage.Content>
</ContentPage>
Let's fire it up - yes, you see Telerik UI powered by XAML now on the web browser. Full caveat - this is completely experimental and our engineering teams will likely not be happy. But hey - it's fun to tinker, right?
Did you notice the button we rendered has a Click event handler? Yes, that can live in our XAML code behind file as normal - Ooui automatically hooks up event handlers from the code behind once user requests come back to server. Here's a little alert window - yes, that is a native web alert through the Ooui renderer:
void Handle_Clicked(object sender, EventArgs e)
{
DisplayAlert("Alert", "You have been alerted", "OK");
}
Behold developers - this is our age where software gets to shape our tomorrow. The future may be complex with variety of app platforms, but exciting with code sharing possibilities for developers. With Ooui, you now have a real way to bring Xamarin.Forms native app technologies to the web. And you can bring web CSS goodness back to Xamarin.Forms. The best thing for developers to do in this ever-changing platform landscape may be to pay attention to how apps are architected - make provisions for sharing your code. Abstract business logic into reusable class libaries. Share styling across app platforms. Reuse everything and take your code places - cheers to that.
Sam Basu is a technologist, author, speaker, Microsoft MVP, gadget-lover and Progress Developer Advocate for Telerik products. With a long developer background, he now spends much of his time advocating modern web/mobile/cloud development platforms on Microsoft/Telerik technology stacks. His spare times call for travel, fast cars, cricket and culinary adventures with the family. You can find him on the internet.