How to shorten a link with Bitly and share it in a Windows Store app

I am working on a Windows Store app where one of the features is to share shortened links. This is a brief description on how I solved it.

Bitly

You can find a long list of different link shorteners at Programmable Web. I will use Bitly mostly because I used it before with success. The signup process and app registration is easy. Here is a blog post describing it in detail: Bitly API: Authentication.

Windows Store App Setup

XAML

We will not spend any time with the UX in this example. Simply put the following XAML in the MainPage.xaml:

<Page
    x:Class="BitlyShareTest.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d" Unloaded="Page_Unloaded">

    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
        <TextBox x:Name="UrlTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Center" Width="300" Text="https://codeblog.silfversparre.com"/>
        <Button Content="Share" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,100,0,0" Tapped="ShrinkButton_Tapped"/>
    </Grid>
</Page>

Code

This example will not use any MVVM architecture whatsoever, all code is placed in the code-behind file MainPage.xaml.cs.
Start by adding an event handler for the DataRequested event.

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    var dataTransferManager = DataTransferManager.GetForCurrentView();
    dataTransferManager.DataRequested += ShareLinkHandler;
}

Then handle the DataRequested event by editing the DataRequestedEventArgs DataPackage object. This would be all code needed if we were to share something we already have. See example: How to share a link (Windows Store apps using C#/VB/C++ and XAML).

But we will make an asynchronous call to Bitly before we have the link to share. Therefore we set a Dataprovider in the last line to handle the actual Bitly call. You can find more info here: How to make asynchronous calls in your DataRequested handler (Windows Store apps using C#/VB/C++ and XAML).

private void ShareLinkHandler(DataTransferManager sender, DataRequestedEventArgs args)
{
    var requestData = args.Request.Data;
    requestData.Properties.Title = "Epic demo";
    requestData.Properties.Description = "A demo...";
    requestData.SetDataProvider(StandardDataFormats.Text, OnDeferredLinkRequestedHandler);
}

UrlEncode the input we are about to send to Bitly. You find the method in the namespace System.Net.WebUtility for WinRT.

We need a DataRequestDeferral object when doing asynchronous methods after the DataRequest event. To get a deferral object, we call GetDeferral().

Then we use Bitly to shorten the input link and add it as content to the DataPackage. Please use your own Bitly credentials in place of “PutYourUserNameHere” and “PutYourOwnApiKeyHere”.

Remember to call deferral.Complete() in all code paths.

private async void OnDeferredLinkRequestedHandler(DataProviderRequest request)
{
    var encodedUrl = WebUtility.UrlEncode(_inputUrl);
    DataProviderDeferral deferral = request.GetDeferral();

    try
    {
        string uri;
        try
        {
            var client = new HttpClient();
            string json = await client.GetStringAsync("https://api-ssl.bitly.com/v3/shorten?" +
                                                        "login=PutYourUserNameHere" +
                                                        "&amp;format=json&amp;apiKey=PutYourOwnApiKeyHere&amp;longUrl=" +
                                                        encodedUrl + "&amp;format=json");

            JsonObject jsonObject = JsonObject.Parse(json);
            uri = jsonObject["data"].GetObject().GetNamedString("url");
        }
        catch (Exception)
        {
            uri = _inputUrl;
        }
        request.SetData(string.Format("Check out my shrinked link: {0}",uri));
    }
    finally
    {
        deferral.Complete();
    }
}

I ran into an issue with this code when navigating from the page and back again because of the event registration: “WinRT information: An event handler has already been registered”. I solved it by removing the event in the PageUnload event:

private void Page_Unloaded(object sender, RoutedEventArgs e)
{
    DataTransferManager manager = DataTransferManager.GetForCurrentView();
    manager.DataRequested -= ShareLinkHandler;
}

Finally handle the button tap to programmatically initiate the user interface for sharing content with an another app:

private void ShrinkButton_Tapped(object sender, TappedRoutedEventArgs e)
{
    _inputUrl = UrlTextBox.Text;
    DataTransferManager.ShowShareUI();
}

Final Code

Here is the complete code-behind:

 using System;
using System.Net;
using System.Net.Http;
using Windows.ApplicationModel.DataTransfer;
using Windows.Data.Json;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Navigation;

namespace BitlyShareTest
{
    public sealed partial class MainPage
    {
        private string _inputUrl;

        public MainPage()
        {
            InitializeComponent();
        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            var dataTransferManager = DataTransferManager.GetForCurrentView();
            dataTransferManager.DataRequested += ShareLinkHandler;
        }

        private void ShareLinkHandler(DataTransferManager sender, DataRequestedEventArgs args)
        {
            var requestData = args.Request.Data;
            requestData.Properties.Title = "Epic demo";
            requestData.Properties.Description = "A demo...";
            requestData.SetDataProvider(StandardDataFormats.Text, OnDeferredLinkRequestedHandler);
        }

        private async void OnDeferredLinkRequestedHandler(DataProviderRequest request)
        {
            var encodedUrl = WebUtility.UrlEncode(_inputUrl);
            DataProviderDeferral deferral = request.GetDeferral();

            try
            {
                string uri;
                try
                {
                    var client = new HttpClient();
                    string json = await client.GetStringAsync("https://api-ssl.bitly.com/v3/shorten?" +
                                                              "login=PutYourUserNameHere" +
                                                              "&amp;format=json&amp;apiKey=PutYourOwnApiKeyHere&amp;longUrl=" +
                                                              encodedUrl + "&amp;format=json");

                    JsonObject jsonObject = JsonObject.Parse(json);
                    uri = jsonObject["data"].GetObject().GetNamedString("url");
                }
                catch (Exception)
                {
                    uri = _inputUrl;
                }
                request.SetData(string.Format("Check out my shrinked link: {0}",uri));
            }
            finally
            {
                deferral.Complete();
            }
        }

        private void ShrinkButton_Tapped(object sender, TappedRoutedEventArgs e)
        {
            _inputUrl = UrlTextBox.Text;
            DataTransferManager.ShowShareUI();
        }

        private void Page_Unloaded(object sender, RoutedEventArgs e)
        {
            DataTransferManager manager = DataTransferManager.GetForCurrentView();
            manager.DataRequested -= ShareLinkHandler;
        }
    }
}

Trackback URL: https://codeblog.silfversparre.com/2013/07/how-to-shorten-a-link-with-bitly-and-share-it-in-a-windows-store-app/trackback/