Thursday, February 12, 2009

Migration

Well, finally got tired of having the old address (Bragosphere), so I migrated my blog over to zleek.wordpress.com. Please update your bookmarks/rss accordingly.

Monday, February 9, 2009

My Day Job

This Dilbert strip sums up my day job pretty well.

I'll get to that File Uploader post that I promised soon...

Monday, February 2, 2009

Phoenix Silverlight User Group

Dave Campbell of Silverlight Cream has asked me to present at the next Phoenix Silverlight User Group meeting. If you are interested in Silverlight and live in the Phoenix-metro area, it is a great user group to join.

My presentation is titled "Using Silverlight and WCF to create a RESTful File Upload Utility". If any of those topics interest you, please come and join us! Source code will be provided on this blog in the days following the presentation. Hope to see you there!

Get the Source Code and the Slide Deck here. I will put up a proper post covering everything more fully in the coming days.

Saturday, January 3, 2009

MIX09 10K Smart Coding Challenge

I entered a Zleek Silverlight application into the MIX09 10K Smart Coding Challenge. Please Vote for my entry by rating it 5 stars!

It is a very "lite" version of Zleek that contains only a single page where you can upload images, manipulate them using drag/rotate/scale, and save your layout. You can't share layouts with other users, but the application will remember your last saved layout.

The idea of the competition is to fit as much functionality in only 10KB of source code. Here's a snippet of what size constraints will make your code look like (note that my actual submission was all on a single line of text):
I should write code like this at work! I'm sure everyone would appreciate how easy to read it is! Anyway, it was fun putting together code completely at odds with my normal coding style. For you geeks out there thinking about entering, here is what I learned from the experience:

  • var is your friend.
  • Use lambdas where possible. The implicitly typed arguments are great for shaving off type names (just like var).
  • LINQ extensions to IEnumerable and IList are great. ForEach and Cast will save you a lot of code especially when combined with lambdas.
  • Use fields over properties. Remember that leaving off the access modifier will mark them private.
  • Question every single framework call you make and whether or not it makes sense to encapsulate it. I ended up taking a bunch of the common ones and creating static methods that wrap the calls.
  • If you have a function that takes multiple parameters of the same type, use an array declaration instead. (e.g. CalcDistance(Point a, Point b) becomes CalcDistance(Point[] p) -- and of course the actual function name should be trimmed to 1-2 characters)
  • XAML vs. Code vs. external image -- In many cases, code is preferred over XAML. The obvious exceptions here is XAML that makes heavy use of Path.Data (code does not accept the shorthand notation, AFAIK). The code for downloading an image using WebClient is fairly small. Definitely worth looking at. Note that downloading remote XAML is frowned upon by the contest moderators and should not be used.
  • Consider subclassing commonly-used non-sealed framework classes. Unfortunately, all of the common long-named classes I was using were sealed, so I couldn't do this... but I wanted to try and subclass framework classes that I used a lot so that I wouldn't waste space with the type name that often.
  • Place all of your CODE in a single file so that you only have to take up space for "using" directives once. (Note: you might have to add some class assignment directives as well e.g. using Path=System.Windows.Shapes.Path when System.IO is also imported)
  • Cleanup all of the whitespace. Remember special spacing rules like int[]a and int?a are valid and do not require spacing after the type name due to the non-alpha character.

Sunday, December 28, 2008

Consuming RESTful Web Services in Silverlight

Overview

This post is an extension of Rob Bagby's series on RESTful services. His 11th post details setting up a RESTful WCF service that can be consumed in Silverlight.

The key points are:
  • Creating a new Service Host Factory and Interceptor to support HTTP Verb tunneling, since Silverlight supports only GET and POST verbs.
  • Issuing calls from a client application to the RESTful service (including Silverlight and Fiddler)
This provides a great starting point for creating RESTful services and consuming them with Silverlight, so I decided to create a RESTful service layer around Zleek that utilizes LINQ to Entities.

Here are my take-aways from the experience:
  • The WCF Rest Starter Kit makes generating RESTful services extremely easy!
  • The ADO.NET generated entity classes are declared as partial so that you can easily extend them with your business logic.
  • You should create a separate Data Contract version of your entities in order to facilitate serialization
I updated my Agnition.Silverlight.Utils library (see my Previous Post on Silverlight Extensions) with some utility classes for dealing with RESTful services, including request creation and serialization.

Step-By-Step

  1. Download the WCF Rest Starter Kit
  2. Create a blank solution and add the Microsoft.ServiceModel.Web project from the starter kit as well as the Agnition.Silverlight.Utils project into it.
  3. Create a class library for your ADO.NET Entities
  4. Create an Entity Data Model from your database
    Creating a Data Model
  5. Create partial classes for each of your entities that you wish to write business logic or create data contracts for. Ideally this will be in a separate class library project.
  6. Create a class library for your data contracts.
  7. Create a Silverlight class library for data contracts. You will add all data contracts here as existing links to your other data contracts library to facilitate code sharing between your .NET 3.5 and Silverlight 2.0 libraries.
    Add Existing Item
    Add as Link
  8. Optionally create Silverlight business entity classes (possibly in another library) for your Silverlight application.
  9. Create a Silverlight application that you will use as your client. Ideally you should create a separate ASP.NET web application linked to the Silverlight application for ease-of-testing.
At this point, your solution structure should look similar to the following:
Sample Solution
Now we can start fleshing out the service and client. Let's start out by creating the service. Follow Rob's Post to walk-through creating your Service Host Factory and Interceptor. After that is complete, get started making the sevice more accessible to Silverlight.
  1. Remember those data contract libraries? Now it's time to flesh them out. For each entity, create a class with public properties for each piece of data you wish to expose. You can include relational properties this way as well. Here is an example:
    Example Data Contract
  2. Provide a way to project your entity class into your data contract. The easiest way (syntactically) to do this is to create an operator that will allow you to project the entity class into your data contract type while using casting syntax. The following screenshot illustrates both creating the operator and using the cast syntax to perform conversions:
    Projecting Into a Data Contract
  3. Create a web service method using OperationContract and WebInvoke (or WebGet) attributes. Remember that to be truly RESTful, retrieval operations should use GET, inserts/updates should use PUT, deletes should use DELETE and appends should use POST. Response codes should be used effectively as well. Here is a GET example:
    Example Web Method
At this point you can either test the service using Fiddler (see Rob's post), or go ahead and create the client application.
  1. Create a way to get the service URL into the Silverlight application. I like to use startup parameters. Here is how they are declared:
    Init Params
    They can only be extracted in the Application.Startup event, so I like to create a Configuration class that gives strongly-typed access to my parameters later.
    Reading Init Params
    Sample Configuration Class
  2. Now we are ready to call the service and deserialize the result:
    Call Service from Silverlight
That's it! Easier that you thought it would be, right? Please post any comments/questions you have about this. Here is the updated Agnition.Silverlight.Utils library.

Sunday, December 21, 2008

Silverlight Extenders

Source updated 12/24 with cross-browser support
Source updated 12/30 with RotateScaleExtender repaint fix
Work on the final version of Zleek is progressing nicely. The new UI is coming along, as well as the backend. The new features, including integration with other photo services and video support, are just about complete as well.

Over the coming months before our release, I will be posting code snippets and libraries that I put together for Zleek that may be helpful for other Silverlight developers.

This first post is a combination of a few extenders that I put together:
  • DragExtender: Adds mouse drag functionality to any FrameworkElement
  • RotateScaleXtender: Adds mouse rotate/scale functionality to any FrameworkElement
  • KeyExtender: Adds extra keyboard support, including handling of DOM events and extra keys
  • FillContainerExtender: Automatically resizes the Silverlight application to fill its container.

Here is the running example.

The source code in the test harness is pretty simple. You declare an instance of the extender and give it a reference to the FrameworkElement you want to add functionality to, and the extender does the rest. There are extensibility points inside of the extenders that should make them useful for any application.

Here is the source code, and here's a snippet from the test harness showing example usage:

   1:  using System;
   2:  using System.Windows.Controls;
   3:  using Agnition.Silverlight.Input;
   4:  using Agnition.Silverlight.Controls;
   5:   
   6:  namespace ExtenderTestHarness
   7:  {
   8:    public partial class Page : UserControl
   9:    {
  10:      public Page() {
  11:        InitializeComponent();
  12:   
  13:        // Initialize extenders
  14:   
  15:        _fillContainerExtender = new FillContainerExtender(this.LayoutRoot);
  16:   
  17:        _keyExtender = new KeyExtender(this, true, true, true);
  18:        _keyExtender.KeyDown += new EventHandler<KeyCodeEventArgs>(KeyExtender_KeyDown);
  19:        _keyExtender.KeyUp += new EventHandler<KeyCodeEventArgs>(KeyExtender_KeyUp);
  20:   
  21:        _dragExtender = new DragExtender(this.DragMe);
  22:        _dragExtender.StateChangeStart += new EventHandler<StateChangingEventArgs>(DragExtender_StateChangeStart);
  23:   
  24:        _rotateScaleExtender = new RotateScaleExtender(this.DragMe, 0.75, 6);
  25:        _rotateScaleExtender.StateChangeStart += new EventHandler<StateChangingEventArgs>(RotateScaleExtender_StateChangeStart);
  26:      }
  27:   
  28:      private void FullScreenButton_Click(object sender, System.Windows.RoutedEventArgs e) {
  29:        // Toggle full screen
  30:        _fillContainerExtender.IsFullScreen = !_fillContainerExtender.IsFullScreen;
  31:   
  32:        // Toggle display of warning
  33:        FullScreenWarning.Visibility =
  34:          FullScreenWarning.Visibility == System.Windows.Visibility.Collapsed ?
  35:          System.Windows.Visibility.Visible : System.Windows.Visibility.Collapsed;
  36:      }
  37:   
  38:      private void KeyExtender_KeyDown(object sender, KeyCodeEventArgs e) {
  39:        // Demonstrates KeyCode event arguments Key and TextValue
  40:   
  41:        // Show which key was pressed
  42:        if (e.Key == KeyCode.Shift) {
  43:          MouseMode.Text = "Mouse Mode: Rotate/Scale";
  44:        }
  45:        else {
  46:          // Don't show message on shift, to prevent spamming while holding
  47:          KeysPressed.Text += e.Key.ToString() + " ";
  48:        }
  49:   
  50:        // Render the text
  51:        if (e.TextValue != null) {
  52:          KeyText.Text += e.TextValue;
  53:        }
  54:        else if ((e.Key == KeyCode.Backspace) && (KeyText.Text.Length > 0)) {
  55:          // Check for backspace
  56:          KeyText.Text = KeyText.Text.Substring(0, KeyText.Text.Length - 1);
  57:        }
  58:      }
  59:   
  60:      private void KeyExtender_KeyUp(object sender, KeyCodeEventArgs e) {
  61:        // Demonstrates KeyCode event arguments Key and TextValue
  62:   
  63:        // Show which key was pressed
  64:        if (e.Key == KeyCode.Shift) {
  65:          MouseMode.Text = "Mouse Mode: Drag";
  66:        }
  67:      }
  68:   
  69:      private void DragExtender_StateChangeStart(object sender, StateChangingEventArgs e) {
  70:        // Demonstrates how to cancel an event in order to combine two MouseMovementExtenders
  71:   
  72:        // If not holding shift, allow dragging
  73:        e.CancelEvent = _keyExtender.IsShiftDown;
  74:      }
  75:   
  76:      private void RotateScaleExtender_StateChangeStart(object sender, StateChangingEventArgs e) {
  77:        // Demonstrates how to cancel an event in order to combine two MouseMovementExtenders
  78:   
  79:        // If holding shift, allow rotate/scale
  80:        e.CancelEvent = !_keyExtender.IsShiftDown;
  81:      }
  82:   
  83:      private readonly FillContainerExtender _fillContainerExtender;
  84:      private readonly KeyExtender _keyExtender;
  85:      private readonly DragExtender _dragExtender;
  86:      private readonly RotateScaleExtender _rotateScaleExtender;
  87:   
  88:    }
  89:  }

Sunday, July 13, 2008

New Job Opportunity

I recently received a package in the mail containing the following letter:
Mr. Stephen A. Commisso: We at Thompson Checkwriter Co., Inc. are in the process of upgrading our computer system. We have been looking into many different options, and think we have found the most useful, top of the line system. We elclosed[sic] a diskette with the program we plan on upgrading to, and a booklet that outlines its use. We have never been in the computer business, and we do not know anything about how to use them. We are in need of training. We have heard your name around the industry, and we would be honored to have you come to our company and train our employees how to use this top of the line system. We will pay top dollar for your services. We will need you to set up the system, and train our employees on its use and how it can improve our company. Thank you very much for your consideration, and we will be earnestly awaiting your response.
Wow, sounds promising! Here are the contents of the package: I don't know, I think I should take it... I'll keep these on my desk at work from now on and see if anyone notices. I only wish I could use these disks. If only I had a copy in 9 1/2"... My brother has a great sense of humor.