Thursday, June 28, 2012

Reading file content using DataReader.ReadBytes in Metro apps

The Windows.Storage.Streams.DataReader.ReadBytes method stupidly breaks with the convention of the other methods on the DataReader object, by requiring you to pass in a variable to populate, instead of instantiating a new variable and returning it.

Looking at the declaration of this method:

[MethodImpl]
void IDataReader.ReadBytes([Out] byte[] value);

we see that the value is marked with an Out attribute. Note that this is not the same as an out parameter modifier.

To have your passed in value correctly populated, you need to instantiate the byte array to pass in, using the correct capacity. The capacity is available on your reader in the UnconsumedBufferLength property.

Here's a sample of using this method:

StorageFile file = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFileAsync("[filename]");
IBuffer buffer = await FileIO.ReadBufferAsync(file);
DataReader reader = DataReader.FromBuffer(buffer);
byte[] fileContent = new byte[reader.UnconsumedBufferLength];
reader.ReadBytes(fileContent);

Thursday, June 21, 2012

Deserialising a JSON formatted string to a dynamic object in C# Metro Style Apps

I found myself looking for an easy way to deserialise Json strings to dynamic objects today. Of course there are many excellent libraries (like Json.net) that will already do this for you. The problem is that I need to do it in a Metro Style app, which can't reference regular .Net libraries.

So, what to do?

First off, Json Serialisation has been provided as a first class citizen in Metro Style apps. There's no point in doing that again. We will use the Windows.Data.Json.JsonObject class provided in WinRT. Where our paths diverge from this provided class, is that the objects are accessed in a relatively gnarly way:

JsonObject jsonObject = JsonObject.Parse(jsonString);
string myStringProperty = jsonObject["myStringPropertyName"].GetString();
double myDoubleProperty = jsonObject["myDoublePropertyName"].GetNumber();
There are different methods you call depending on the type of the value you want. This type is exposed in the ValueType property of the IJsonValue interface, which is the type of the object returned by the indexing operation. We don't necessarily like this.

What I want to do is to read my Json object like this:

dynamic jsonObject = new DynamicJsonObjectReader(jsonString);
string myStringProperty = jsonObject.myStringPropertyName;
double myDoubleProperty = jsonObject.myDoublePropertyName;
It's debatable wether we would want the property to be returned as a concrete type, or as a dynamic object, but for these purposes I want a concrete type for string, double, bool and Array, and another DynamicJsonObjectReader for JsonObject.

To accomplish this, I created an object that wraps up the built-in JsonObject class and inherits from DynamicObject. I called the object a reader, because I've only overridden the TryGetMember method. To make it writable, I would also override the TrySetMember method. This is a bit more complicated, and surplus to my needs. For Now. The ToString method will spit out the Json formatted representation, which at the moment is useful for debugging. Once TrySetMember is properly implemented, ToString would be used for serialising. Here is the code:

Update:I've added an implementation for GetDynamicMemberNames. This enables the debugger to show you all the members and their values at runtime in the watch window. Pretty handy.

using System;
using System.Dynamic;
using System.Linq;
using Windows.Data.Json;

namespace JsonSerialisation
{
    internal class DynamicJsonObjectReader : DynamicObject
    {
        private readonly JsonObject jsonObject;

        public DynamicJsonObjectReader(string jsonString)
        {
            jsonObject = JsonObject.Parse(jsonString);
        }

        private DynamicJsonObjectReader(JsonObject jsonObject)
        {
            this.jsonObject = jsonObject;
        }

        public override string ToString()
        {
            return jsonObject.Stringify();
        }

        public override IEnumerable GetDynamicMemberNames()
        {
            return jsonObject.Keys;
        }
        
        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            IJsonValue jsonValue;
            if (!jsonObject.TryGetValue(binder.Name, out jsonValue))
            {
                // return null to avoid exception.  caller can check for null this way...
                result = null;
                return true;
            }

            result = GetValue(jsonValue);
            return true;
        }

        private object GetValue(IJsonValue jsonValue)
        {
            object result = null;
            switch (jsonValue.ValueType)
            {
                case JsonValueType.Object:
                    result = new DynamicJsonObjectReader(jsonValue.GetObject());
                    break;
                case JsonValueType.String:
                    result = jsonValue.GetString();
                    break;
                case JsonValueType.Number:
                    result = jsonValue.GetNumber();
                    break;
                case JsonValueType.Boolean:
                    result = jsonValue.GetBoolean();
                    break;
                case JsonValueType.Array:
                    result = CreateArray(jsonValue.GetArray());
                    break;
            }
            return result;
        }

        private Array CreateArray(JsonArray jsonArray)
        {
            return jsonArray.Select(GetValue).ToArray();
        }
    }
}

Tuesday, June 12, 2012

Enabling PIN authentication on Windows 8 for domain logons

By default, PIN authentication is disabled for domain logons on Windows 8 Release Preview.

There is a new group policy setting for allowing pin authentication. The description reads:
This policy setting allows you to control whether a domain user can sign in using a PIN. If you enable this policy setting, a domain user can set up and sign in with a PIN. If you disable or don't configure this policy setting, a domain user can't set up and use a PIN. Note that the user's domain password will be cached in the system vault when using this feature.

The setting is located by running GPEdit.msc Then navigate to Computer Configuration -> Administrative Templates -> System -> Logon -> Turn on pin sign-in Set this setting to enabled to allow domain users to use a pin when signing in to the computer.