NotifyMe – part II

In previous post which is available here I told you how to use built in facebook authorization using Microsoft Azure App Service. Today I want to show you how to get a list of facebook friends in our application using Graph API Explorer tool.

Let’s do this!

Our development finished at view presented below:

Its XAML code:

<views:BasePage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:TypeArguments="ViewModels:FriendsViewModel" xmlns:controls="clr-namespace:ImageCircle.Forms.Plugin.Abstractions;assembly=ImageCircle.Forms.Plugin.Abstractions" xmlns:ViewModels="clr-namespace:NotifyMe.App.ViewModel" xmlns:views="clr-namespace:NotifyMe.App.Views;assembly=NotifyMe.App" x:Class="NotifyMe.App.Views.FriendsPage" Title="Friend selection" Style="{StaticResource contentPageStyle}">
  <ContentPage.Content>
  <Grid>
    <Grid.RowDefinitions>
      <RowDefinition Height="1*" />
      <RowDefinition Height="3*" />
    </Grid.RowDefinitions>
    <Button Text="Show friends" Style="{StaticResource buttonStyle}" Command="{Binding GetFriendsCommand}" Grid.Row="0"/>
    <ListView x:Name="ListView" ItemsSource="{Binding Friends}" IsGroupingEnabled="false" HasUnevenRows ="false" SeparatorColor="#FFBF65" SeparatorVisibility="Default" SelectedItem="{Binding SelectedFriend}" RowHeight="100" CachingStrategy="RetainElement" Grid.Row="1">
      <ListView.ItemTemplate>
        <DataTemplate>
          <ViewCell>
            <StackLayout BackgroundColor="#486669">
              <StackLayout Orientation="Horizontal" Margin="16,0,0,0" VerticalOptions="CenterAndExpand">
                <controls:CircleImage Source="{Binding ImageUrl}" Aspect="AspectFit" WidthRequest="55" HeightRequest="55" />
                <StackLayout Orientation="Vertical" VerticalOptions="CenterAndExpand" Margin="16,0,0,0">
                  <Label Text="{Binding Name}" TextColor="#FFBF65" FontSize="16" />
                </StackLayout>
              </StackLayout>
            </StackLayout>
          </ViewCell>
        </DataTemplate>
      </ListView.ItemTemplate>
    </ListView>
    <StackLayout IsVisible="{Binding IsBusy}" HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand" Grid.Row="1">
      <ActivityIndicator IsRunning="{Binding IsBusy}" Color="#FFBF65" />
      <Label Text="Loading..." TextColor="#FFBF65"/>
    </StackLayout>
  </Grid>
  </ContentPage.Content>
</views:BasePage>

As you can see there is one of the available layouts in Xamarin.Forms – Grid. It has two rows and first of them takes 1/4 of screen. To put elements inside we have to use Attached Property.

Grid.Row="0"

In the second row is ListView control which containts facebook friends. That list can be overlapped by ActivityIndicator control. It is usually used to show application users that our application is busy.

    <StackLayout IsVisible="{Binding IsBusy}" HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand" Grid.Row="1">
      <ActivityIndicator IsRunning="{Binding IsBusy}" Color="#FFBF65" />
      <Label Text="Loading..." TextColor="#FFBF65"/>
    </StackLayout>

Bind button action – click to following command in ViewModel class:
IsBusy property comes from BaseViewModel class.

        public ICommand GetFriendsCommand
        {
            get
            {
                return getFriendsCommand ?? (getFriendsCommand = new RelayCommand(async () =>
                {
                    IsBusy = true;
                    Friends = new ObservableCollection<FacebookFriend>(await FacebookService.GetFacebookFriends());
                    IsBusy = false;
                }));
            }
        }

Now, we have to use Graph API Explorer to prepare classes for JSON deserialization.

After login it allows you to create queries in console.

We can get information about friends using https://graph.facebook.com/v2.8/me/friends?fields=id,name,picture addres. It returns following structure:

{
  "data": [
    {
      "id": "myId",
      "name": "Bartosz Radlak",
      "picture": {
        "data": {
          "is_silhouette": false,
          "url": "myPictureUrl"
        }
      }
    }
  ],
  "paging": {
    "cursors": {
      "before": "someCursor",
      "after": "someCursor"
    }
  },
  "summary": {
    "total_count": 2
  }
}

Notice that it will be necessary to implement pagination. At this moment we can skip it. According to structure above we can create following classes:

    public class FriendsResponse
    {
        [JsonProperty("data")]
        public List<FacebookFriend> Friends { get; set; }

        [JsonProperty("summary")]
        public Summary Summary { get; set; }
    }

    public class FacebookFriend
    {
        [JsonProperty("id")]
        public string Id { get; set; }

        [JsonProperty("picture")]
        public PictureData PictureData { get; set; }

        [JsonProperty("name")]
        public string Name { get; set; }

        [JsonIgnore]
        public string ImageUrl
        {
            get
            {
                return PictureData.Picture.Url;
            }
        }
    }

    public class PictureData
    {
        [JsonProperty("data")]
        public FacebookPicture Picture { get; set; }
    }

    public class FacebookPicture
    {
        [JsonProperty("url")]
        public string Url { get; set; }
    }

Now it is a good time for question – “Ok, but what about access token?”

To handle it Microsoft Azure and App Service Authentication has App Service Token Storage mechanism. It is simple OAuth tokens repository for application user.

After successful configuration of App Service Authentication, our App Service got new endpoint.
By calling /.auth/me with GET request we can get every access token.

var data = await MobileServiceClientWrapper.Instance.Client.InvokeApiAsync("/.auth/me");

Response structure:

[{
  "provider_name":"<provider>",
  "user_id": "<user_id>",
  "user_claims":[{"typ": "<claim-type>","val": "<claim-value>"}, ...],
  "access_token":"<access_token>",
  "access_token_secret":"<access_token_secret>",
  "authentication_token":"<authentication_token>",
  "expires_on":"<iso8601_datetime>",
  "id_token":"<id_token>",
  "refresh_token":"<refresh_token>"
}]

According to the strucure we can create classes again:

    public class ProvidersResponse
    {
        [JsonProperty("access_token")]
        public string AccessToken { get; set; }

        [JsonProperty("expires_on")]
        public DateTime ExpiresOn { get; set; }

        [JsonProperty("provider_name")]
        public string ProviderName { get; set; }

        [JsonProperty("user_claims")]
        public List<UserClaim> UserClaims { get; set; }

        [JsonProperty("user_id")]
        public string UserId { get; set; }
    }

    public class UserClaim
    {
        [JsonProperty("typ")]
        public string Type { get; set; }

        [JsonProperty("val")]
        public string Value { get; set; }
    }

Now, we can create FacebookService component which will be responsible for executing http request and deserialization.

 public class FacebookService : IFacebookService
    {
        public async Task<IEnumerable<FacebookFriend>> GetFacebookFriends()
        {
            var providers = await Initialize();
            string path = @"https://graph.facebook.com/v2.8/me/friends?fields=id,name,picture&access_token=" + providers[0].AccessToken;
            using (var client = new HttpClient())
            {
                var request = new HttpRequestMessage()
                {
                    RequestUri = new Uri(path),
                    Method = HttpMethod.Get,
                };
                var data = await client.SendAsync(request);

                var response = await data.Content.ReadAsStringAsync();
                var deserialized = JsonConvert.DeserializeObject<FriendsResponse>(response);

                return deserialized.Friends;
            }
        }

        private async Task<ProvidersResponse[]> Initialize()
        {
            var data = await MobileServiceClientWrapper.Instance.Client.InvokeApiAsync("/.auth/me");
            var datastr = data.ToString();
            var response = JsonConvert.DeserializeObject<ProvidersResponse[]>(datastr);
            return response;
        }
    }

The final result:

In next project post I am going to show you how to send a first notification message to selected friend by using Notification Hub and Google Cloud Messaging

Leave a Reply

Your email address will not be published. Required fields are marked *