0 Comments

pexels-photo-292426

Whether writing a mobile app with Xamarin Forms or native Xamarin.iOS/Xamarin.Android sometimes the requirements demand that your app updates as quickly as possible when something changes on the server. This might be a chat application, stock ticker or any monitoring app showing live data to a user of a process currently running in the backend.

Let's say we wanted to create a simple chat app. If we would go down the path of a traditional Create Read Update Delete (CRUD) app over HTTP, we might choose to poll the server every few seconds or so to read the latest value. While this approach delivers the results, it comes with some drawbacks. To name a few: making requests even though nothing has changed, climbing the leader board on the battery usage category plus your server gets hammered with requests only to tell them: "Sorry no news yet..." - so if not poll lets push. And this is where WebSockets come in.

The only problem with WebSockets is that the implementation in .Net is close to the metal. This results in an additional implementation effort having to be done by the developers. Luckily for .Net developers, there is SignalR which comes with all the boilerplate code you want around WebSockets. A web developer will also tell you about fall back options backed into SingalR. As a Xamarin developer, you will most probably never use those features. But the chances are good that you will be delighted by the ease of handling connections, channels or writing to specific connected clients.

SignalR is around for quite a while; it has been ported over to .Net Core and is .Net Standard compatible. This is excellent news since we can add the SignalR client directly into our Xamarin Forms app - no platform-specific/wrapper code required. But before we can start implementing our client, we will first have to create a SignalR enabled backend.

If you are new to SignalR, be aware that there is quite a big difference between SignalR and SignalR Core. If you are writing a new app today using ASP.NET Core or Azure Functions. You will want to use SignalR Core or else you will go on a nasty error hunt ending with your palm slapping against your forehead ‍🤦‍♂️

The Server

When implementing the backend, we can choose between two options. Either we implement SignalR using ASP.NET Core, or we decide to go with Azures SignalR Core Service. The later can be integrated into ASP.NET Core or an Azure Function app. The Azure option also comes with scaling capabilities - in other words, you get up to 1 Million simultaneous connections using SignalR out of the box.

For more detail on how to set up the Azure Functions and SignalR combo, you will find instructions in the official documentation.

For our simple chat application, we will want a way for our clients to send and receive messages. To achieve this, we will have to create a SignalR Hub that provides a method for sending messages:

[FunctionName("SendMessage")]
public static Task SendMessage(
    [HttpTrigger(AuthorizationLevel.Anonymous, "post")]string message,
    [SignalR(HubName = "SignalRDemo")]IAsyncCollector<SignalRMessage> signalRMessages)
{
    return signalRMessages.AddAsync(
        new SignalRMessage
        {
            Target = "NewMessage",
            Arguments = new[] { message }
        });
}

On invocation, the method will send the message to all connected clients. Which brings us to our next point. Every chat participant will first have to connect to the hub so that messages can be received. So let's implement that registration method:

[FunctionName("Negotiate")]
public static SignalRConnectionInfo Negotiate(
[HttpTrigger(AuthorizationLevel.Anonymous)]HttpRequest req,
[SignalRConnectionInfo(HubName = "SignalRDemo")] SignalRConnectionInfo connectionInfo)
{
    // connectionInfo contains an access key token with a name identifier claim set to the authenticated user
    return connectionInfo;
}

The naming of the method is a convention from SignalR. In other words, you must name the method Negotiate, or your code will not work. No, I do not want to elaborate on how I found this one out the hard way 😉

With the function and SignalR Service in place, we can now turn our focus to the client.

The mobile client

On the mobile client, we want to be able to receive messages and type responses to the group. Our simple app will have to live with the limitation of only receiving messages while being connected. At least for the moment. But here is the chat running in all of its glory.

SignalRChat

Now let's have a look at the ChatService which connects us to the backend and receives messages:

public async Task Connect()
{
    if (_connection.State == HubConnectionState.Connected) return;

    _connection.On<string>("NewMessage", (messageString) =>
    {
        var message = JsonConvert.DeserializeObject<Message>(messageString);
        _newMessage.OnNext(message);
        Debug.WriteLine(messageString);
    });

    await _connection.StartAsync();
}

Note that we register the receiver method before we connect to the backend. This way, we start receiving updates as soon as being connected to the SignalR Service. Now when implementing a receiver method, you must ensure that the type signature matches the method we defined earlier on the server. If the types or the name do not match, you will never receive any messages.

Since reading is only half the fun, let's implement the send message:

public async Task Send(Message message)
{
    var serializedPayload = JsonConvert.SerializeObject(message);

    var response = await _httpClient.PostAsync("https://gnabbersignalr.azurewebsites.net/api/SendMessage", new StringContent(serializedPayload));
    Debug.WriteLine(await response.Content.ReadAsStringAsync());
}

And if you ever had enough from the stream of messages but want to give your eyes the joy of staring at a bare app here is the disconnect method:

public async Task Disconnect()
{
    await _connection.DisposeAsync();

    _connection = new HubConnectionBuilder()
        .WithUrl(backendUrl)
        .Build();
}

I hope you could see that using SignalR it is a breeze to implement a bidirectional communication layer to your server. Which will allow your (mobile) clients to send and receive data in near real-time. Another side effect of using SignalR is that you could easily extend the app with a web client. Since your favourite JavaScript framework will allow you to use the SignalR client. If you are ready to get started with SignalR, be sure to check out the docs.

You can find the entire sample, including all the UI code on GitHub.

This blog is part of the October Xamarin Challenge. So be sure to check out the other posts for more best practices when writing Xamarin apps.

HTH

0 Comments

Ever since I have received my Azure IoT Devkit, I wanted to create a small app with it. The app would let me play around with streaming data from the device and view it on my phone. Also sending data to the device and many other exciting aspects of creating an IoT application. So what better way than to create a system that would stream the sensor data from my devkit to my mobile phone. Once that is implemented, how about creating an alerting system. Should a value increase over a certain threshold, the system will notify me. Many exciting ideas and paired with the capabilities of Azure all in my grasp. So before implementing, let me show you my high-level system design:

System Overview showing the IoT Kit, the different Azure services and the Xamarin mobile app.

However, first we will need to create an app on the device or emulate a device that sends up a stream of data to the Azure cloud over the IoT Hub. Then we will probably want to stream the data to the mobile client using SignalR. And finally visualise all of the data using some nice Xamarin Forms code - perhaps even a fancy charting library.

Once the data is getting streamed to the client let's have a look at alarming scenarios. What if the value e.g. the humidity rises quickly over a short timeframe. We should be able to detect such an event using Stream Analytics and then send a push notification to a client.

SignalR vs IoT Hub

Before diving into the implementation I showed this overview to a friend of mine - to make sure I am not overdoing it with the Azure-candy store. And promptly I got the question: "Hey Mark, so what you are basically doing is a Publish and Subscribe system - why do you need SignalR and IoT Hub. Wouldn't IoT Hub or SignalR offer all you need to send messages at scale to clients?". What a great question - and simplification of the problem. While it is right that what we are doing is nothing else then publishing data and subscribing to it. They are two worlds we are combining here. On the one side we have the IoT world. Here we the creator/company/enterprise produce the software and often also distribute the hardware. So we own the device and software. On the other hand when we release an app we often do not own the device on which the app is running on. So while we generally tend to trust our IoT devices because we create them, harden them and equip them with certificates for communication with our backend - in our case Azure IoT Hub. We generally do not have the same trust in mobile apps. Mobile apps are often deployed to the mobile store and therefore have no guarantee that the app does not end up on a rooted Android or Jailbreaked iOS phone. Once on such a device is often just a cat and mouse game to make it as difficult as possible for an attacker to access the secrets that got installed with the app. In short IoT apps and mobile apps come from a different starting position and therefore we tend to use different approaches for implementing security. And that is why we use two pub/sub systems, because both of them were designed with the two different aspects in mind.

In the next blog post we will get started with writing the IoT client and also see how we can write an IoT client without requiring a devkit.

0 Comments

Image with red dots - intended to look fancy

Some apps require quite a bit of content which is fairly static but changes over time and then the app should adjust and provide the user with the new content. Let's assume we want an app that provides us with quotes and their authors. We could just add the quotes to our app but whenever we wanted to update the app we would have to redeploy our app to the store(s). This can range from an inconvenience to requiring technical expertise for updating the app for simply correcting such a simple thing as a comma. So it becomes evident that in these cases we would like to separate the content from the app itself.

Hosting content does not require running any logic on the server. We do not need any other service than that of a simple file share. With perhaps one or two additional requirements regarding security etc. but more on that later. And that is exactly what Azure Blob Storage can provide us with.

Setting up the blob storage

You are required to have an Azure Account to create a blob storage, the steps, therefore, you can find here. On Azure create a blob storage, under containers, create a Container if you haven't done so already and then upload your data to it. In this sample, we will upload a single JSON file.

Showing Blobstorage Container with one JSON File

In a real application, we could also provide multiple other files including videos and other static files. But for this simple demo, we will stick to a lonely JSON file. We can access the content by calling the URL:

Sample get request with Postman

Having something on a public server always raises questions about security and the sorts. So let's have a look at them.

Security

So let's start with what you get out of the box. The easiest security is if your data is public. Like on a website but for your app. The default you can limit the anonymous access to your blob storage as follows:

  • read-only container: which will allow everyone to read at the container level i.e. "look at the directory" and list all the blobs within.
  • read-only blob: here the caller will have to know which blob he wants to open and is limited to reading the blob storage itself.
  • no read access for anonymous: this will restrict the access to authenticated parties only.

In our sample, we will stick with anonymous blob access. But if you are interested in adding some extra layers of security be sure to check out the Azure Storage security guide which explains the different methods of authentication from shared keys all the way to using Azure Active Directory (Azure AD) for securing the access of your data. Which in summary means Blob Storage is not only quick and convenient in the beginning but can also be modified to add some serious layers of protection.

The client

AppInAction

On the client, we will want to consume the hosted resource and use it in our app. You can do this rather simply within a .Net Standard library using JSON.Net as follows:

string quotesJson;
using (var httpClient = new HttpClient())
{
    var response = await httpClient.GetAsync("https://gnabberonlinestorage.blob.core.windows.net/alpha/quotes.json");
    quotesJson = await response.Content.ReadAsStringAsync();
}
_quotes = JsonConvert.DeserializeObject<List<QuoteInfo>>(quotesJson);

While the above sample works and will get us our data it is not really smart, it will always pull the entire file even if nothing has changed. Fortunately, Azure Blob Storage supports ETags which allows us to be smarter when creating the call, by adding the If-None-Match header to our request as follows:

public async Task Init()
{
    if (_quote != null) return;

    IsBusy = true;
    string quotesJson;
    using (var httpClient = new HttpClient())
    {
        if(!string.IsNullOrEmpty(CurrentEtagVersion)) httpClient.DefaultRequestHeaders.Add("If-None-Match", CurrentEtagVersion);
        var response = await httpClient.GetAsync("https://gnabberonlinestorage.blob.core.windows.net/alpha/quotes.json");

        quotesJson = response.StatusCode == HttpStatusCode.NotModified
            ? ReadQuotesFromCache()
            : await response.Content.ReadAsStringAsync();

        UpdateLocalCache(response.Headers.ETag, quotesJson);
    }
    _quotes = JsonConvert.DeserializeObject<List<QuoteInfo>>(quotesJson);

    PickAndSetQuote();
    IsBusy = false;
}

If the local and remote ETag match, we will not receive any data with the call leaving us with a very small data footprint for this call. The code handling the caching is shown below. Note that for accessing the preferences Xamarin.Essentials were used:

public string CurrentEtagVersion => Preferences.Get(EtagKey, string.Empty);

private void UpdateLocalCache(EntityTagHeaderValue eTag, string quotesJson)
{
    // Only update the cache if we need to
    if (eTag == null || CurrentEtagVersion == eTag.Tag) return;
    Preferences.Set(EtagKey, eTag.Tag);
    File.WriteAllText(_quotesFilename, quotesJson);
}

private string ReadQuotesFromCache()
{
    if (!File.Exists(_quotesFilename)) return string.Empty;
    return File.ReadAllText(_quotesFilename);
}

I will leave it there with this sample but since we are already storing the data in a local cache we could also consider making this app fully Offline capable. With Xamarin Essentials, which we are already using, we can check if we have a network connection and what kind of connection. This information allows us to decide if we want/can access the remote storage or rather load the data from the initial cache.

You can find the entire client sample code on GitHub.

Conclusion

In this post, we saw how you can use Azure Blob storage as a backend service to host the content of your app without having to implement any web server. You can add security layers to the storage. Tracking changes on the backend are provided out of the box via HTTP ETags.

But how much will this cost me? Probably less than you would think but check out the Blob Storage pricing to get your exact number.

0 Comments

When working with a mobile app you will often work with a backend, which if you are working with C# might very probably be a Web API backend. In this blog we will look at how we can consume and write to a Web API Controller that we can host on Azure. Why Azure? Because it is the easiest way of hosting a web service straight out of Visual Studio and if you happen to have a MSDN subscription you can do this all for free. For the client we will be using a Windows 10 Universal App which allows us to write a client for Desktop, Tablet and Phone.

The app we will be building will add the capability to read a list of people from a service and add a person to the existing. So we will see how we can read and write to a HTTP service.

The client

As a client we will be targeting Windows Phone (soon to be Windows Mobile again), Android and iOS. Our implementation of integrating with the backend we will perform in the Portable Class Library (PCL) which provides us the unique advantage of only having to write our backend service integration once.

PCL integration

In the PCL we will require the following NuGet packages:

Armed with the capabilities of now being able to communicate to a HTTP backend and serializing i.e. deserializing objects to and from JSON we can start implementing our communication layer by creating a HTTP client in the constructor. We usually only need one instance of the HTTP client as it will handle multiple requests and only spawn as many active connections as are reasonable over HTTP:

public class PersonService : IPersonService
{
    private HttpClient _httpClient;

    public PersonService()
    {
        _httpClient = new HttpClient();
    }

    // ... Person Service implementation
}

For reading over HTTP we should use the GET keyword which is provided by the HTTP client and is implemented as follows:

public async Task<IEnumerable<Person>> GetPeople()
{
    var result = await _httpClient.GetAsync(BASE_URI);
    var peopleJson = await result.Content.ReadAsStringAsync();

    return JsonConvert.DeserializeObject<IEnumerable<Person>>(peopleJson);
}

Note that if you are using a free website on Azure you can choose to run communications over SSL, the only thing you have to change for this is adding an s in the URI after http i.e. resulting in an https URI.

Writing to a HTTP service depends on the action we want to perform. Creating something new e.g. adding a new person to the existing person list, should be performed over a HTTP POST.  Implementing the post can be done as follows:

public async Task<bool> CreatePerson(Person person)
{
    var personJson = JsonConvert.SerializeObject(person);
    var content = new StringContent(personJson, Encoding.UTF8, "application/json");
    var result = await _httpClient.PostAsync(BASE_URI, content);

    return result.IsSuccessStatusCode;
}

The StringContent method has additional parameters to indicate to the server how the content can be interpreted. This is required to inform the backend service that the data we are sending is serialized as JSON. Not doing so would end in false information in the header which would prevent Web API to automatically deserialize the body.

Updating an existing person usually is done via PUT, which is similar to the CreatePerson method but contains an ID in the URI which usually corresponds with the ID from the Person which is set on the backend.

public async Task<bool> UpdatePerson(int id, Person person)
{
    var uri = Path.Combine(BASE_URI, id.ToString());

    var personJson = JsonConvert.SerializeObject(person);
    var content = new StringContent(personJson, Encoding.UTF8, "application/json");

    var result = await _httpClient.PutAsync(uri, content);

    return result.IsSuccessStatusCode;
}

As you can see implementing a Web service is quite straight forward with the HTTP Client and allows to easily create a backend integration for native clients that can be shared across platforms.

The UI

On the client side we now can invoke our portable service and display a list of people.

<Page
    x:Class="HttpClientSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:HttpClientSample"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    DataContext="{Binding Main, Source={StaticResource Locator}}"
    mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <GridView ItemsSource="{Binding People}" SelectedItem="{Binding SelectedPerson, Mode=TwoWay}"></GridView>

        <AppBar VerticalAlignment="Bottom">
            <AppBarButton Icon="Add" Label="Add" Command="{Binding AddNewPerson}" />
        </AppBar>
    </Grid>
</Page>

In the ViewModel we can invoke the backend service to provide the data.

public class MainViewModel:ViewModelBase
{
    private readonly IPersonService _personService;
    private ObservableCollection<Person> _people;
    private Person _selectedPerson;

    public MainViewModel(IPersonService personService)
    {
        if (personService == null) throw new ArgumentNullException(nameof(personService));
        _personService = personService;
        _people = new ObservableCollection<Person>();
        ShowPerson = person => { };
        AddNewPerson = new RelayCommand(() => ShowPerson(0));
    }

    public ObservableCollection<Person> People => _people;
    public Action<int> ShowPerson { get; set; }

    public Person SelectedPerson
    {
        get { return _selectedPerson; }
        set
        {
            if (_selectedPerson == value) return;
            _selectedPerson = value;
            RaisePropertyChanged(nameof(SelectedPerson));
            if (_selectedPerson != null) ShowPerson(_people.IndexOf(_selectedPerson));
        }
    }

    public ICommand AddNewPerson { get; private set; }

    public async Task Init()
    {
        var people = await _personService.GetPeople();

        _people.Clear();

        foreach (var person in people)
        {
            _people.Add(person);
        }
    }
}

Adding a person means we have to add a further page to our client application that provides us with a form to enter the name and first name of a person. To keep things simple we will just use the same UI and identify via the navigation parameter if we have to create or update the person on the backend.

<Page
    x:Class="HttpClientSample.PersonDetail"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:HttpClientSample"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    DataContext="{Binding Person, Source={StaticResource Locator}}"
    Loaded="PersonDetail_OnLoaded"
    mc:Ignorable="d">

    <StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <TextBox Header="Firstname" Text="{Binding Firstname, Mode=TwoWay}"/>
        <TextBox Header="Lastname" Text="{Binding Lastname, Mode=TwoWay}"/>
        <Button Content="Save" Command="{Binding StoreCommand, Mode=TwoWay}" IsEnabled="{Binding HasPendingChanges}" HorizontalAlignment="Center" Margin="0,10"/>
    </StackPanel>
</Page>

The ViewModel is handling the integration with the PersonService from the PCL library:

public class PersonViewModel:ViewModelBase
{
    private readonly IPersonService _personService;
    private int _id;
    private string _firstname;
    private string _lastname;
    private bool _hasPendingChanges;

    public PersonViewModel(IPersonService personService)
    {
        if (personService == null) throw new ArgumentNullException(nameof(personService));
        _personService = personService;

        StoreCommand = new RelayCommand(StorePerson, () => true);
        HasPendingChanges = false;
    }

    public bool HasPendingChanges
    {
        get { return _hasPendingChanges; }
        set
        {
            if (value == _hasPendingChanges) return;
            _hasPendingChanges = value;
            RaisePropertyChanged(nameof(HasPendingChanges));
        }
    }

    public string Firstname
    {
        get { return _firstname; }
        set
        {
            if (value == _firstname) return;
            _firstname = value;
            HasPendingChanges = true;
            RaisePropertyChanged(nameof(Firstname));
        }
    }

    public string Lastname
    {
        get { return _lastname; }
        set
        {
            if (_lastname == value) return;
            _lastname = value;
            HasPendingChanges = true;
            RaisePropertyChanged(nameof(Lastname));
        }
    }

    public ICommand StoreCommand { get; set; }

    public async Task Init(int id)
    {
        _id = id;
        var person = id > 0 ? (await _personService.GetPeople()).ToList()[id] : new Person("", "");
        Firstname = person.FirstName;
        Lastname = person.LastName;
        HasPendingChanges = false;
    }

    private async void StorePerson()
    {
        HasPendingChanges = false;

        var person = new Person(Firstname, Lastname);

        if (_id > 0)
        {
            await _personService.UpdatePerson(_id, person);
        }
        else
        {
            await _personService.CreatePerson(person);
        }

        HasPendingChanges = false;
    }
}

Again integrating a PCL library is not difficult and requires no additional hoops to jump through. What we gain by putting our logic into the PCL is that we can reuse the code across multiple platforms.

The Controller

We will focus on the client part during this post but for getting an understanding of the bigger picture here is the controller we will be communicating with.

public class PersonController : ApiController
{
    private readonly static Lazy<IList<Person>> _people = new Lazy<IList<Person>>(() => new PersonService().GeneratePeople(1000), LazyThreadSafetyMode.PublicationOnly);
    // GET: api/Person
    public IEnumerable<Person> Get()
    {
        return _people.Value;
    }

    // GET: api/Person/5
    public Person Get(int id)
    {
        if (id < 0 || _people.Value.Count < id) return null;
        return _people.Value[id];
    }

    // POST: api/Person
    [HttpPost]
    public IHttpActionResult Post(Person value)
    {
        if (value == null) return BadRequest();

        _people.Value.Add(value);

        return CreatedAtRoute("DefaultApi", new { id = _people.Value.IndexOf(value) }, _people.Value.Last());
    }

    // PUT: api/Person/5
    [HttpPut]
    public IHttpActionResult Put(int id, [FromBody]Person value)
    {
        if (id < 0 || id >= _people.Value.Count()) return BadRequest();

        _people.Value[id] = value;

        return Ok(value);
    }

    // DELETE: api/Person/5
    public IHttpActionResult Delete(int id)
    {
        if (id < 0 || id >= _people.Value.Count()) return BadRequest();

        _people.Value.RemoveAt(id);

        return StatusCode(System.Net.HttpStatusCode.NoContent);
    }
}

internal class PersonService
{
    public IList<Person> GeneratePeople(int count)
    {
        var firstNames = new List<string>(count);
        var lastNames = new List<string>(count);

        for (int i = 0; i < count; ++i)
        {
            firstNames.Add(NameGenerator.GenRandomFirstName());
            lastNames.Add(NameGenerator.GenRandomLastName());
        }

        return firstNames.Zip(lastNames, (firstName, lastName) => new Person(firstName, lastName)).ToList();
    }
}

As you can see it is rather basic and through the static variable we have some sort of poor mans database. Do not use this way of storing data in a production environment!

Conclusion

In this post we saw how we can integrate a ASP.Net Web API server in a PCL. Thereby seeing how to read and write objects to a web service. Further we saw how we can display and enter the data on a Windows 10 client. The entire sample could have been written for Xamarin.iOS, Xamarin.Android or WPF which is exactly the sweet spot of writing your business logic in the PCL it does not matter what client you are intending to write now or in the future as long as the PCL allows you to integrate multiple client platforms.

You can find the entire sample project on NuGet.

0 Comments

In this post I want to look at how to create a Web API project with F# and host it on Azure. This will part of a blog series on how to create a mobile application (incl. the backend) based on F#. The blog post assumes that you the reader has a basic understanding of how to create a Web API web service.

F# is a functional programming language based on the .Net Framework which contrary to many other functional programming languages also makes it a general purpose language. In my endeavor to explore a functional programming language I chose F# as it will allow me to create not only .Net applications but also Xamarin based cross platform apps.

To deploy to Azure you will need a valid Azure account. Alternatively you can run the App on your local machine.

Setting up the project

I’ll be using Visual Studio 2015 RC for this setup but you can follow along on VS 2013 just as well. Create a new project then go to Online projects, Select Visual F# and then select F# MVC 5. This only has to be done during the first setup. From now on you will find the project template under the Installedproject templates.

NewProjectFromOnlineTemplate

Having a look at the solution

If you are familiar with a Web API solution you will find yourself right at home.

WebApiSolution

Under Controllers you find the expected definitions, as well as under models. The Global.asax.fs also has a familiar ring to it:

namespace FSharpWebSample

open System
open System.Net.Http
open System.Web
open System.Web.Http
open System.Web.Routing

type HttpRoute = {
    controller : string
    id : RouteParameter }

type Global() =
    inherit System.Web.HttpApplication() 

    static member RegisterWebApi(config: HttpConfiguration) =
        // Configure routing
        config.MapHttpAttributeRoutes()
        config.Routes.MapHttpRoute(
            "DefaultApi", // Route name
            "api/{controller}/{id}", // URL with parameters
            { controller = "{controller}"; id = RouteParameter.Optional } // Parameter defaults
        ) |> ignore

        // Configure serialization
        config.Formatters.XmlFormatter.UseXmlSerializer <- true
        config.Formatters.JsonFormatter.SerializerSettings.ContractResolver <- Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver()

        // Additional Web API settings

    member x.Application_Start() =
        GlobalConfiguration.Configure(Action<_> Global.RegisterWebApi)

Extending the Controller

When we look at the controller we see that an array of the model is created and there is on method that will return the list. Let’s extend the controller to return a value requested by it’s Id. So first we have to extend the model Car.fs:

namespace FSharpWebSample.Models

open Newtonsoft.Json

[<CLIMutable>]
type Car = {
    Make : string
    Model : string
    Id : int
}

Now we can extend the CarsController.fs so that we can filter the list and get the according value:

namespace FSharpWebSample.Controllers
open System
open System.Collections.Generic
open System.Linq
open System.Net.Http
open System.Web.Http
open FSharpWebSample.Models

/// Retrieves values.
type CarsController() =
    inherit ApiController()
    
    let values = [ { Make = "Ford"; Model = "Mustang"; Id = 1 }; { Make = "Nissan"; Model = "Titan"; Id = 2 }; { Make = "Audi"; Model = "R8"; Id = 3 } ]
    
    /// Gets all values.
    member x.Get() = values
    
    member x.Get(id:int) = values |> List.filter(fun v -> v.Id = id)

Deploying to Azure

Deploying to azure luckily is luckely the same as it always has been for C#, right click onto the Web API project, select Publish…, Microsoft Azure Web Apps then create a new web app enter a name and finally click on Pubish. Now all that is left is to test the web service so lets do this the manual way.

Testing the controller

Opening the prefered browser of your choice e.g. the new Edge browser enter the path to the azure website and be executing the following URI:

http://fsharpwebsample.azurewebsites.net/api/cars

We receive the entire list:

[{"make":"Ford","model":"Mustang","id":1},{"make":"Nissan","model":"Titan","id":2},{"make":"Audi","model":"R8","id":3}]

When we add a Id parameter:

http://fsharpwebsample.azurewebsites.net/api/cars/3

We only receive the requested record:

[{"make":"Audi","model":"R8","id":3}]

Conclusion

Creating a Web API service with F# is not much different than creating it with C# thanks to Ryan Riley and Daniel Mohl who provide the F# MVC 5 template. Also uploading it to Azure and sending requests are the way one would expect the service to run. Looking forward to go on further down the F# rabbit hole.

You can find the sample on GitHub.