Geeks With Blogs

@adammmckee
  • adammmckee I have the best wife ever... She bought me Starcraft 2 and surprised me with it! about 1513 days ago
  • adammmckee Check out Kevin Israel at TriSPug on April 6th in Raleigh! It's speaking on SharePoint Search strategy http://bit.ly/1pAW2M about 1629 days ago
  • adammmckee @MLCarter1976 No problem at all, sir! Please let me know if have any other questions at all - I'm always happy to lend a hand :) about 1662 days ago
  • adammmckee @leniWaltz Sure - are you doing this from a workflow you are writing in VS, or a workflow you're designing in SharePoint Designer? about 1663 days ago
  • adammmckee @MLCarter1976 I'd check codeplex for SharePoint tag cloud solutions - lots to choose from. about 1664 days ago

Amusingly MOSS ...It's funny how difficult some stuff is when it really shouldn't be

If you’ve ever written a standard .NET ASMX web service before, you know the drill.  You make your service, build out your web methods, publish your service, make your consuming web project, point your project to your service via a web reference, and voila!  You get strongly-typed proxy classes auto-generated for your web service consumption pleasure…  But this comes at a great cost.  WSDL is slow, clunky, and bloated.  All that proxy code that is generated results in serializing, packaging, unpacking, and de-serializing data each way (not to mention the ludicrous amount of code generated to perform relatively simple operations).

A better approach, I think, is to create a web service architecture that gleans the best aspects of REST, and combine it with Spring.NET on the back-end to allow simple functionality extension.  And that is exactly what I intend to impart to you - a practical case study in doing exactly that.

Before I go any further, I want to talk briefly about the scope of what I'm trying to demonstrate.  This post is not intended to show you how dependency injection works, or even how to roll your own service architecture.  What I want to do is to walk you through a super-lightweight service implementation that we've created based on the dependency injection that comes with Spring.NET.  Yeah, I know, there are a million things that Spring.NET does, but I’m mostly interested in talking about dependency injection and one really practical use for it.
 
I’m Too RESTY For My Shirt

So, what made us choose a REST-ful service implementation?  Well, a few reasons:

  1. We’re interested in REST because of how the service call allows us to very simply extract what action is to be performed or what data is to be returned by the very nature of the call, as opposed to unpacking a SOAP semi truck just to retrieve a toothpick of instruction.
  2. REST service calls can very easily be constructed either from JavaScript or a server-side function, meaning that AJAX (or even server-side) calls can become very simple, and uniform. 
  3. You don't have to re-build a ginormous proxy class every time you change the functionality of your service - just change the query string on the service call, and away you go.

Before I dive in to how all of this marries up with Spring.NET, I feel that I should mention that I'm not using true REST – I'm only using the parts that make sense for the service implementation that I'm working with.  In particular, I'm only interested in GET (for fetching stuff) and POST (for doing stuff) verbs.  Conceivably, we could write actions for other common verbs, but you’ll see why we chose against it when we bring Spring.NET into the mix.

Is That a Spring in Your Code, or Are You Just Happy to See Me?

The purpose of using dependency injection in our service implementation serves two main purposes:

  1. To segregate and VERY loosely couple the different functions (verbs, resources, and response types) of our REST-ful service
  2. To make it easy to extend the functionality of the service to accommodate future requirements

Binding the Service Together

Before we dive into the code, there is a bit of terminology that I need to bring to your attention.  In the code, you'll see frequent reference to an object called a "binder."  This binder object is nothing more than a means of passing relevant data to and from various layers of the service.  It has the following members:

  • string Format - how the output of the service call is to be formatted (JSON, XML, etc.)
  • string Resource - dictates what resource is to be queried (labor, employees, parts, etc.)
  • string Action - what is to be done to the resource (getAll, getById, getSomethingMeaningful, etc.)
  • Dictionary<string, object> LocalData - Holds any single values that need to passed from one layer to the next that doesn't fall into one of the above properties
  • DataSet ResultSets - any recordsets to be passed to the response handler to be translated to JSON, XML, or whatever is dictated by the Format property. 
  • HttpContext Context - object reference to the current HttpContext other layers of the service can see it without having to trying to fetch the context themselves.

Now that we've cleared that up, let's explore some code to see what the service is really going to do when it gets a request.

The Service, Top-to-Bottom

Here's what a request to the service might look light:

http://svc.mycomany.com/servicehandler.ashx?resource=labor&action=get&id=1

What this does is tell the service everything it needs to know to fetch a results set.  A results set might be a scalar value, or an entire recordset.  In this case, the expected result will be a single labor record whose Id is We'll be following this example throughout the rest of this tutorial.

   public class ServiceHandler : IHttpHandler
   {
        public void ProcessRequest(HttpContext context)
        {
            // Create an instance of the Spring.NET application context
            IApplicationContext ctx = ContextRegistry.GetContext();

            // Create a binder object
            IBinder binder = (IBinder)ctx.GetObject("binder");
            binder.Context = context;
           
            // Default to JSON format (response)
            string format = "json";

            try
            {
                string resource = null;
                string action = null;

                HttpRequest request = context.Request;
                format = request["Format"];
                resource = request["Resource"];
                action = request["Action"];

                // An error should be thrown if no resource is provided in the service call
                if (Resource == null)
                {
                    throw new Exception("Resource was not found");
                }

                // An error should be thrown if no action is provided in the service call
                if (Action == null)
                {
                    throw new Exception("Action was not found");
                }

                binder.Format = format;
                binder.Resource = resource;
                binder.Action = action;
               
                // Call Spring.NET to get the appropriate request handler, based on the named passed in from the query string
                IServiceRequestHandler requestHander = (IServiceRequestHandler)ctx.GetObject(resource.ToLower() + "requesthandler");
               
                // Call the appropriate IServiceRequestHandler method, based on the RequestType of the call to the service
                switch (request.RequestType.ToLower())
                {
                    case "get":
                        requestHander.Get(binder);
                        break;
                    case "post":
                        requestHander.Post(binder);
                        break;
                }

            }
            catch (Exception e)
            {
                binder.SetLocal("error", e.Message);
            }

            IServiceResponseHandler responseHandler = (IServiceResponseHandler)ctx.GetObject(Format.ToLower() + "responsehandler");

            responseHandler.binder = binder;
            responseHandler.write();
        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }


The service handler is designed to digest any call to servicehandler.ashx, break apart its request parameters, and determine what to do.  After it breaks down the request and creates a binder, it calls Spring.NET to get an IRequestHandler based on the name of the resource.

Let's take a look at what the LaborRequestHandler class looks like:

    public class LaborRequestHandler : IServiceRequestHandler
    {

        public IBinder Get(IBinder binder)
        {
            IApplicationContext ctx = ContextRegistry.GetContext();
            IServiceAction action = (IServiceAction)ctx.GetObject(binder.Action.ToLower() + binder.Resource.ToLower() + "serviceaction");
            action.execute(binder);

            return binder;
        }

        public IBinder Post(IBinder binder)
        {
            IApplicationContext ctx = ContextRegistry.GetContext();
            IServiceAction action = (IServiceAction)ctx.GetObject(binder.Action.ToLower() + binder.Resource.ToLower() + "serviceaction");
            action.execute(binder);

            return binder;
        }
    }


By the time this class is instanced by the ServiceHandler, the ServiceHandler has determined the RequestType (GET or POST), and has determined that the Labor resource is necessary, and has instanced the proper IServiceRequestHandler (LaborRequestHandler, in this case).  In this class, the action taken will be resolved down to an actual IServiceAction implementation, which then gets passed the binder instance, and executed.

You'll notice that both the Get and Post methods are identical - this is circumstantial.  In this case, it happens that no further binder processing is necessary at this point, but this may not always be the case.  This is why we've added this layer of abstraction into the mix, to allow for request type-specific processing at this level.

Note: The execute method returns a Binder - the implementation of the execute method on the IServiceAction will put any results into the binder, and pass it back up to the ServiceHandler for formatting into the output for the original service call from the client.

Here's what the GetLaborServiceAction looks like:

    internal class GetLaborServiceAction : IServiceAction
    {
        public GetLaborServiceAction()
        {
        }

        public bool execute(IBinder binder)
        {
            try
            {
                DataTable results = null;

                // Your code here to fetch single labor record into the results DataTable

                binder.addResultSet("Labor", results);

                return true;
            }
            catch (Exception e)
            {
                // Perhaps some logging here
                throw e;
            }
        }
    }

Once the database code has been executed and put back into the binder, the ServiceHandler will then instance the proper IServiceResponseHandler (JSONResponseHandler in this case), and call the write method.  The write method will take the binder that was populated with data, and convert it into the appropriate format (JSON, in this circumstance).

The Beauty of It All

Now that you've seen how it all works, let's take a step back and think through some of the implications of using DI in this service.

Let's say that you have a requirement for a new, specialized get method - one that gets all Labor rates that are only available on Tuesdays.  Here's all you'd have to do:

  1. Write your stored procedure to actually fetch the data
  2. Create a GetLaborRatesForTuesdays : IServiceAction class, and flesh out the execute method to call the stored procedure
  3. Update your Spring.NET configuration to accommodate the new class

POOF!  You're done!  Your service has entirely new functionality, and you didn't have to touch any existing code.  Using this methodology, you could also create IServiceRequestHandler implementations for other verbs, but that's up to you.  We didn't use them here because we would end up with a lot of classes that had identical code, and it would mean more complex code on the client-side to know which verb to call - it was a lot easier just to use GET and POST on all fronts.

Speaking of client code, here's the best part:  Your client code doesn't have to change one bit to accommodate this new functionality.  In order to call this new method, all you have to do is slightly alter your query string to look like this:

http://svc.mycomany.com/servicehandler.ashx?resource=labor&action=getLaborForTuesdays

That's it!  Purty, eh?

So, Adam, How Do We Wrap This One?

Without a shadow of a doubt, bust...  oh wait, you mean me, not Adam Savage.

This is just one way to go about doing this.  The implications go way deep and way wide - there are lots of ways to make this even better.  For example, there's an entire DAO layer that I left out of this implementation - I felt it would have added a bit of complexity that would have detracted from the scope I was trying to maintain.

I'll be posting other thoughts I have on the matter as I come across them - there is so much here to learn.

Posted on Sunday, July 5, 2009 3:14 PM Systems Architecture and Design | Back to top


Comments on this post: Service Architecture Using Spring.NET

# re: Service Architecture Using Spring.NET
Requesting Gravatar...
This is a really good intro article to the use of Spring.NET and RESTful service writing. The humor is spot on, and the level of introductory explanation is great.
I see 2000+ job openings with "Spring" in them, for the Java crowd, can .NET developers wean themselves off of the Microsquish Enterprise Application Blocks or Enterprise, whatever flavor-of-the release ... to build scalable, reliable architectures ?? Time will tell. Great job!
Left by Marty Mazurik on Feb 19, 2010 8:36 AM

# re: Service Architecture Using Spring.NET
Requesting Gravatar...
Hey, thanks for the comments, Marty!

Yeah, I generally steer clear of the MS application blocks - they try to provide a means for every possible permutation of all scenarios, which ends up being more code than you can shake a stick at.

Thanks again for reading!

Cheers,
Adam
Left by Adam McKee on Feb 19, 2010 9:52 AM

# re: Service Architecture Using Spring.NET
Requesting Gravatar...
The humor is spot on, and the level of introductory explanation is great.
I see 2000+ job openings with "Spring" in them, for the Java crowd, can .NET developers wean themselves off of the Microsquish Enterprise Application Blocks
Left by Joey on Aug 10, 2010 12:43 AM

Your comment:
 (will show your gravatar)
 


Copyright © Adam McKee | Powered by: GeeksWithBlogs.net | Join free