Dynamically Attach Delegates to WCF Service in Silverlight

My team has a Silverlight 4 application sitting in an ASPX page hosted from SharePoint 2007 consuming WCF Services targeting .NET 3.5 also hosted from within SharePoint. Using this setup, our service methods can access SPContext. This allows us to leverage SharePoint Groups as a way to assign roles to users to grant or deny them access to data we’re hosting in a custom database.

Through our design, we’ve been using a generic class as the response for all our methods. This lets us have fields for data we want to track during each response (an error message for instance) along with a generic field to hold specific typed data.

As our design progressed we discovered a need to see if a user has been removed from a SharePoint group which would signify their revocation of access to specific data. Rather than wait for the user to attempt access and throw an unfriendly message, we decided to add a field to our generic response wrapper. Now we only need to check this field and pop a picker dialog to let the user pick a new organization based on SharePoint Groups to which they belong.

The problem is we have 42 methods that can return this field. Attaching to all of them with specific callbacks for the different eventargs types that were generated by adding a Service Reference to the service in our Silverlight application would be ugly and a pain to maintain as our methods are added and removed as our application evolves.

Through an earlier design decision, I implemented a singleton instance for the communication to the service: ConnectionService. This seemed like a great place to implement the side-listener. Now I just needed to hook up to each of the methods and listen for the field. I accomplished this via reflection:

ConnectionService() //private constructor in singleton class
{
   …
   EventInfo[] events = WcfClient.GetType().GetEvents();

   events.ParallelForEach((evt) =>
   {
      if (evt.EventHandlerType.IsGenericType && null != evt.EventHandlerType.GetGenericArguments()[0].GetProperty("Result"))
      {
         Delegate handler = Delegate.CreateDelegate(
            evt.EventHandlerType,
            this,
            this.GetType().GetMethod("WcfClient_CheckForInvalidUserOrg", BindingFlags.NonPublic | BindingFlags.Instance));

         evt.AddEventHandler(WcfClient, handler);
      }
   });
   …
}

void WcfClient_CheckForInvalidUserOrg(object sender, AsyncCompletedEventArgs e)
{
   try
   {
      PropertyInfo pi = e.GetType().GetProperty("Result");
      if (null != pi)
      {
         WebServiceVoidWrapper result = pi.GetValue(e, null) as WebServiceVoidWrapper;

         if (null != result)
            if (!result.IsGroupActive)
               HandleUserOrgNotValid(sender, e);
      }
   }
   catch (TargetInvocationException exc)
   {
      Debug.WriteLine(exc.Message);
   }
}

Working backwards a bit you see I created a function to be attached to the events. Since all our WCF Service methods return Silverlight-generated EventArgs inheriting from AsyncCompletedEventArgs. The upside is that we can use one method and not have to much with any of the generated code to insert a different base class. The downside is we don’t have direct access to the field in which we’re interested. The Silverlight generated class contains a field called “Result” which is of the type we’re returning. In our case we’re returning from our service method. We reflect the object, ensure the Result field is present and then try to cast it to the base class of our response wrapper which contains the boolean flag we want. If the flag is false, the user’s org is no longer valid and we pass off to another function to handle it.

Now jumping up to the constructor for the singleton class I have code that will grab all the events contained in our service connection object. This object is what exposes the Async methods to our service methods and the events that are fired when the service calls complete. Then I iterate them. You can use a simple for loop for this but I decided to use an extension method that will execute the statements in parallel and wait for them all to complete before moving forward. Since the service connection exposes a couple built-in events that we don’t care about, we reflect the type to ensure it matches the signature we’re interested in from our callback.

Once we’re sure the event is probably one we’re interested in listening to, we create an event delegate of the type required by the event which is accessed from EventHandlerType. The remainder of the delegate is just grabbing the MethodInfo for our callback function and where it exists. We call AddEventHandler and that’s it!

Now when the singleton class is constructed (and the WcfClient object is connected to our service) we cycle through all the events it exposes and attach our generic handler. If we detect the user org is invalid we fire a custom event. This lets our UI pages listen if they want to react but for our purposes we’re using our Silverlight project’s MainPage to pop up a ChildWindow for the user. We do it this way because we actually have a heartbeat method which pulses the service to see if the user’s report data has changed and if so, pop a refresh message. Since this is done in a separate thread, we can’t interact with the UI directly. Instead we fire an event which is listened to by something already in the VisualTree. Calling Dispather.BeginInvoke() lets us marshal the UI work on the proper thread and show the ChildWindow.

I was pretty sure before I started this design that I could make it work but I didn’t expect it to be so succinct.

Happy Coding!
-Erik

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s