[French] Configuring Visual Studio 2015 to develop Xamarin.iOS applications

As Microsoft MVPs, we have opportunities to collaborate with Microsoft teams and we have access to a lot of resources and tools which are not available to the general audience.

Today, I’m proud to announce that my first screencast (and certainly not the last) was published on Channel 9, the official Microsoft video portal for developers.

If you speak French (yes it’s my native language) and are interested by Xamarin development, you can discover how to configure your Visual Studio 2015 development environment to develop iOS applications.

Broadcast messages over the network from your Xamarin application

Since few days, I think and look for the best technical solutions to create a new tool to include in my mobile application development toolkit.

This tool requires, when a mobile application (let’s call it client) starts/stops on a device in the same network as my development machine, to send information over the network, to inform other applications (let’s call them listeners) that a new client is started and available on the network.

The “classic” way to achieve this goal is to create a webservice, an call it when the application starts/stops. It’s easy to do but in that case, it’s necessary to store the data sent over the network (e.g. a device identifier), and the listeners need to poll the webservice, to detect new clients.

It’s a good solution in some cases, but not what I want for my tool. I prefer to be notified in real-time when a new client is started/stopped and I don’t want to create a database to store information about clients (in-memory storage is enough).

Then I remembered that it’s possible to broadcast messages over the network through UDP (User Datagram Protocol).

Let’s take a look to this solution to check if it works with Xamarin.

UDP protocol / UdpClient class

UDP is a transport layer protocol defined for use with the IP network layer protocol. This is an unreliable service that provides no guarantees for delivery, packets order and no protection as TCP does (e.g. send an acknowledgment after that a packet was sent and received over the network, otherwise retry to send it). The simplicity of UDP reduces the overhead from using the protocol and the services may be adequate in many cases.

To use UDP from a .NET / Xamarin application, wether to create clients or listeners, the .NET framework offers an UdpClient class which covers all the needs (send, receive, broadcast, multicast, etc…).

Enough of theory, let’s go to the code 🙂

Create a simple UDP listener in C#

To test that we can use UDP from a Xamarin application, we first need to create a listener that will receive the messages sent by the application. To do this, I created on a PC, a console application with the following code :

using System;
using System.Net.Sockets;
using System.Text;

namespace UdpListenerDemo
{
  class MainClass
  {
    public static void Main(string[] args)
    {
      var listener = new UdpListener();
      listener.StartListening();
      Console.ReadLine();
    }
  }

  class UdpListener
  {
    private readonly UdpClient _udpClient = new UdpClient(15000);

    public async void StartListening()
    {
      while(true)
      {
        var result = await _udpClient.ReceiveAsync();
        var message = Encoding.ASCII.GetString(result.Buffer);
        Console.WriteLine(message);
      }
    }
  }
}

This console application will listen for all messages sent over the network through UDP, on port number 15000. When a message is received, it’s printed in the console.

Send messages over the network from Xamarin.iOS

The next part is to create a Xamarin application (a client) that will send messages over the network. For this part, I used the “Single View App” template and put a button on the main screen. Each time the user will tap the button, the application will send a message over the network.

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using UIKit;

namespace UdpClientDemo
{
  public partial class ViewController : UIViewController
  {
    public ViewController(IntPtr handle) : base(handle)
    {
    }

    public override void ViewDidLoad()
    {
      base.ViewDidLoad();
    }

    public override void DidReceiveMemoryWarning()
    {
      base.DidReceiveMemoryWarning();
    }
 
    async partial void SendMessage(UIButton sender)
    {
      using(var client = new UdpClient())
      {
        client.EnableBroadcast = true;
        var endpoint = new IPEndPoint(IPAddress.Broadcast, 15000);
        var message = Encoding.ASCII.GetBytes("Hello World - " + DateTime.Now.ToString());
        await client.SendAsync(message, message.Length, endpoint);
        client.Close();
      }
    }
  }
}

The most important part of the code above, is the declaration of the endpoint. As you can see, we use the same port number (15000) that is declared in the listener, and we use the broadcast address instead of a specific IP address (because we don’t want to target a particular client).

For this sample, I used a Xamarin.iOS application but it also works with Xamarin.Android.

Use the listener and the client

Now that we have all the necessary parts, we can execute our Xamarin application (the client) to see if it works. As you can see on this screenshot, the interface is pretty simple.

Xamarin - UDP Client

If you tap on the “Send UDP Message” button, and if the listener is not started, nothing will happen. The message will be sent over the network but nobody will receive it.

Now if we execute the listener (our console application) then tap the button on the client (our Xamarin application), the message is sent over the network, then received and printed on the console as you can see below.

Xamarin - UDP Listener

Limitations

As we saw in this article, the solution based on UDP to broadcast messages over the network, can be used in Xamarin applications and it’s very easy to implement. But there are some limitations to understand if you use this solution.

The most important is that broadcast messages, generally don’t go through routers. It means that this solution only works if the listeners and the clients are on the same network segment.

Another limitation concerns the UDP protocol. As mentioned earlier, UDP is not reliable and it’s not guaranteed that a message will be delivered. It’s not guaranteed too, that messages are delivered in the same order where they were sent. It also may happen that a message is received many times. For all these cases, your application is responsible to react as you need.

But in my case, I just need to send a message when an application starts/stops. Because my need is very basic, this solution seems to be viable.

Signing your Xamarin.Android application package during the development phase

When you create an application using Xamarin.Android (or even if you use other tools such as Android Studio), it’s necessary to sign the application package (APK) to publish your application on the Google Play Store.

If you don’t know how how to proceed, Xamarin has published a step-by-step tutorial which explains how to achieve this goal.

This article is very useful when your application is finished, because it explains how to use the built-in tools to archive, sign and distribute your application.

But when you’re still in the development phase (e.g. to implement and test push notifications), it’s not convenient to use this workflow.

Fortunately, a more simple way to reach the same goal exist and is very easy to implement. Let’s take a look to this process.

Create a new keystore/certificate

The first step to sign an application is to generate a keystore, the container for the certificate associated to your application.

There are different ways to generate a keystore (e.g. command-line tools), but my preferred way is to use the GUI available in Xamarin Studio. To access this screen, go to Xamarin Studio > Preferences > Android Signing Keys.

Xamarin - Android Signing Keys

This screen lists all the keystores that you created on your computer. You are also able to import an existing keystore, or generate a new one by clicking to Create a new key.

When you create a new new key, you just have to complete some information on who you are (firstname, lastname, organisation…) and the security of your certificate (alias, password and validity).

Xamarin - Android Create Keystore

Once you created the new key, it’s stored in the folder ~/Library/Developer/Xamarin/Keystore/Your-Alias (if you’re using a Mac).

Sign your package with the keystore

The second (and last) step to sign your package is to associate the keystore to your project.

Once your project is open in Xamarin Studio, go to Project Options > Android Package Signing.

Check the box labeled “Sign the .APK file using the following keystore details” and fill the details with information used when you created the keystore.

If you have used the GUI to create the keystore, you probably noticed that there’s only one password value while there are 2 values (keystore password and alias password) in this screen. The GUI use the same value for both fields, but it’s possible to use different values if you use command-line tools.

Xamarin - Android Package Signing

Please note that it’s possible to use different keystores for debug and release modes. You can switch between these modes using the configuration list on the top of the dialog box.

Performing a search request with SharePoint REST API throws a Microsoft.SharePoint.Client.UnknownError

Most of Office 365 REST APIs use the OData v4.0 protocol for exchanging and formatting data between the client and the server.

When you develop an application that uses those APIs, you need to add some HTTP headers in all your requests to let the server know that you want to use this protocol version and to specify the desired verbosity of returned metadata as you can see below :

Accept: application/json;odata.metadata=minimal
OData-Version: 4.0

But if you use these HTTP headers with the SharePoint API to perform a search by calling…

POST https://tenant.sharepoint.com/_api/Search/PostQuery

… then you will receive the following error message :

{
  "error": {
    "code":"-1,
    Microsoft.SharePoint.Client.UnknownError",
    "message":"Unknown Error"
  }
}

You could be surprised because if you try to get information about a site collection by calling…

https://tenant.sharepoint.com/_api/Site

… with the same HTTP headers, it works without any issues.

It can look weird but in fact it’s normal.

If you ever call the following URL to retrieve the OData manifest for the SharePoint API…

https://tenant.sharepoint.com/_api/$metadata

… you can see that the API only supports OData v3.0 (cf. MaxDataServiceVersion).

<edmx:Edmx Version="1.0">
  <edmx:DataServices m:DataServiceVersion="3.0" m:MaxDataServiceVersion="3.0">
    ...
  </edmx:DataServices>
</edmx:Edmx>

So even if a lot of features in the SharePoint REST API are working with the OData v4.0 headers, you should better use the OData v3.0 headers such as below to avoid such issues :

Accept: application/json;odata.metadata=minimal
DataServiceVersion: 3.0

Microsoft Graph / OneDrive : The resource could not be found

Microsoft Graph gives you access to a large range of features and data (Outlook, Delve, Azure AD…) using its REST API.

Among these features, you are able to retrieve content from the “OneDrive for Business” service associated to your Office 365 account.

To do this, you just have to call the following URL that will return all the items stored in the root folder of your personal document library.

GET https://graph.microsoft.com/v1.0/me/drive/root/children

By calling that URL, the server will return a JSON response such as the following (the response shown here was truncated for brevity) :

{
  value = ({
    @odata.id = "users/31950312-e7dd-44de-bfaa-4d8274e4d6a0/drive/root/children/01ZWNXWXJYRUGTTJRMQZB2L2YE4NQK4CIF",
    createdBy = { ... },
    createdDateTime = "...",
    eTag = "...",
    folder = { ... },
    id = "01ZWNXWXJYRUGTTJRMQZB2L2YE4NQK4CIF",
    lastModifiedBy = { ... },
    lastModifiedDateTime = "...",
    name = "...",
    parentReference = { ... },
    size = 0,
    webUrl = "..."
  },
  {
    @odata.id = "users/31950312-e7dd-44de-bfaa-4d8274e4d6a0/drive/root/children/01ZWNXWXJ3G5EOS6XJRRCJ54PQZQAJIM3H",
    createdBy = { ... },
    createdDateTime = "...",
    eTag = "...",
    folder = { ... },
    id = "01ZWNXWXJ3G5EOS6XJRRCJ54PQZQAJIM3H",
    lastModifiedBy = { ... },
    lastModifiedDateTime = "...",
    name = "...",
    parentReference = { ... },
    size = 0,
    webUrl = "..."
  })
}

This sample has 2 folders with their respective properties. One of the important parts in the response is the parameter named “@odata.id” which is the URL associated to the object, and used by the API to uniquely identify an item.

In the case of a folder, it could have children (folders and files). If you want to retrieve these children, you have to concatenate “/children” to the unique identifier of the item.

With the first folder of the previous JSON response, it should look like this :

GET https://graph.microsoft.com/v1.0/users/.../drive/root/children/01ZWNXWXJYRUGTTJRMQZB2L2YE4NQK4CIF/children

But if you call that URL, you get the following error message :

The resource could not be found.

This message means that Microsoft Graph is unable to process your request. It’s weird because the URL was generated by the server and returned in the JSON response.

So how can you get to access the children of this item ?

Now that we have retrieved the ID for the item (see the ID value in the JSON response), we are able to build our own URL to retrieve its children.

In Microsoft Graph / OneDrive API, each item is accessible through an URL such as “…/v1.0/users/{user_id}/drive/items/{item_id}”. So if we build our URL by respecting that schema, it works without errors.

In our previous example, the URL to call will be :

GET https://graph.microsoft.com/v1.0/users/.../drive/items/01ZWNXWXJYRUGTTJRMQZB2L2YE4NQK4CIF/children

If you want to play with Microsoft Graph APIs with data stored on your tenant, you can use this site created and hosted by Microsoft : https://graphexplorer2.azurewebsites.net

Set the timezone used for the events in Outlook and Microsoft Graph REST APIs

When you’ve been working for a while like me, you know that when a developer has to work with dates, he faces problems with timezones.

Outlook REST API allows you to get the events for a user by calling the following URL :

GET https://outlook.office365.com/api/v2.0/Me/Events

In the version 2.0 of the API and as you can see in the JSON response below for an event (the response shown here was truncated for brevity), the Start and End items contain two distinct properties for the date and timezone.

By default, all dates and times returned by the server are based on the UTC timezone.

{
  Attendees = (),
  Body = { ... },
  BodyPreview = "...",
  Categories = (),
  ChangeKey = "...",
  CreatedDateTime = "2015-12-02T16:21:57.91403Z";
  End = {
    DateTime = "2012-02-09T19:00:00.0000000",
    TimeZone = "UTC"
  },
  HasAttachments = false,
  Id = "...",
  Importance = "Normal",
  IsAllDay = false,
  IsCancelled = false,
  IsOrganizer = true,
  IsReminderOn = false,
  LastModifiedDateTime = "2015-12-02T16:21:58.7734204Z";
  Location = { ... },
  Organizer = { ... },
  OriginalEndTimeZone = "Pacific Standard Time",
  OriginalStartTimeZone = "Pacific Standard Time",
  Recurrence = { ... },
  ReminderMinutesBeforeStart = 0,
  ResponseRequested = true,
  ResponseStatus = { ... },
  Sensitivity = "Normal",
  SeriesMasterId = <null>,
  ShowAs = "Tentative",
  Start = {
    DateTime = "2012-02-09T18:00:00.0000000",
    TimeZone = "UTC"
  },
  Subject = "...",
  Type = "SeriesMaster"
  WebLink = "...",
  iCalUId = "..."
}

It’s now easier to know what timezone is used for the dates and times. But that’s not all.

If you want the server automatically convert the dates and times of the events into a different timezone, you are able to do so and it’s very easy.

You just have to specify a HTTP header like in the example below to change the timezone. The server will then use this new parameter to return the dates and times in the desired timezone.

Prefer: outlook.timezone="Central Standard Time"

Specifying this HTTP header and calling the previously mentioned URL, you will retrieve a new JSON response like this one :

{
  Attendees = (),
  Body = { ... },
  BodyPreview = "...",
  Categories = (),
  ChangeKey = "...",
  CreatedDateTime = "2015-12-02T16:21:57.91403Z";
  End = {
    DateTime = "2012-02-09T13:00:00.0000000",
    TimeZone = "Central Standard Time"
  },
  HasAttachments = false,
  Id = "...",
  Importance = "Normal",
  IsAllDay = false,
  IsCancelled = false,
  IsOrganizer = true,
  IsReminderOn = false,
  LastModifiedDateTime = "2015-12-02T16:21:58.7734204Z";
  Location = { ... },
  Organizer = { ... },
  OriginalEndTimeZone = "Pacific Standard Time",
  OriginalStartTimeZone = "Pacific Standard Time",
  Recurrence = { ... },
  ReminderMinutesBeforeStart = 0,
  ResponseRequested = true,
  ResponseStatus = { ... },
  Sensitivity = "Normal",
  SeriesMasterId = <null>,
  ShowAs = "Tentative",
  Start = {
    DateTime = "2012-02-09T12:00:00.0000000",
    TimeZone = "Central Standard Time"
  },
  Subject = "...",
  Type = "SeriesMaster"
  WebLink = "...",
  iCalUId = "..."
}

If you want more information about the names of supported timezones, you can find a list on the official documentation on MSDN.

It’s also good to know that even if it’s not mentioned (for now) on the official documentation, this HTTP header also works with Microsoft Graph.

Programmez #191 : Developing C# applications on OSX with Xamarin.Mac

You probably heard about Xamarin for mobile cross-platform development, but do you know that Xamarin also offers a solution to build OSX applications ?

Discover an overview of Xamarin.Mac in my article in the latest issue of Programmez, a magazine available in French-speaking countries (France, Belgium, Switzerland, Luxemburg, Canada…).

Programmez 191

Be careful to case sensitivity in Microsoft Graph REST API

Last week during Connect(); // 2015, Microsoft announced the general availability (GA) of Microsoft Graph (formerly known as Unified API).

In association with the announcement, a brand new website with a full documentation that explains what’s Microsoft Graph and how to use the REST API was launched here : http://graph.microsoft.io/docs

Since few days, I’m working with Microsoft Graph and I found few issues. Today, I want to talk about one of them which is common with a lot of APIs but frustrating when you encounter it.

During my investigations, I was trying to send a mail and by refering the documentation, it’s noted that you just have to send a JSON message like this one…

["message": {
  body = {
    content = "This message was sent with Microsoft Graph",
    contentType = "text"
  },
  importance = "high",
  subject = "Microsoft Graph REST API",
  toRecipients = ({
    emailAddress = {
      address = "john@doe.com",
      name = "John Doe"
    }
  })
},
"saveToSentItems": false]

… to the following URL.

https://graph.microsoft.com/v1.0/me/microsoft.graph.sendMail

Very easy in theory but when I execute the request with these values, I receive the following error message.

One or more parameters of the operation 'SendMail' are missing from the request payload. The missing parameters are: Message.

To understand what’s the problem, I looked at the metadata generated for the REST API (based on OData 4.0) by accessing the following URL.

https://graph.microsoft.com/v1.0/$metadata

In the metadata returned by the server, you can see this.

<Action Name="sendMail" IsBound="true" EntitySetPath="bindingParameter">
<Parameter Name="bindingParameter" Type="microsoft.graph.user" />
<Parameter Name="Message" Type="microsoft.graph.message" Nullable="false" />
<Parameter Name="SaveToSentItems" Type="Edm.Boolean" />
</Action>

As you can see, the parameters used by this method are named “Message” and “SaveToSendItems” (in PascalCase) and not “message” and “saveToSendItems” (in lowerCamelCase) as written in the documentation.

When you pay attention to metadata generated by OData, you will see that some methods, especially those existing in other parts of Office 365 REST APIs (e.g. sendMail is used in Outlook REST API), still use PascalCase for their parameter names.

So if you follow the documentation to implement Microsoft Graph but you receive an error message indicating that a parameter is missing, take a look at metadata generated by OData to validate that the method is not expected to use PascalCase instead of lowerCamelCase for its parameters.

An SSL error has occurred when trying to use the Outlook REST API on iOS 9 or OSX 10.11 (El Capitan)

In a previous article, we talked about an issue when you try to stream an Office 365 Videos from Azure Media Services in your application running on iOS 9.

It seems that Microsoft is actually doing some modifications on the infrastructure of the Office 365 platform, especially around the SSL certificates, because today I’m facing the same error when using the Outlook REST API.

I’m trying to call the following URL which should return the last 10 messages stored in the inbox  of the authenticated user :

https://outlook.office365.com/api/v2.0/Me/MailFolders('Inbox')/Messages

But I get the following error message, which indicates there’s an issue with SSL certificates :

NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802)

Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made."
UserInfo={NSLocalizedDescription=An SSL error has occurred and a secure connection to the server cannot be made., NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFStreamErrorDomainKey=3, NSUnderlyingError=0x7d96cd90 {Error Domain=kCFErrorDomainCFNetwork Code=-1200 "(null)" UserInfo={_kCFStreamPropertySSLClientCertificateState=0, _kCFNetworkCFStreamSSLErrorOriginalValue=-9802, _kCFStreamErrorCodeKey=-9802, _kCFStreamErrorDomainKey=3, kCFStreamPropertySSLPeerTrust=<SecTrustRef: 0x7afb9d50>, kCFStreamPropertySSLPeerCertificates=<CFArray 0x7ae63490 [0xa97098]>{type = immutable, count = 2, values = (
 0 : <cert(0x7afb8570) s: outlook.com i: Microsoft IT SSL SHA1>
 1 : <cert(0x7afb96d0) s: Microsoft IT SSL SHA1 i: Baltimore CyberTrust Root>
)}}}, _kCFStreamErrorCodeKey=-9802, NSErrorFailingURLStringKey=https://outlook.office365.com/api/v2.0/Me/MailFolders('Inbox')/Messages, NSErrorPeerCertificateChainKey=<CFArray 0x7ae63490 [0xa97098]>{type = immutable, count = 2, values = (
 0 : <cert(0x7afb8570) s: outlook.com i: Microsoft IT SSL SHA1>
 1 : <cert(0x7afb96d0) s: Microsoft IT SSL SHA1 i: Baltimore CyberTrust Root>
)}, NSErrorClientCertificateStateKey=0, NSURLErrorFailingURLPeerTrustErrorKey=<SecTrustRef: 0x7afb9d50>, NSErrorFailingURLKey=https://outlook.office365.com/api/v2.0/Me/MailFolders('Inbox')/Messages}

The cause of this error is still the same as explained in our previous article : App Transport Security (ATS).

To solve the issue, you need to add some lines in your Info.plist to configure ATS to ignore the SSL error.

<key>NSAppTransportSecurity</key>
<dict>
  <key>NSExceptionDomains<key>
  <dict>
    <key>outlook.office365.com</key>
    <dict>
      <key>NSExceptionRequiresForwardSecrecy</key>
      <false/>
    </dict>
  </dict>
</dict>

You can also edit this file using the editor in Xcode rather than manually edit the XML file :

Office365 Outlook REST API - App Transport Security

Searching documents across multiple Office 365 groups with REST API

If you work on Office 365, you probably know what are groups, one of the latest features launched by Microsoft on its collaborative platform.

For those who don’t know what’s it, it’s a new way and mostly a simplest way, to create sites that allow users to collaborate with a minimal set of collaborative features such as storing documents, creating conversations, taking notes in a notebook and sharing events on a calendar.

Below you can see an example of a group, especially the document storage.

Office365 - Groups

For now, if you want to find a document in a given group or a set of documents across all groups, there’s no possibility to search what you’re looking for.

Indeed, when you search for documents using the search area available on the top-left (cf. screenshot), you will be redirected to the global search center of your company available in Office 365.

Fortunately, we can use the search engine with REST API to implement that missing feature.

As a reminder (we described it many times in articles on this blog), to submit a search query in Office 365 using REST API, you can send a POST request to the following URL with a well-formatted HTTP body.

https://tenant.sharepoint.com/_api/Search/PostQuery

When you want to retrieve only documents stored in SharePoint libraries, you can filter items based on the ContentClass property which exists for each items (pages, documents, tasks, events…) that were created in your sites.

In the same way, if you want to search only in a particular kind of site (e.g. Office 365 groups in our case), you can filter results based on the SiteTemplate property.

So what looks like the request to send to the REST API ?

{
  request = {
    Querytext = "ContentClass:STS_ListItem_DocumentLibrary AND SiteTemplate:GROUP",
    RowLimit = 100,
    SelectProperties = (
            Title,
            DefaultEncodingURL,
            SiteTitle,
            SPSiteURL
        ),
        StartRow = 0,
        Timeout = 30000,
        TrimDuplicates = True
    }
}

In the request above, we return the first 100 documents (excluding duplicates) stored in all Office 365 groups and we also retrieve some additional information such as the title of the documents (Title), the URL of the file (DefaultEncodingURL), the name of the group where it’s stored (SiteTitle) and the URL of the group (SPSiteURL).

If you want to be more precise on your search (e.g. search for documents that have a title which start with the word “Program“), then you can add new filters to your query such as the example below.

Title:Program* AND ContentClass:STS_ListItem_DocumentLibrary AND SiteTemplate:GROUP

As we have seen in this article, it’s pretty simple to search documents across all Office 365 groups and it’s just up to you to integrate and to use REST API in your different applications (mobile, Office add-ins, WebParts…).