Using MessageDialog to show a message after Exception occurs

WinRT comes with a useful class called MessageDialog which can be used to show a simple modal dialog. However, per Microsoft’s design guideline, we should try to avoid using it unless we use it for urgent information or something that we really want our user to see it.

MessageDialog has a ShowAsync method which is used to show dialog asynchronously. We can put await operation before ShowAsync statement to make sure our code after it won’t be executed until our user close the dialog.

Here is how we can use it:

async void showDialog_Click(object sender, RoutedEventArgs e)
{
    var dlg = new MessageDialog("Modal Dialog");
    await dlg.ShowAsync();            

    // The code below won't be executed until our user close the dialog
    mainGrid.Background = new SolidColorBrush(Colors.Blue);
}

If we didn’t put await in the dlg.ShowAsync() line, the Grid’s background would change before user close the dialog.

One useful scenario that I think we could use MessageDialog is to show some message when there is an Exception in our app. However, await can’t be used in catch or finally block, so we can’t just do something like this.

catch (Exception ex)
{
    await new MessageDialog(exception.Message).ShowAsync();
}

Or we will get this compilation error, “Cannot await in the body of a catch clause”:

clip_image002

To resolve it, we can just grab the exception in catch block and use it with the await statement outside the catch block like this:

Exception exception;
try
{
    //... do something
}
catch (Exception ex)
{
    exception = ex;    
}

if(exception != null)
    await new MessageDialog(exception.Message).ShowAsync();

mainGrid.Background = new SolidColorBrush(Colors.Red);

Hope this helps someone! Enjoy coding.

Connect your Windows Store App to LinkedIn (via OAuth 2.0) using WebAuthenticationBroker and PasswordVault

I have written a sample using OAuth 1.0a to connect to LinkedIn service. However, for many developers (me too), OAuth 1.0a can be tricky and very complicate to get right with all the details of the protocol.

Like OAuth 1.0a, the OAuth 2.0 provides ways for applications to share their private resources with other applications, but it has been designed with focus on client developer simplicity. You don’t need to worry about implementing request signing mechanism as OAuth 2.0 utilizes and requires SSL for that task. If you want to know more about the differences between OAuth 2.0 and OAuth 1.0a, you can go to this link, or this one on StackOverflow.

Last month, LinkedIn starts supporting OAuth 2.0, so I want to write a small sample showing how easy we can create a Windows Store App (aka Metro or Moderm) to connect to LinkedIn now.

In this post, I will use WebAuthenticationBroker which makes everything much easier as well. In the OAuth 1.0a LinkedIn post, I didn’t worry about storing and reusing an access token, but this time, I will show you how we can securely keep the token in PasswordVault.

Because LinkedIn already provide great documentation about how to use their service with OAuth 2.0, I will focus on my code only.

1. We will start by getting an authorize code by going to LinkedIn, and call WebAuthenticationBroker.AuthenticateAsync and get the WebAuthenticationResult back. During this process, a user has to sign into LinkedIn. If everything works as expected, we will get the authorization code from the WebAuthenticationResult and use it in the next step.

private async Task getAuthorizeCode()
{
    var url = "https://www.linkedin.com/uas/oauth2/authorization?response_type=code"
                                    + "&client_id=" + _consumerKey
                                    + "&scope=" + Uri.EscapeDataString(_scope)
                                    + "&state=STATE"
                                    + "&redirect_uri=" + Uri.EscapeDataString(_callbackUrl);
    log(url);
    var startUri = new Uri(url);
    var endUri = new Uri(_callbackUrl);

    WebAuthenticationResult war = await WebAuthenticationBroker.AuthenticateAsync(
                                                WebAuthenticationOptions.None,
                                                startUri,
                                                endUri);
    switch (war.ResponseStatus)
    {
        case WebAuthenticationStatus.Success:
            {
                // grab access_token and oauth_verifier
                var response = war.ResponseData;
                IDictionary<string, string> keyDictionary = new Dictionary<string, string>();
                var qSplit = response.Split('?');
                foreach (var kvp in qSplit[qSplit.Length - 1].Split('&'))
                {
                    var kvpSplit = kvp.Split('=');
                    if (kvpSplit.Length == 2)
                    {
                        keyDictionary.Add(kvpSplit[0], kvpSplit[1]);
                    }
                }

                _authorizationCode = keyDictionary["code"];
                break;
            }
        case WebAuthenticationStatus.UserCancel:
            {
                log("HTTP Error returned by AuthenticateAsync() : " + war.ResponseErrorDetail.ToString());
                break;
            }
        default:
        case WebAuthenticationStatus.ErrorHttp:
            log("Error returned by AuthenticateAsync() : " + war.ResponseStatus.ToString());
            break;
    }
}

Please notice that we also pass scope which will determine what our app can access. Our user will also warns our user in the login page as well. Please go to LinkedIn document for more information.

/// <summary>
/// In this sample, we want to see the full profile and connections
/// http://developer.linkedin.com/documents/authentication#granting
/// </summary>
private string _scope = "r_fullprofile r_network";

image

2. You would notice that with the magic of WebAuthenticationBroker, our user doesn’t need to worry about anything. After we get the authorization code, we will try to get an access token by sending the authorization code with our secret key as well.

private async Task getAccessToken()
{
    var url = "https://www.linkedin.com/uas/oauth2/accessToken?grant_type=authorization_code"
        + "&code=" + _authorizationCode
        + "&redirect_uri=" + Uri.EscapeDataString(_callbackUrl)
        + "&client_id=" + _consumerKey
        + "&client_secret=" + _consumerSecretKey;

    using (var httpClient = new HttpClient())
    {
        httpClient.MaxResponseContentBufferSize = int.MaxValue;
        httpClient.DefaultRequestHeaders.ExpectContinue = false;

        var httpRequestMessage = new HttpRequestMessage
        {
            Method = HttpMethod.Post,
            RequestUri = new Uri(url)
        };

        var response = await httpClient.SendAsync(httpRequestMessage);
        var jsonString = await response.Content.ReadAsStringAsync();

        var json = JsonObject.Parse(jsonString);
        _accessToken = json.GetNamedString("access_token");
        log("Getting New Access Token");
    }
}

3. That’s it. We can now access LinkedIn API. By default, LinkedIn returns XML, we can get JSON instead by adding the header, “x-li-format”, with “json” value.

async void sendHttpRequestButton_Click(object sender, RoutedEventArgs e)
{
    var apiUrl = linkedInApiUrl.Text;
    var url = apiUrl + "?oauth2_access_token=" + _accessToken;

    if (!string.IsNullOrEmpty(apiQuery.Text))
    {
        url += "&" + apiQuery.Text;
    }

    using (var httpClient = new HttpClient())
    {
        httpClient.MaxResponseContentBufferSize = int.MaxValue;
        httpClient.DefaultRequestHeaders.ExpectContinue = false;
        // By default, LinkedIn returns XML, we can get JSON instead by adding the header below
        httpClient.DefaultRequestHeaders.Add("x-li-format", "json");

        var httpRequestMessage = new HttpRequestMessage
        {
            Method = HttpMethod.Get,
            RequestUri = new Uri(url)
        };

        var response = await httpClient.SendAsync(httpRequestMessage);

        if (response.IsSuccessStatusCode)
        {
            var jsonString = await response.Content.ReadAsStringAsync();
            log(jsonString);
        }
        else
        {
            log(response.ToString());
        }
    }
}

In step #2, once we get the access token, we will keep it in PasswordVault. Now we can close our app and re-open it. The access token should be retrieved from PasswordVault, and our user don’t need to sign into LinkedIn again.

/// <summary>
/// A credential locker to securely store our Access Token 
/// http://msdn.microsoft.com/en-us/library/windows/apps/br227089.aspx
/// </summary>
private PasswordVault _vault;
private const string RESOURCE_NAME = "LinkedInAccessToken";
private const string USER = "user";

// we use a property instead of normal field because of how PasswordVault works
private string _accessToken
{
    get
    {
        try
        {
            var creds = _vault.FindAllByResource(RESOURCE_NAME).FirstOrDefault();
            if (creds != null)
            {
                return _vault.Retrieve(RESOURCE_NAME, USER).Password;
            }
            else
            {
                return null;
            }
        }
        catch (Exception)
        {
            // if no access token found, the FindAllByResource method throws System.Exception: Element not found
            return null;
        }
    }
    set
    {
        _vault.Add(new PasswordCredential(RESOURCE_NAME, USER, value));
    }
}

Let’s run the app and see some nice looking screenshots 😉

After our user signs into LinkedIn and we get the access token, we are now ready to send some request to LinkedIn API.image

Here we access Profile API with some field selectors.

image

Here we access Connections API with some field selectors as well as count parameters.

image

I hope this helps someone. You can download the full source code from here.

Enjoy coding!

Playing with CalendarControl from Mindscape: Part 1

Since WinRT has been introduced in //build/ 2011 with the Windows 8 Developer Preview, many companies such as Telerik, Syncfusion, and Infragistics that have been providing .NET controls and development tools jump on the bandwagon and start providing controls for WinRT.

I have written about Chart controls from Telerik in the previous posts. However, I also look around to see how other companies have been doing. And I see one interesting control which is a calendar control from Mindscape.

The CalendarControl can be used as a date picker or to display data for individual days or months. You can visualize the days of each month using a “Month view” or months in a year using a “Year view.”

image

image

Today, I will just show you simplest thing you can do with the CalendarControl. I will create an app that allows a user to tap a date and set the app background to Bing image of the day of the selected date.

Let’s start!

  1. First, you have to download the MetroElements Trial version. (Note: As far as I know the trial version occasionally shows a message dialog which tells you that you are using the trial version :-). I think it is also built in debug mode, so you can’t just submit your app with the trial version to the store.)
  2. Next step, we install the controls by running the msi file.image
  3. After that, we can start Visual Studio and create a blank Windows Store app project. image
  4. Next, we add Metro Elements reference to the project. image
  5. We can add XAML code directly or just drag the CalendarControl from the Toolbox, and let Visual Studio handle the namespace adding for us.image

Here is the XAML code:

<Page xmlns:MetroElements="using:Mindscape.MetroElements" 
    x:Class="MindscapeCalendar.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MindscapeCalendar"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">
    <Grid x:Name="mainGrid" Background="Crimson">
        <MetroElements:CalendarControl x:Name="calendar"/>
    </Grid>
</Page>

This should be all for the XAML side. Let’s look at C# code-behind.

public sealed partial class MainPage : Page
{
    string bingUrlPrefix = "http://www.bing.com/HPImageArchive.aspx?format=xml&n=1&mkt=en-US&idx=";

    public MainPage()
    {
        this.InitializeComponent();        
    }
    
    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        calendar.SelectedDateChanged += calendar_SelectedDateChanged;
    }

    async void calendar_SelectedDateChanged(object sender, EventArgs e)
    {
        var calendarControl = sender as CalendarControl;
        var selectedDate = calendar.SelectedDate;

        var dateDiff = DateTime.Now - selectedDate;
        var day = dateDiff.Days;
        
        // we can't get a future photo or a photo older than 11 days
        if (day >= 0 && day <= 11)
        {
            using (var client = new HttpClient())
            {
                var fullBingUrl = string.Format("{0}{1}", bingUrlPrefix, day);
                var xmlString = await client.GetStringAsync(new Uri(fullBingUrl));

                var doc = XDocument.Parse(xmlString);

                var imageUrlElement = doc
                    .Descendants("image")
                    .Descendants("urlBase")
                    .FirstOrDefault();

                if (imageUrlElement != null)
                {
                    var imageUrl = imageUrlElement.Value;
                    var medResolutionUrl = imageUrl + "_1366x768.jpg"; 
                    var imageBrush = new ImageBrush();
                    imageBrush.ImageSource = new BitmapImage(new Uri("http://www.bing.com/" + medResolutionUrl));
                    mainGrid.Background = imageBrush;
                }
            }
        }
    }
}

The code is pretty straightforward here. We create an event handler, calendar_SelectedDateChanged, which will handle the CalendarControl.SelectedDateChanged event.

In the event handler, we get the selected date and make sure we can get bing image from that day (Note: we can’t get a future photo or photo older than 11 days from the URL that we used in the code here).

Basically, to get a bing image, we have to get XML which contains the file name (in <url> tag) or prefix (in <urlBase> tag). The app gets 1366×768 version of the photo by using “1366×768.jpg” suffix. After we get the image, we create an ImageBrush and set it as our main grid’s background.

Let’s see how it works in action:

This is just the simplest way to use the CalendarControl. You can actually customize your calendar and display any kind of data you want. In the next post, I will show you how you can customize the CalendarControl to look something similar to this.image

Enjoy coding!

Open Win + X (Advanced System Menu) without using keyboard or mouse on Windows 8

Windows 8 comes with a new keyboard shortcut, Windows + X, that will open the advanced system menu for power users.

image

As I said in the last post, I don’t want to always pulling up keyboard or mouse, so that I can open the menu.

I can easily do that by activating the on-screen keyboard.

No, no, not this one.

image

But this one, which you can just tap, Windows Key and X to open the advanced system menu.

image

If you don’t like the on-screen keyboard above, you could also go to PC settings –> General, and turn the “standard keyboard layout” on which will allow you to change the normal on-screen keyboard type to the standard one.

image

image

Now, you can press any shortcut keys that you want. Hope this helps.

Capture a screenshot on Windows 8/RT tablet without a keyboard

I have been using a Windows 8 and a Surface RT tablets for a while. Although I do have a small Microsoft Wedge Keyboard and a touch-cover for the Surface RT, many times I just want to capture a screenshot without using a keyboard (and press Windows + PrtScn).

For a Surface RT, you can press and hold Windows Key button and then press the volume down button to capture a screenshot.

But you can also use the snipping tool to do that as well. We start by using the search charm and search for “Snipping Tool.”

image

Once you have a “Snipping Tool”, you can capture the full-screen snip or you can choose other options.

image

Hope this helps!