Showing posts with label Web Services. Show all posts
Showing posts with label Web Services. Show all posts

Monday, April 4, 2011

Rock, Paper, Scissors & Azure!

Check out this interesting and super cool contest post by DevFish…

http://www.devfish.net/fullblogitemview.aspx?blogid=809

Round #1 kicks off April 4 and the Contest Ends May 10th.

See you out there under TheWolfBytes_FL

-twb

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