Wednesday, June 30, 2010

Custom Authentication with Silverlight and WCF Data Services

I’m currently ripping out the .NET web forms configuration component for my Chaos Filter product and replacing it with a Silverlight component that is being fed by and OData WCF Data Service.  One of the requirements I have is to secure the services.  My strategy for securing my ASMX web services was to provide an AppId, DateStamp, User Context ID and a security hash, where AppId identified the client application, the User Context ID was used to identify the current users session, the DateStamp was used to eliminate any replay attacks a secure key was used to create a security hash to make sure that every thing is valid.  So each ASMX web request contained (appId,  security hash, userContextId, dateStamp).  It’s a little bit of an overhead but it seemed to be pretty secure.

With a traditional ASMX request this information was always just sent up as parameters to the call.  When creating and OData query I needed a different approach, and needed to extract that information on the server to perform authentication (confirm the users identity) and then authorization (confirm the user can do what they are asking to do).

So after creating the my security hash, here are the steps necessary to complete the hand-shaking.

  • Within the Silverlight application create a partial class for the main DataServiceContext on the generated proxy for your WCF Service.
  • Provide a partial method implementation for OnContextCreated within the constructor attach a handler to the SendingRequest event.

partial void OnContextCreated()
{
   this.SendingRequest += MyEntities_SendingRequest;
}

  • Add a method to set the auth fields on the partial class (these are custom fields created to hold the values until the actual call is made)

public void SetAuthParams(string appId, string hash, string userContextId, DateTime dateStamp)

  • In your event handler for SendingRequest, add the following code

void MyEntities_SendingRequest(object sender, SendingRequestEventArgs e)
{
    e.RequestHeaders["ApiId"] = _appId;
    e.RequestHeaders["SessionId"] = _userContextId;
    e.RequestHeaders["SecurityHash"] = _hash;
    e.RequestHeaders["TimeStamp"] = _timeStamp;
}

  • Then to make the call simply:
  • serviceContext.SetAuthParams(appId, securityHash, userContextId, dateStamp);
    conferences.LoadAsync(conferenceQuery);

  • Next on the server side we can extract these values by simply looking at the Request.Headers collection

var headers = System.Web.HttpContext.Current.Request.Headers;
foreach (var header in headers)
    Debug.WriteLine("{0} -> {1}", header, headers[header.ToString()]);

  • Finally we need to add some configuration to our applications.  On the Silverlight side we need to add the following to the root node Manifest for our .XAP file.

<Deployment xmlns="http://schemas.microsoft.com/client/2007/deployment"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            ExternalCallersFromCrossDomain="ScriptableOnly">

  • On the server side that hosts the WCF service we need to add the following to the <system.serviceModel> node.
  •     <serviceHostingEnvironment aspNetCompatibilityEnabled="true"  />

    With this approach you should be able to pass parameters via the header from your Silverlight Client to a WCF Data Service for what ever your application requires.

    -twb

Friday, June 25, 2010

Using DataAnnotations on Generated Entities within Silverlight

It makes sense to use DataAnnotations to decorate your models so that when you bind those models to the DataForm within the Silverlight Toolkit, that DataForm comes to life with all the proper validation and display functionality.  To add the data annotations you need to decorate properties like:

[Required(ErrorMessage="Date is a required field.")]
[Display(Name="Date", Description="Date of event.")]
[DisplayFormat(DataFormatString="{0:d}")]
public DateTime Date { get; set; }

 

This works well if you create your models a POCO’s within your Silverlight project.  However, in most cases you will want to bind to data that is presented through some sort of service.  If you add a service to your project, a proxy will be generated that really can’t be, shouldn’t be modified.  The challenge is when your proxy for the service gets generated the property is generated as well, any modifications you make to that generated property will be overwritten if you regenerate your proxy.

In the MVC2 world, you can use the MetadataType attribute to decorate a partial class for the generated entity within your proxy.  In the case below I am mapping the meta data class MyNameSpace.Day.MetaData to the generated entity MyNameSpace.Day via a partial class.:

using System;
using System.ComponentModel.DataAnnotations;

namespace MyNamespace
{
    [MetadataType(typeof(MetaData))]
    public partial class Day
    {
        public class MetaData
        {
            [Required(ErrorMessage="Date is a required field.")]
            [Display(Name="Date", Description="Date of event.")]
            [DisplayFormat(DataFormatString="{0:d}")]
            public object Date { get; set; }

            [Required()]
            [Display(Name="Display Date",Description="Display.")]
            public object DateDisplay { get; set; }

        }
    }
}

However sadly as of Silverlight 4, the MetadataType attribute does not exist within System.ComponentModel.DataAnnotations namespace.  The solution I came up with was to provide my own implementation of MetadataType.  I reused the System.ComponentModel.DataAnnotations namespace for two reasons.  First because when the functionality does indeed become available within Silverlight your code won’t need to change.  Second you compiler will tell you with an error when it does become available, at that point you can use the standard implementation. 

Here’s my very basic implementation:

using System;

namespace System.ComponentModel.DataAnnotations
{
    public class MetadataTypeAttribute : Attribute
    {
        public MetadataTypeAttribute(Type t)
        {
            MetaDataType = t;
        }

        public Type MetaDataType
        {
            get;
            set;
        }
    }
}

With the above implementation, my partial class that uses the MetadataType object will compile with Silverlight as it did with MVC2.

The final component to make this work is to let the DataForm know how to look for the MetaData.  This requires building the DataForm within the Silverlight toolkit and modifying the code.  I’m sure you realize the risk in doing something like this, but hopefully in a future release of the DataForm this functionality will be baked in and you can just use the canned version and the rest of your application should work without any modifications.

Within the System.Windows.Controls.Data.DataForm.Toolkit project you should look for /DataField/DataField.cs this is where all the magic happens to add the validation and display functionality to you form.  Specifically look for a method GetPropertyInfo(), you will modify the functionality of that method to check to see if the class that is mapped to the form as the custom attribute MetadataTypeAttribute.  If so it will use the class associated with it to look for decorated properties used to properly render the form.  Since GetPropertyInfo() is used by all the methods to render the form, this one change supports all the different types of attributes used for form validation and display.

private PropertyInfo GetPropertyInfo()
{
    Debug.Assert(this.DataContext != null, "DataContext should never be null
                                       when GetPropertyInfo() is called.");

    PropertyInfo propertyInfo = null;

    if (!string.IsNullOrEmpty(this.PropertyPath))
        propertyInfo = this.DataContext.GetType().GetPropertyInfo
                                                   (this.PropertyPath);

    if (propertyInfo == null && this.Content != null)
    {
        var bindingInfos = this.Content.GetDataFormBindingInfo(
                                 this.DataContext, 
                                 false /* twoWayOnly */,
                                 false /* searchChildren */);

        foreach (DataFormBindingInfo bindingInfo in bindingInfos)
        {
            var binding = bindingInfo.BindingExpression.ParentBinding;

            if (binding != null &&
                binding.Path != null &&
                !string.IsNullOrEmpty(binding.Path.Path))
            {
                var contextType = this.DataContext.GetType();
                var bindingPath = binding.Path.Path;
                var metaDataTypes = contextType.GetCustomAttributes(typeof
                                        (MetadataTypeAttribute), false);
                if (metaDataTypes.Length == 1)
                {
                    var metaDataTypeInfo = metaDataTypes[0] as
                                                  MetadataTypeAttribute;
                    var metaDataType = metaDataTypeInfo.MetaDataType;
                    propertyInfo = metaDataType.GetPropertyInfo(bindingPath) 
                                                  as PropertyInfo;

                    if (propertyInfo != null)
                        break;
                 }
                else
                {
                    propertyInfo = contextType.GetPropertyInfo(bindingPath)
                                                  as PropertyInfo;

                    if (propertyInfo != null)
                        break;
                }
            }
        }
    }

    return propertyInfo;
}

Ever since I started using code generation to create a DataAccessLayer for my application, I’ve dreamt of the day I could decorate my models with attributes, then anywhere I needed to expose those models to the UI, the UI would just pickup those attributes and behavior properly.  The above approach is somewhat “hack-ish” but does provide a stop-gap until a future generation of Silverlight implements this functionality.  It also does so in such a away that should be forward-compatible, at least as much as possible without a crystal ball. 

-twb

Wednesday, June 16, 2010

Speaking at Sarasota .NET VS2010 Launch Event

Tonight I’m speaking at the Sarasota .NET Launch Event.

In one hour, I’m going to attempt to cover:

  • Introduction to Windows Phone 7 Development
  • What’s new in Silverlight 4

I’ll probably go pretty quick so if we don’t cover everything, you can download the materials from the link below:

Download Resource Files

Hope to see you all there!

-twb

Friday, June 11, 2010

The Announcement of the Death of Windows Mobile 6.5 is Premature

This year for TechEd, I created a Windows Mobile 6.5 widget to allow attendees to manage their schedule.  After noticing on the third day that there seemed to be a constant stream of downloads, I added some server side instrumentation to detect user agent strings and record what types of devices were downloading the data.  Although this was a Microsoft event I was still somewhat surprised with the results.

image

  • 50.74% (1777) - Windows Mobile 6.5
  • 19.85% (695) – iPhone
  • 13.91% (487) – Android 2.1
  • 11.65% (408) – Sidebar Desktop Gadget
  • 3.57% (125) – iPad
  • 0.29% (10) – Unknown

Some additional notes:

  • Without any real publicity, about 900 people had downloaded the app from Marketplace in the first few days.
  • The above metrics were captured after these initial downloads had already taken place from Window Phone Marketplace and before I announced support for other platforms.
  • On the second to last night of the conference, I found someone with a Palm Pre, the application also ran on that platform.
  • This only runs on Windows 6.5 Professional.  I heard from a number of people they would like to install on Windows 6.1 without Widget support.  A version for the earlier version of Windows Mobile is already underway.
  • A few people also told me that they could not find the application on the Verizon version of the Windows Phone marketplace.
  • I didn’t hear of anyone having any problems with the Windows Mobile widget.  However I had to scale back the amount of data stored on the iPhone since there is a 5MB limit local storage limitation.  On the Android phones there seemed to be a problem where on some devices, the local storage was not saved after the application exited and on other devices it did.  This required a last minute work around (changed from local storage to local database) to resolve the issue.
  • The total number of downloads was approximately 4400, the total number of people registered for TechEd was approximately 8000. 

Summary

Although this was a Microsoft conference, I was surprised that even though the application was available on all of the major platforms, Windows Mobile 6.5 was the most used platform for this application by a wide margin.  I was also very happy to see so many people picking up the application from Marketplace even before I started publicizing and the link was added to the TechEd web site.  If you are under the perception that no one is using Windows Mobile in its current version anymore, you might want to reconsider.  There are a number of great Windows Mobile 6.5 devices out there and apparently there is a silent, yet fairly large number of users that still use these devices, including yours truly.

-twb

Tuesday, June 1, 2010

TechEd 2010 Schedule and Twitter Tool – One App, 5 Different Platforms

The Wolf Bytes is proud to announce the availability of the free TechEd 2010 Scheduling and Main_315x420 Twitter tool influenced with the Windows Phone 7 Metro design guide lines.  After you download the session data, you can view the schedule and build your own custom schedule.  With the twitter tool, you can view tweets for the main conference hash tag #TechEd as well as build up a favorite list of tags you wish to follow.

Windows Phone 6.5

Availability for Windows Phone 6.5 is through the Windows Phone Marketplace.  The current version sends tweets via SMS, look for a update by the time TechEd starts that will allow you to send tweets directly from the application.  To download and install, either search for TechEd or look under Tools and then Developer tools on your windows mobile phone in the Marketplace.  Or click here to get it online.

Sidebar Gadget

You can install the scheduling and twitter tool directly to your Vista or Windows desktop.  This version is presented to you in a Windows Phone 7 skin.  Download the Desktop widget from here.

Android

You can download a free version of the scheduling and twitter tool to your Android V2.1 phone.  Just go to the marketplace and search for TechEd.

UPDATED 6/3/2010:  There seems to be a bug in android (or the way I’m using the WebView) where session data is not stored when you close the app.  This is not on all devices, but if this is happening to you, please use the web URL http://eventmgr.slsys.net/android.htm and see if that helps.  I’m currently researching a work around but this may not be completed by the time TechEd starts.

UPDATED 6/5/2010: Uploaded V1.3 to Android Marketplace should contain fix for losing session data when application is terminated.  If this fixes it for you, let me know via @ByteMaster or Kevin@TheWolfBytes.com

iPhone

Don’t look for the iPhone/iPad application on the App store.  Follow these two very easy steps.

  1. Open Safari and enter the address http://eventmgr.slsys.net/iPhone.htm
  2. Once the page is opened, click the “+” on the bottom of your screen and then click “Add to Home Screen”.  This will create an icon in your home menu that will allow you to start the app.

iPad

The iPhone version will work on the the iPad, however look for a more resolution appropriate version by the time TechEd starts.

Any questions or comments, please feel free to contact me on twitter @ByteMaster

Enjoy!

-twb