Application Insights for Xamarin- and UWP apps with TinyInsights

About two and a half years ago I created a library with the name TinyInsights with the idea to abstract away the underlying provider for diagnostics and analytics. The reason was that I wanted to make it possible to change the provider without that it affected my code more than in the initial setup of the app. Because diagnostics- and analytics services have a tendency to come and go, for example, Xamarin Insights and HockeyApp are no longer with us. Instead, we now have AppCenter, which also was my first provider for TinyInsights. I also wanted to make it possible to use multiple providers at the same time, because I have worked with apps where business analysts want the data to be in Google Analytics and developers want another service because other services are better for finding errors in apps.

My default provider has been AppCenter the last years, but recently I have missed a couple of important features and you can not analyze the data any deeper. You can export the data to Application Insights and then you can create deeper reports etc. But the way AppCenter store data make some questions harder to make in a good way. For example, if you want to track page views, you have to do that as an event. Application Insights is not built to handle page views that way, because it has real support for page views. AppCenter also lacks the future of tracking dependencies.

So what I decided to do was to create a new provider to TinyInsights with support for Application Insights. But I still using AppCenter for crashes and errors, because it also supporting me to upload symbols to it and Application Insights have no good way to distinguish between an error and a crash. But when I am logging crashes to Application Insights I am setting a custom property with the name "IsCrash" to "true".

I have implemented TrackDependency to all providers, but for AppCenter it only saves all data as custom properties and there is no good way to visualize them, but the data is there if you want to export it to your own visualizer.

Below I have written a short introduction about how to get started with the ApplicationInsightsProvider and TinyInsights in general.

Initializing Application Insights Provider

When initializing TinyInsights you need to specify what provider or providers you want to use. For Application Insights, you only need to give it the IntrumentationKey. If you don't pass different keys for different platforms all data will be collected together and not as in AppCenter where you create one app per platform.

var appInsights = new ApplicationInsightsProvider("{InstrumentationKey}");
var appCenter = new AppCenterProvider("{keyForIOS}", "{keyForAndroid}", {keyForUWP});
appCenter.IsTrackPageViewsEnabled = false;
appCenter.IsTrackEventsEnabled = false;
appCenter.IsTrackDependencyEnabled = false;
 
TinyInsights.Configure(appCenterProvider, applicationInsightsProvider);

Handling exceptions

To track exceptions/errors, just use the TrackErrorAsync method. Crashes will automatcially be tracked and sent to Application Insights next time the user is starting the app.

catch(Ecception ex)
{
     await TinyInsights.TrackErrorAsync(ex);
}
 
//with properties
var properties = new  Dictionarty<string, string>();
properties.Add("MyFirstProperty", "MyFirstValue");
properties.Add("MySecondProperty", "MySeconndValue");
 
catch(Ecception ex)
{
     await TinyInsights.TrackErrorAsync(ex, properties);
}

Tracking dependencies

There are a two of ways to track dependencies with TinyInsights.
The first and the basic method is TrackDependencyAsync, and is also used in the background by the other way to do it.

var startTime = DateTimeOffset.Now;
 
var success = await GetData();
 
var duration = DateTimeOffset.Now - startTime
 
await TinyInsights.TrackDependencyAsync("api.mydomain.se", "https://api/mydomain.se/v1/data/get", startTime, duration, success);

The second way is to create a TinyDependency object that handles most of the tracking for you. You will do that by just by wrapping your code for the dependency in a using statement.

using (var tracker = TinyInsights.CreateDependencyTracker("api.mydomain.se", "https://api/mydomain.se/v1/data/get"))
{
     await GetData();
}

If the dependency succeded that is fine, but if it not you need to handle that on your own, using the Finish method of the TinyDependency object.

using (var tracker = TinyInsights.CreateDependencyTracker("api.mydomain.se", "https://api/mydomain.se/v1/data/get"))
{
     try
     {
          var repsonse = await GetData();
 
          if(!response.IsSuccessStatusCode)
          {
               await tracker.Finish(false, (int)response.StatusCode);
          }
     }
     catch(Exception ex)
     {
          tracker.Finish(false, ex);
     }
}

Tracking page views

To track page views, just use the TrackPageViewAsync method.

await TinyInsights.TrackPageViewAsync("SuperCoolView");
 
//with properties
var properties = new  Dictionarty<string, string>();
properties.Add("MyFirstProperty", "MyFirstValue");
properties.Add("MySecondProperty", "MySeconndValue");
 
await TinyInsights.TrackPageViewAsync("SuperCoolView", properties);

Tracking events

To track events, just use the TrackEventAync method.

await TinyInsights.TrackEventAsync("SuperCoolEvent");
 
//with properties
var properties = new  Dictionarty<string, string>();
properties.Add("MyFirstProperty", "MyFirstValue");
properties.Add("MySecondProperty", "MySeconndValue");
 
await TinyInsights.TrackEventAsync("SuperCoolEvent", properties);

Feedback

If you have any feedback, please create an issue on GitHub. You will also be welcome to contribute to the library with improvments or/and other providers.
 

Azure Static Websites: Navigate to routes in a SPA using URL

I and my colleagues recently developed an app with Rect that we hosting using Static Websites in Azure. When we ran the application on our development machines everything works well when we navigated to route using a URL., but when we deployed it to Azure, that stopped to work. The only thing we could do was to navigate to the root route.

When you are building a SPA application you want the application to handle all routes for you. And if we only specify an "Index document name" in the settings or the static websites, we will get back an ugly 404 page for all routes other then the root route. The reason is that Azure is trying to serve us a file with that name because it thinks we want another document than the index.html.

The solutions are to specify the index.html file as an "Error document path". When we have done so, our application can handle the routing for us!

 

Xamarin ♥ Azure SignalR Service

Azure SignalR Service is a service in Microsoft Azure that makes it possible for developers to build applications with real-time communications without having to think about how to host it. Azure will handle all that for us.

If you are interested to learn more about SignarlR service and Xamarin apps there is a chapter in the Xamarin.Forms project, the book that I have written together with Johan Karlsson that cover the subject. In the book, you will get step-by-step guidance on how to set up the backend and how to write the app from "file new" to a full app. Read more about the book here, https://www.packtpub.com/application-development/xamarinforms-projects.

This post will cover:

  • How to set up a simple backend built with Azure functions and Azure SignalR service
  • How to use SignalR in a Xamarin App.

Setting up a backend

For the backend, we need to create two services in the Azure portal.

  1. Create a SignalRServcie in a new resource group
  2. Create a Function App in the same resouce group.

Open Visual Studio and create a new Azure Functions projects.

Install the NuGet package, Microsoft.Azure.WebJobs.Extensions.SignalRService. We need to check the "Show prereleases" checkbox to find the package, because it is still just a pre-release.

Create a new function with the name GetSignalRConnectionInfo.

public class GetSignalRConnectionInfo
{
        [FunctionName("GetSignalRConnectionInfo")]
        public static SignalRConnectionInfo Run(
            [HttpTrigger(AuthorizationLevel.Anonymous)] HttpRequest req,
            [SignalRConnectionInfo(HubName = "chat")] SignalRConnectionInfo connectionInfo)
        {
            return connectionInfo;
        }
}

The SignalRConnectionInfo attribute is used to read the information from the configuration and to generate an access token. If the function should be able to read the information from the configuration we need to add it. What we should add is the connection string that we will find in the Azure Portal in the Keys tab under the SignalR Service. It will be added with the key AzureSignalRConnectionString to the ApplicationSettings of the Function App or to the local.settings.json file in our Visual Studio project if we want to run the function locally. It is also with the attribute we can set the name of the hub that we want to use, we can have multiple hubs in a SignalR Service.

Next step is to create a function that will add messages to the SignalR Service. Create a new function with the name SendMessages.

public class SendMessages
{
        [FunctionName("SendMessages")]
        public async static Task Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "post")] object message,
            [SignalR(HubName = "chat")] IAsyncCollector<SignalRMessage> signalRMessages)
        {
            await signalRMessages.AddAsync(
                new SignalRMessage
                {
                    Target = "chatMessage",
                Arguments = new[] { message }
                });
        }
}

Use the SignalR attribute and an IAsyncCollector parameter to get a collection that you can use for adding messages to the SignalR Service. Target is a key that we can listen after in the app.

If we want to add some logic, for example, some type of validation we can do it here, before we add the message to the collection. In the app we are building in the book can the users upload photos. Then we use Azure Cognitive Services to make sure that the photos not are classified as adult photos.

Authentication

If we want to add authentication to our SignalR Service we should add it to the function that returns the connection info.

Building the app

To build an app with Xamarin we need to install the Microsoft.AspNetCore.SignalR.Client NuGet package.

Create a connection and start listening for messages

First we will create a model for connection information:

public class ConnectionInfo
{
     public string Url { get; set; }
     public string AccessToken { get; set; }
}

Now we can make an HTTP call to the function we created for getting connection information. When we get an answer we will serialize it to a ConnectionInfo model.

var result = await httpClient.GetStringAsync("https://{name-of-your-function}.azurewebsites.net/api/GetSignalRConnectionInfo");
var info = JsonConvert.DeserializeObject<Models.ConnectionInfo>(result);

Now we have all the information that we need to connect to the SignalR Service. To create a connection we will use the HubConnectionBuilder.

var connectionBuilder = new HubConnectionBuilder();
connectionBuilder.WithUrl(info.Url, (Microsoft.AspNetCore.Http.Connections.Client.HttpConnectionOptions obj) =>
{
     obj.AccessTokenProvider = () => Task.Run(() => info.AccessToken);
});
 
var hub = connectionBuilder.Build();

To subscribe for messages we will use the On<object> method on the hub. We will pass the key that we specified in the message and an Action, in this case, we using an expression for the action.

In the expression body, we will handle the message, the message will come as a string so we need to convert the object to a string and then we can deserialize it to the type of message that we will receive. In this case, I have created a model with the name Message.

The last thing to do to start to listen for messages is to call the StartAsync method on the hub.

hub.On<object>("chatMessage", (message) =>
{
      var json = message.ToString();
      var obj = JsonConvert.DeserializeObject<Message>(json);
 
      //Handle the message here
});
 
await hub.StartAsync();

Sending a message

To sending a message is just a simple POST to the SendMessages function.

public async Task SendMessage(Message message)
{
     var json = JsonConvert.SerializeObject(message);
 
     var content = new StringContent(json, Encoding.UTF8, "application/json");
 
     var response = await httpClient.PostAsync("https://xfbook.azurewebsites.net/api/SendMessages", content);
}

OnSuspend and OnResume

It is important to handle the suspend and resumes events. The best way to that is to override OnSuspend and OnResume in App.xaml.cs. I recommended that you create a Dispose method in the same class as we have the other code that is related to SignalR. In this method, we will stop listening for messages and dispose the hub.

public async Task Dispose()
{
     if(hub != null)
     {
          await hub.StopAsync();
          await hub.DisposeAsync();
     }
}

And then we can call the Dispose method from the OnSuspend method. In the OnResume method, we can start the connection again.

Xamarin Month

This blog post is a part of Xamarin Month. Follow this link to read all the other blog post of the Xamarin Month.

Azure functions for single page websites

Some applications are applications that are not used so often, maybe just once a month to update or add a value to a database that a calculation service is using. I’m building a service like that for a customer right now.

While the websites are just used once a month it feels unnecessary to have a website running all the time. Instead for creating a website in Azure App Services I created an Azure function. Azure functions are what is called serverless, which means you don’t have to manage a server at all. You just deploy snippets of code that will be executed when it’s triggered to run, instead of a service that running all the time just waiting for “something to do”.

Many examples about returning HTML from a function that I have read is embedding HTML in the C# code. I don’t like that approach at all, it maybe works if you will create a “Hello World” website. But in my case, I wanted to have a website with a form and validation with JavaScript etc. And when I posting my form I do it to another function that saves the values to the database.

What I did was to add an HTML page in my Visual Studio project and changed Build action from None to Embedded Resource. While it is an HTML page I can edit HTML, CSS and JavaScript will the full power of Visual Studio. The static resources I used for my webpage, like (images, JavaScript- and CSS frameworks), I uploaded to Azure blob storage. While I have them in Azure blob storage I also could add them to a CDN network.

Below is the code that I'm using in the function to read the HTML page and return the result to the browser as an HTML page.

var assembly = Assembly.GetExecutingAssembly();
var resourceName = "MyWebPage.form.html";
 
using (Stream stream = assembly.GetManifestResourceStream(resourceName))
{
    using (StreamReader reader = new StreamReader(stream))
    {
        string result = reader.ReadToEnd();
 
        var response = new HttpResponseMessage(HttpStatusCode.OK);
        response.Content = new StringContent(result);
        response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("text/html");
 
        return response;
    }
}

MSDN-förmåner

Du vet väl av att du som har ett MSDN abbonemang har tillgång både till Azure och gratis utbildning? Väldigt många har helt missat att det följer med förmåner som bara försvinner om man inte utnyttjar dem.

Med ditt MSDN.abbonemang följer möjligheten att använda resurser för mellan 50-150 $ månad. Väldigt bra om man vill testa något i befintlig eller kika på nästa version av Microsoft produkter. Framförallt finns också möjligheterna att labba med TFS & Visual Studio!

Det finns ingen risk för ”omedvetna” kostnader och ingen betalkort info krävs för aktivering. För att aktivera Azure-förmånen, logga in på MSDN, https://msdn.microsoft.com/sv-se/subscriptions/manage

MSDN Pluralsight förmån
Med ditt MSDN abbonemang får du också tillgång till ett begränsat utbud (beroende på MSDN abbonemanget) av Pluralsights kurser. Där finns tex kurser om Microsoft Test manager, Fakes, Intellitrace och Scrum med TFS. Klicka bara på länken och logga in med det Microsoft Account (LiveId) som är kopplat till ditt MSDN abbonemang. https://msdn.microsoft.com/sv-se/subscriptions/manage

WordRoom – vägen till cross platform med Xamarin och Azure

Att bygga ett onlinespel innebär många utmaningar, att bygga ett onlinespel cross platform innebär ännu fler utmaningar. Under TechDays kommer jag och Johan Karlsson att berätta om våra erfarenheter efter att vi byggde ordspelet WordRoom där vi använde Xamarin dels för att kunna använda C#, men främst för att kunna dela klientkod mellan alla plattformarna för att spara utvecklingstid och öka förvaltningsbarheten. Som backend använder vi en lösning hostad i Windows Azure, en lösning som är fullt skalbar för att kunna skalas både upp och ner beroende på hur belastningen ser ut.

Under vår session på TechDays kommer vi att fokusera på dessa områden

  • Hur man bygger en cross platform lösning för mobila enheter med hjälp av Xamarin
    Vi kommer att berätta varför vi valde Xamarin och vilken arkitektur vi använder för WordRoom för att kunna dela så mycket kod som möjligt mellan de olika plattformarna, vilken kod man kan dela och vilken kod som måste vara plattformsspecifik.
  • Vad man behöver tänka på för att bygga en skalbar backend med hjälp av Azure
    WordRoom använder flera olika tjänster i Azure. Vi kommer att berätta vilka vi använder och hur vi tänkte när vi byggde en arkitektur anpassad för att kunna utnyttja Azure optimalt.

 

WordRoom finns att ladda mer för Windows 8+, Windows Phone, iOS och Android.

Azure Mobile Services and Autofac

If you want to use an IoC container in your backend hosted in Azure Mobile Services I recommend to use Autofac. The reason is that Autofac already are wired up in Mobile Services and is used by the runtime to resolve references.

Because Autofac already is wired up you cannot create a container as you use to when not hosting in Mobile Services.

To configure how to resolve your references using Autofac in Mobile Services se the code below. The code should be in the register method in the WebApiConfig class. The class can be found in App_Start folder.

ConfigOptions options = new ConfigOptions();
var configBuilder = new ConfigBuilder(options, builder =>
{
      builder.RegisterType<MyImplementation>().As<IMyInterface>();
});
 
HttpConfiguration config = ServiceConfig.Initialize(configBuilder);
configBuilder.ConfigureOwin(config);

Authentication for REST calls with HTTPClient to Azure MobileServies

In a current project I working with an app that uses a .NET Backend in Azure Mobile Services. Backend is a WebAPI.

On client side I have all the code for networking in portable class library so I can reuse it on other platforms. Right now we are building the app for Windows Phone, but the plan is to build it for both iOS and Android using Xamarin. I am using the HttpClient object to do the REST calls. HttpClient is not in portable class library per default. But if you download “Microsoft HTTP Client Libraries” from NuGet you will get it.

My first problem was about which credentials I should use for the REST call to Azure. You can only see the application key in the portal. Is that the password? And what is the username in that case? The answer is that the application key is the password and username is just an empty string.
Problem number two was how to specify the credentials. My first try was to add the as the code below shows.

var handler = new HttpClientHandler {Credentials = new NetworkCredential("", "appKey") };
 
var client = new HttpClient(handler);

But then I got a 401 (Unauthorized) error back. After some mail conversations with the always helpful Mobile Services team we consider that the problem probably was that the call does not try to authenticate with basic authentication. When I tried the code below instead of the code above it worked.

var client = new HttpClient();
                client.DefaultRequestHeaders.Authorization = 
                    new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.UTF8.GetBytes(String.Format("{0}:{1}", "", "appKey"))));

Solution: Web role deploy problem with Azure SDK 2.2

When I updated my Windows Azure SDK to 2.2 I got a problem when deploying the package of my MVC 4 web site from Visual Studio to a web role in Windows Azure. The message I got was that a exception has occored under recycling and that I should check for unhandled exceptions or configurations errors.

Finnaly I found the solution, setting Copy local to true on the reference to the assembly for WindowsAzure.ServiceRuntime made it work again.