Introduction to Services in the CAB (Introduction to the CAB/SCSF Part 7)

Introduction

Part 6 of this series of articles concluded our discussion of dependency injection in the CAB.

This article and part 8 of the series will discuss services in the CAB in some more detail. This article discusses services in general terms, whilst part 8 will show in detail the various ways of creating and using services.

What is a ‘Service’?

You probably already have an intuitive idea of what a ‘service’ is in computer programming. Wikipedia defines a service in the context of a Service-oriented architecture as ‘a discretely defined set of contiguous and autonomous business or technical functionality’. The CAB documentation defines a service as ‘a supporting class that provides functionality to other components in a loosely coupled way’. CabPedia has a good definition:

‘Services allow easy access to a chunk of functionality that may be used frequently throughout an application. Error handlers, loggers and the event broker are good examples of functionality that can be exposed as a service.’

So think of a service as a chunk of related functionality. In the CAB each service is exposed through one class (and maybe an associated interface) that provides a gateway into the functionality.

We have already seen how to use CAB services in earlier articles in this series. Part 2 described how one of the collection classes on a WorkItem is the Services collection. Part 5 showed how we can inject a service (which is just any item in the Services collection) by using a setter with a ServiceDependency attribute. We saw that we can inject the WorkItem itself in this way. This is because a WorkItem is automatically a ‘service’ in its own Services collection.

The Services Collection versus the Items Collection

Part 5 of this series of articles also touched on the fact that the Services collection on a WorkItem has some important differences with the Items collection. This is separate from the fact that the intent of the two collections is different: services are meant to be objects that expose chunks of related functionality, whereas items are just any objects that we want to be able to access through the WorkItem.

The differences between the collections can be confusing so I’ll start this discussion by comparing the two collections.

Services vs Items (1): Unique Types

The most obvious of these conceptual differences is the fact that the Services collection can only ever contain one object of a given type. If we attempt to add a second service of the same type to a Services collection we get an ArgumentException with message ‘A service of this type already exists’.

In contrast, the Items collection of a WorkItem can contain multiple objects of the same type. To accommodate this all objects added to the Items collection are assigned a unique string ID, either by the user explicitly, or by the CAB implicitly (a random GUID is assigned).

However, this means that if we want to access a specific object in the Items collection we have to know its ID. Hence the ComponentDependency attribute, which injects an object from the Items collection, needs an ID passed as an argument.

We don’t need an ID to access an object in the Services collection. Because we can identify a service uniquely by its type the ServiceDependency attribute can be used to inject a service without the need for any ID.

Services vs Items (2): Searching the Hierarchy

Another difference between the Services collection and the Items collection is what happens if we request a specific object from the collection and the CAB can’t find it in the WorkItem’s collection. When trying to retrieve a service the CAB will then search in any parent WorkItem’s Services collections for the object, and return it if found. With the Items collection the CAB will just return null if the object cannot be found in the specific Items collection for the WorkItem.

Basic Service Example without Dependency Injection

A simple example of how to create and use a service without using dependency injection is available. The ‘service’ here is just one class (MyService) with one method (GetHello) that returns the string “Hello World”:

    public class MyService
    {
        public string GetHello()
        {
            return "Hello World";
        }
    }

We can make this simple class into a CAB service by adding it to the Services collection of a WorkItem. In this case we add it to the Services of the RootWorkItem in AfterShellCreated:

        protected override void AfterShellCreated()
        {
            RootWorkItem.Services.AddNew<MyService>();
            UseMyService();
            ...

We use the service in routine UseMyService. Here we retrieve the service using the Get method of the Services collection, telling it the type of the service we want to retrieve. We then call our method and output the results to the Output window:

        private void UseMyService()
        {
            MyService service = RootWorkItem.Services.Get<MyService>();
            System.Diagnostics.Debug.WriteLine(service.GetHello());
        }

It’s as simple as that. The full code also outputs all of the services that have been set up in the application, and shows that our MyService service is in there. You can see that there are a surprisingly large number of services set up by default by the CAB even in a simple application of this kind:

SERVICES:
[Microsoft.Practices.CompositeUI.WorkItem, Microsoft.Practices.CompositeUI.WorkItem]
[Microsoft.Practices.CompositeUI.Services.ICryptographyService, Microsoft.Practices.CompositeUI.Collections.ServiceCollection+DemandAddPlaceholder]
[Microsoft.Practices.CompositeUI.ITraceSourceCatalogService, Microsoft.Practices.CompositeUI.TraceSourceCatalogService]
[Microsoft.Practices.CompositeUI.Services.IWorkItemExtensionService, Microsoft.Practices.CompositeUI.Services.WorkItemExtensionService]
[Microsoft.Practices.CompositeUI.Services.IWorkItemTypeCatalogService, Microsoft.Practices.CompositeUI.Services.WorkItemTypeCatalogService]
[Microsoft.Practices.CompositeUI.IWorkItemActivationService, Microsoft.Practices.CompositeUI.SimpleWorkItemActivationService]
[Microsoft.Practices.CompositeUI.Services.IAuthenticationService, Microsoft.Practices.CompositeUI.Services.WindowsPrincipalAuthenticationService]
[Microsoft.Practices.CompositeUI.Services.IModuleLoaderService, Microsoft.Practices.CompositeUI.Services.ModuleLoaderService]
[Microsoft.Practices.CompositeUI.Services.IModuleEnumerator, Microsoft.Practices.CompositeUI.Services.FileCatalogModuleEnumerator]
[Microsoft.Practices.CompositeUI.Commands.ICommandAdapterMapService, Microsoft.Practices.CompositeUI.Commands.CommandAdapterMapService]
[Microsoft.Practices.CompositeUI.UIElements.IUIElementAdapterFactoryCatalog, Microsoft.Practices.CompositeUI.UIElements.UIElementAdapterFactoryCatalog]
[Microsoft.Practices.CompositeUI.WinForms.IControlActivationService, Microsoft.Practices.CompositeUI.WinForms.ControlActivationService]
[Shell.MyService, Shell.MyService]

Splitting the Interface from the Implementation

As we all know, for services it is considered good practice to separate our interface from our implementation. This allows us to vary the way the service is implemented without having necessarily to change the interface and thus affect client code. This can be important in a composite smart client application where different teams may be working on different parts of the application.

This can be very easily done for our basic example. We simply set up an interface with our method signature in it:

    public interface IMyService
    {
        string GetHello();
    }

We then implement this interface on our MyService class:

    public class MyService : IMyService
    {
        public string GetHello()
        {
            return "Hello World";
        }
    }

Another change we need to make is how we create the service. We want the type associated with it in the Services collection to be IMyService, but clearly we need to tell the CAB that it is creating an object of type MyService (it can’t just instantiate the interface). The syntax for this is as below:

            RootWorkItem.Services.AddNew<MyService, IMyService>();

The UseMyService method now retrieves the service using the IMyService interface. It doesn’t need to know about the MyService class:

        private void UseMyService()
        {
            IMyService service = RootWorkItem.Services.Get<IMyService>();
            System.Diagnostics.Debug.WriteLine(service.GetHello());
        }
 

These are the only changes that need to be made. The code for this example is available.

Conclusion

That concludes our initial introduction to services in the CAB. Part 8 will show the various options for creating and using services in more detail.

References

CabPedia page on Services
http://www.cabpedia.com/index.php?title=Services

Wikipedia on Services in an SOA
http://en.wikipedia.org/wiki/Service_%28Systems_Architecture%29

9 thoughts on “Introduction to Services in the CAB (Introduction to the CAB/SCSF Part 7)

  1. I really enjoy reading your article. Here is my comment on the service issue. From what you described here, I can image that a service class must have a default constructor. Is that right?

  2. After I read your next article, it looks like that you can add a service with customized constructor by Add method.

  3. chudq. A service does not have to have a default constructor. The add method will construct a type that has parameters in the constructor, though they must be tagged either with a [CreateNew] or a [ServiceDependency] attribute. Once the builder which gets called by executing the add method sees those attributes it will know how to create a new instance or grab the specified service. You can also manually create an instance rather than having the add method do it and you can register that instnace. This allows you to manually invoke whichever constructor you choose.

    Regards
    Glenn

  4. CabPedia no longer available?

    When I try to surf to CabPedia, I get to a site called “siteground.com” saying that “The account is currently not active”. 😦

  5. I think this is the destination for the one’s who need proper & clear understanding Of CAB. Thanks a lot. Keep the good work going. .

Leave a reply to chudq Cancel reply