Category Archives: Step-By-Step

So you want to provide a DataSet to your WP7 app?!

Hi folks,

It is not new (wow, more than 2 years) that MS announced that there’s no plan to support dataset on Silverlight (currently WP7 is based on Silverlight 3 based).
http://blogs.msdn.com/b/adonet/archive/2009/05/26/dataset-and-silverlight.aspx

But we all know that life is not so easier and we cannot just change to LINQ to Entities. I’m not even going to jump in this discussion here. Actually I am assuming that you need an alternative. One possible alternative is the SilverlightDataset project, created by Laskarzhevsky Software Inc. I have to be honest that I did not used this solution mainly because at the first moment I’m trying to do something really simple.

My general idea is to create a WCF Service that will expose dynamically new types (POCO) which will be created based on a dataset. I played a little bit with Reflection & Emit to do this job. Here is a code that, given a DataTable returns a dynamically created type:

public class Functions
{
    public static Type CreateType(DataTable table)
    {
        //Obtaining DataContract & DataMember Attribute
        CustomAttributeBuilder dataContractAttribute = new CustomAttributeBuilder(typeof(DataContractAttribute)
                                                      .GetConstructor(System.Type.EmptyTypes), new object[] { });
        CustomAttributeBuilder dataMemberAttribute = new CustomAttributeBuilder(typeof(DataMemberAttribute)
                                                      .GetConstructor(System.Type.EmptyTypes), new object[] { });

        AssemblyName assemblyName = new AssemblyName();
        assemblyName.Name = string.Format("DynamicType.{0}", table.TableName);

        AppDomain appDomain = AppDomain.CurrentDomain;
        //Later you just change it to AssemblyBuilderAccess.Run and remove the file saving process to save some time...
        AssemblyBuilder assemblyBuilder = appDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
        ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name,"dynamic.dll");

        TypeBuilder typeBuilder = moduleBuilder.DefineType(string.Format("Data.{0}", table.TableName), TypeAttributes.Public, typeof(BaseType));
        //decorating as DataContract
        typeBuilder.SetCustomAttribute(dataContractAttribute);

        //calling base contructor passing thw datarow to it
        ConstructorBuilder constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new Type[] { typeof(DataRow) });
        ILGenerator constructorIL = constructorBuilder.GetILGenerator();
        constructorIL.Emit(OpCodes.Ldarg_0);
        constructorIL.Emit(OpCodes.Ldarg_1);
        constructorIL.Emit(OpCodes.Call, typeof(BaseType).GetConstructor(new Type[] { typeof(DataRow) }));
        constructorIL.Emit(OpCodes.Ret);

        //Creating one property per column
        foreach (DataColumn column in table.Columns)
        {
            createDataMemberProperty(dataMemberAttribute, typeBuilder, column);
        }

        Type toReturn = typeBuilder.CreateType();
        // Save the assembly so it can be examined with Ildasm.exe,
        // or referenced by a test program.
        assemblyBuilder.Save("dynamic.dll");

        return toReturn;
    }

    private static void createDataMemberProperty(CustomAttributeBuilder dataMemberAttribute, TypeBuilder typeBuilder, DataColumn column)
    {
        string propertyName = column.ColumnName;
        string fieldName = string.Format("_{0}", propertyName.ToLower());

        //Creating Field that will be set/get on the properties                
        FieldBuilder propertyField = typeBuilder.DefineField(fieldName,
                                            column.DataType,
                                            FieldAttributes.Private);
        // The last argument of DefineProperty is null, because the
        // property has no parameters. (If you don't specify null, you must
        // specify an array of Type objects. For a parameterless property,
        // use an array with no elements: new Type[] {})
        PropertyBuilder property = typeBuilder.DefineProperty(column.ColumnName,
                                                    System.Reflection.PropertyAttributes.None,
                                                    CallingConventions.Standard, column.DataType, null);

        //decorating with DataMember attribute
        property.SetCustomAttribute(dataMemberAttribute);

        // The property set and property get methods require a special
        // set of attributes.
        MethodAttributes getSetAttr =
            MethodAttributes.Public | MethodAttributes.SpecialName |
                MethodAttributes.HideBySig;

        // Define the "get" accessor method for CustomerName.
        MethodBuilder propGetMethod =
            typeBuilder.DefineMethod("get_" + propertyName,
                                        getSetAttr,
                                        column.DataType,
                                        Type.EmptyTypes);

        ILGenerator getIL = propGetMethod.GetILGenerator();
        getIL.Emit(OpCodes.Ldarg_0);
        getIL.Emit(OpCodes.Ldfld, propertyField);
        getIL.Emit(OpCodes.Ret);

        // Define the "set" accessor method for CustomerName.
        MethodBuilder propSetMethod =
            typeBuilder.DefineMethod("set_" + propertyName,
                                        getSetAttr,
                                        null,
                                        new Type[] { column.DataType });
        ILGenerator setIl = propSetMethod.GetILGenerator();

        setIl.Emit(OpCodes.Ldarg_0);
        setIl.Emit(OpCodes.Ldarg_1);
        setIl.Emit(OpCodes.Stfld, propertyField);
        setIl.Emit(OpCodes.Ret);

        // Last, we must map the two methods created above to our PropertyBuilder to 
        // their corresponding behaviors, "get" and "set" respectively. 
        property.SetGetMethod(propGetMethod);
        property.SetSetMethod(propSetMethod);
    }
}

The code look a bit scary… And it really is… Use emit is like develop in IL directly… J Anyway, if you give this datatable:

It will return something like this:

[DataContract]
public class Students : BaseType
{
	private int _age;
	private string _name;

    [DataMember]
	public int Age
	{
		get
		{
			return this._age;
		}
		set
		{
			this._age = ;
		}
	}

	[DataMember]
	public string Name
	{
		get
		{
			return this._name;
		}
		set
		{
			this._name = ;
		}
	}
	public Students(DataRow ) : base()
	{
	}
}

You can see that it is deriving from a base type, called BaseType…

[DataContract]
public class BaseType
{
    public BaseType(DataRow row)
    {
        foreach (DataColumn column in row.Table.Columns)
        {
            var field = this.GetType().GetField(string.Format("_{0}",column.ColumnName.ToLower())
                                                ,BindingFlags.NonPublic|BindingFlags.Instance);
            if (field != null && !row.IsNull(column))
                field.SetValue(this, row[column]);
        }
    }
}

As you can see the base type has a constructor that given a dataRow, it will set the fields of the type. I could implement this logic on the Contructor but I was really lazy to find out how to do it using Emit… Could take some hours to find out… Then I just made the easy way… Another thing that you should not is the WCF attributes [DataContract] and [DataMember] that are decorating the types and properties…

Now we want to expose this datatable through a WCF service… The service contract is quite simple:

[ServiceContract]
public interface IDataSetService
{
    [OperationContract]
    [ServiceKnownType("GetKnownTypes", typeof(DataSetService))]
    DataSet.BaseType GetData();
}    

You can see that it returns the BaseType, which is the basetype of my dataset elements. Another important thing to remark is the ServiceKnownType attribute that I’m using to dynamically add KnowTypes(like this Students class that I showed above). Here you can have the service implementation:

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class DataSetService : IDataSetService
{

    #region [ServiceKnownType("GetKnownTypes", typeof(DataSetService))]
    /// <summary>
    /// Detects all KnownTypes that should be published by the Service WSDL
    /// Basically we will find all DataContracts, ServiceCommandRequest and ServiceCommandResponses
    /// </summary>
    /// <param name="provider"></param>
    /// <returns></returns>
    public static IEnumerable<Type> GetKnownTypes(ICustomAttributeProvider provider)
    {
        Type dynamicType = DataSet.Functions.CreateType(new Students.StudentsDataTable());
        dynamicTypes = new Dictionary<Type, Type>();
        dynamicTypes.Add(typeof(Students.StudentsDataTable), dynamicType);

        System.Collections.Generic.List<System.Type> knownTypes =
            new System.Collections.Generic.List<System.Type>();
        knownTypes.Add(dynamicType);
        // Add any types to include here.        
        return knownTypes;
    }
    #endregion

    static Dictionary<Type, Type> dynamicTypes;

    public DataSet.BaseType GetData()
    {
        Students.StudentsDataTable table = new Students.StudentsDataTable();
        table.Rows.Add("Pedro", 28);
        DataSet.BaseType toReturn = (DataSet.BaseType)System.Activator.CreateInstance(dynamicTypes[table.GetType()],
                                                                                      new object[] { table.Rows[0] });
        return toReturn;
    }
}

Just to remember, AspNetCompatibilityRequirements is required by the Silverlight 3 Service client. The GetKnownTypes method is doing the miracle to allow me to return dynamic types to my client. Actually when my client generates the proxy classes, the Students class will be available as well! Finally, you can see that the service is returning a created type based on a row with the values “Pedro” and 28.

Let’s add the reference to our Web Service from our WP7 Client…

One you add the Service reference, you can take a look on the generated proxy code

The most important thing to see is that our Students type was created, even if our main WebService API do not refer to it. Actually that GetKnownTypes made this “miracle”!

Now it is time to consume the service from our WP7 app… Look this very simplistic code:

// Constructor
public MainPage()
{
    InitializeComponent();

    // Set the data context of the listbox control to the sample data
    DataContext = App.ViewModel;
    this.Loaded += new RoutedEventHandler(MainPage_Loaded);

    DataSetService.DataSetServiceClient cli = new DataSetService.DataSetServiceClient();
    cli.GetDataCompleted += new EventHandler<DataSetService.GetDataCompletedEventArgs>(cli_GetDataCompleted);
    cli.GetDataAsync();
}

void cli_GetDataCompleted(object sender, DataSetService.GetDataCompletedEventArgs e)
{
    DataSetService.Students students = (DataSetService.Students)e.Result;
    MessageBox.Show(string.Format("{0}, {1}", students.Name, students.Age));
}

Basically this code just call the method GetData from our service… Look that when the GetDataCompleted event we just cast the result to (DataSetService.Students) . Then we just show a messageBox… Really simple… And it worked nicely!

Well… This is it! That was an easy way to expose your dataset to WP7 clients using WCF without bigger issues. Of COURSE this sample is really simplistic but I’m sure that it can handle a lot of situations. In case of some special data editing support we would need some extra code to synchronize the POCO class with the dataset… But you know… this is just the start…. J

DOWNLOAD: Naturally you can have the sourceCode of this sample here.

Where is my Binding UpdateSourceTrigger= PropertyChanged on WP7 Silverlight ?

WTF! Where is the UpdateSourceTrigger= PropertyChanged on WP7 Silverlight? J

I got surprised when I saw that there was no PropertyChanged option on the UpdateSourceTrigger… All I could see was Default and Explicit…

The Default behavior works like our “LostFocus” from WPF, where the value is updated only when the control loses focus. This works most of the time, but there will be situations that you need the value to get updated as soon as the control values changes (equivalent to PropertyChanged).

To achieve this behavior you will need to do:

Set the UpdateSourceTrigger to Explicit

When you say that it is “explicit”, basically you will have to handle it…. Next step is to add one event handler to your bound control. On my sample it is a TextBox.

On the event handler comes the magic:

 

private void TextChangedUpdateTrigger(object sender, TextChangedEventArgs e)
{
  TextBox txtbox = sender as TextBox;
BindingExpression bindingExpression = txtbox.GetBindingExpression(TextBox.TextProperty);
bindingExpression.UpdateSource();
}

The code above sets the binding explicitly! Great!!(or not so if you know what I mean) Anyway, this will give you the “PropertyChanged” like behavior…

That’s it for now!

BTW I found this solution on the very nice free book
Programming Windows Phone 7 from Charles Petzold. Read the whole book or jump to page 387 to know about this issue in particular.
J

Publishing one App to the Market Place

As previously mentioned, on this post I will cover the submission process of the MSDN App Hub.

To follow this procedure you will need to register yourself on the App Hub. This includes paying the annual subscription fee (75€, $99 USD). So, no new Xbox game this month…. Or you should cut some of your beer/coke to pay that. J

You can submit one app even before your account gets verified by GeoTrust. Actually I was advised by the support guys to submit an App (even if it would be just a test app) in order to trigger the verification procedure from geoTrust.

The general process is described on the image Bellow:


Source: http://msdn.microsoft.com/en-us/library/hh184843(v=VS.92).aspx

You should be patient and read all the requirements in order to avoid that your application fails the certification process… This is boring but very important. Take your time to read it…

One of the advices that I followed before send the app was to use the Capability Detection tool to only have on my manifest what my app really needed.

Manifest before.


Tool execution results:


Manifest after.

Before start the submission you should have:

  • Application name and version (Of course you need it! J)
  • One description about the app. You will need to give it. It’s important that you think in pre-hand.
  • Have images on the following dimensions:
    • 173 x 173(Large phone application tile icon)
    • 99 x 99(Small phone application tile icon)
    • 200 x 200 (Large PC application tile icon)
    • 1000 x 800(Background panorama [optional])
    • 480 x 800(Page screenshots [at least 1, up to 8]). Just use the tool that I proposed on this post to take as much screenshots you can.
  1. Once you are logged, just click on My dashboard/Windows Phone

  1. If you don’t have anything published you will see the screen bellow. Click on submit App.

  2. Now just fill in the Application name and Version. Then you should also provide the XAP. DON’T FORGET TO SEND YOUR XAP FROM THE RELEASE FOLDER. If you send debug bits, the TEST WILL FAIL.

  3. Once you click on next it might take a while depending on how big your XAP is…

  4. Then it is time to provide your description

  5. After that you should provide the images that I described before… Just add all of them.

  6. If you are looking for money, just give your price at the Pricing step. That’s also the place where you say if your app has a demo version or not. On some next post I want to talk more about Trial versions…

  7. Ready! Easy, isn’t it? If you don’t want to publish even if it passes the certification, just uncheck the checkbox.

Now you need to wait… Like I’m waiting… J I read that the average time to have one app certified is 1.8 days…. Mine already went over. I hope that it passes. J

I give more news when I have! :)

Follow

Get every new post delivered to your Inbox.