Tuesday, May 15, 2012

How to determine the username of the logged on user in Windows 8 Metro Style apps

There are 2 options available here, depending on what you would like to achieve.

If it's simply to authenticate a user, you would want to use the Windows.Security.Authentication.Web.WebAuthenticationBroker, and one or more OAuth2.0 identity services like Facebook or Windows Live. There are very good samples available on using these. Start with MSDN

If you need to do authorization or log a user in using a web service, you may need to know the logged in user's username. This can be found in the UserInformation object, like so:

Windows.System.UserProfile.UserInformation.getPrincipalNameAsync().then(function (result)
{
    Debug.writeln(result);
});
 
 
You can then look at using the various web services and APIs provided by your chosen identity provider. One option is to provide your own web service, which may perform any further required logging in for the user, if Kerberos is not working for you.

Another option when having to ask the user for credentials is to use the CredentialPicker object. Here's an example of how to use it:

var credentialPickerResults;
var credentialPickerOptions = new Windows.Security.Credentials.UI.CredentialPickerOptions();
credentialPickerOptions.targetName = "My App";
credentialPickerOptions.caption = "My App";
credentialPickerOptions.message = "Sign in to My App";
credentialPickerOptions.authenticationProtocol = Windows.Security.Credentials.UI.AuthenticationProtocol.ntlm;
credentialPickerOptions.alwaysDisplayDialog = false;
var credentialPicker = Windows.Security.Credentials.UI.CredentialPicker;
credentialPicker.pickAsync(credentialPickerOptions).done(
function complete(result) {
    console.log("pickAsync complete: username = " + result.credentialUserName + ", password = " + result.credentialPassword + " errorCode = " + result.errorCode);
    credentialPickerResults = result;
},
function error(e) {
    console.log("pickAsync error: " + e.message);
});
 
 
The result object will contain the credentials the user specified. No authentication is performed on these credentials.

Tuesday, May 8, 2012

Displaying your product version in a Windows 8 Metro App

When creating a package for the store, the wizard gives you an option to automatically increment the package version number. This version number is used for a variety of important things. Wouldn't it be useful to display this number to the user when doing support, or logging errors?

To access the version you can easily use

Package.Current.Id.Version;

This returns a PackageVersion, with the regular 4 version properties.

Format it like so:

PackageVersion packageVersion = Package.Current.Id.Version;
string.Format("{0}.{1}.{2}.{3}", packageVersion.Major, packageVersion.Minor, packageVersion.Build,packageVersion.Revision);

Extra points for turning this into an extension method if you'll be doing it in more than one place!

In my current app, I've decided to add it to the application resources, and then bind to it from wherever I want to display it.

Windows App Certification Kit Test can't find the app

I've been trying to run the Windows App Certification Kit Test for a while now and again after building a package. It failed every time with an error stating that it couldn't find the app. I found this rather strange, because whenever I open the start menu, it's right there!

It turns out, before you run the kit, you have to install the package. When Visual Studio deploys the app, it is deployed as an unpackaged app. The certification kit looks for a packaged app, with a particular application name (a product guid). I won't go into the details about the other differences.

First, you have to uninstall the unpackaged app that Visual Studio deploys. Right click on the app in the start menu, and click Uninstall in the app bar.
To install the app, click on the link to the build package location in the window that is displayed after package creation. Next, open the folder with the name of your package, right click the Add-AppxDevPackage.bat file, and click Run as administrator. This will install your app as a packaged app.

You can now click the button to run the certification kit.

Sunday, May 6, 2012

COM Exception "HRESULT E_FAIL has been returned from a call to a COM component" in C# Windows 8 Metro app

I've recently been developing a few Windows 8 apps using the Consumer Preview release of Windows 8 and VS11. For the last week I've been struggling with a bug that occurred in a Windows 8 C#/XAML app.

In my app I have a Hub Page, which displays a grid with grouped items. I bind this grid to a CollectionViewSource, which takes care of this grouping for me. I also have a snapped view, which uses a ListView bound to the same CollectionViewSource. I got a ComException intermittently whenever I navigated to the page in the Snapped view. No exception would occur when navigating around in the filled view.

The exception would only be reported as a System.Runtime.InteropServices.COMException, with the message "Error HRESULT E_FAIL has been returned from a call to a COM component." and the error code -2147467259

I thought for a long time that it was a syncronisation problem on the ObservableCollection I was binding to, as I had several threads updating this collection. The problem only occurred when I was replacing items in the collection.

Eventually, the fact that it was only occurring in the snapped View, made me question what the difference was between the two. The only meaningful difference was that they never showed at the same time, and the snapped view was bound to the CollectionViewSource after the first. I remembered noticing in a different article about ObservableCollection that there could be problems binding multiple UIElements to the same collection, so this made me have another look at the XAML. My first attempt was to create a copy of the CollectionViewSource for my snapped view, and change the binding for the ListView.

It worked! I almost ran naked down the street!

I have no idea why it wouldn't work previously, but I can only speculate that the filled GridView may be taking too long to render the individual items, as the process to do so is actually quite involved in this instance. Using 2 identical CollectionViewSources is less efficient, but seems to be a sad necessity this time around.