
Components, services and dependencies
Service
Service in Windsor and WCF service
The term service is extremely overloaded and has become even more so in recent years. Services as used in this documentation are a broader term than for example WCF services.
Services in Windsor lingo, are abstract contracts describing some cohesive unit of functionality. An
IErrorNotificator or
IUserRepository could be examples of services you might use in your application.
Component
A component is a small unit of reusable code. It should implement and expose just one service, and do it well. In practical terms, a component is usually a class that implements the service interface(s). For example an
EmailErrorNotificator class would be implementation of a component exposing
IErrorNotificator service. The interface is the service's contract. It creates an abstraction layer so that your other components, depending on the given service, are decoupled from their implementation. This enables your code to change more rapidly, there by, limiting the impact of these changes. An additional side-benefit is that you can replace the service's implementation without effort. In some (rare) cases the class itself may be the service, when additional abstraction is unnecessary.
class != component (advanced stuff)
If you're just starting with Windsor, it may be convenient at first to think a class is a component. While often your will create single component based on single class that's not always the case. You can have many components based on a single class (for example if your application is accessing multiple databases your
UnitOfWork class may end up being used to create a component for each of the databases) and you have have a single component built from multiple classes (via mixins), although that's extremely rare.
So just keep in mind that while putting equality between
class and component may be helpful when learning the concepts, it's not exactly true.
Dependency
Dependency is another service or parameter that a component uses in order to do its job. In Windsor, dependencies are either constructor parameters, writeable properties, or custom, like
Interceptors, mixins etc.
The picture on the right shows a concrete example of how that concept looks in real life.
CustomerRepository is a class that we register as a component in the container. It exposes one service -
IRepository<Customer>. It also has one mandatory dependency -
IUnitOfWork and one optional dependency -
ILogger.
What makes a good component?
You should not register all your classes in the container, only the classes that expose services to the system. Most classes in a system might represent data but not services. Although it is not common, a service might have state.
To make the distinction clear, consider the following classes:
public class CustomerDataAccess
{
public void Insert(Customer customer)
{
// Generate SQL and execute it
}
public void Update(Customer customer)
{
// Generate SQL and execute it
}
public void Delete(Customer customer)
{
// Generate SQL and execute it
}
}
public class Customer
{
public int Id { get ; set; }
public string Email { get ; set; }
public string Name { get ; set; }
}The former provides a service to the system: it handles data access for an entity. The latter represents a Customer, it is basic data and should not be registered on the container.
Component and service relation¶
In real application you wouldn't use the
CustomerDataAccess component as it is defined above. It does not implement an interface, so its only service is itself. Services should be (in most cases) abstract contracts, so it would be preferable to refactor the component to extract an
ICustomerDataAccess interface and expose it as a service, instead of the concrete class type.
public interface ICustomerDataAccess
{
void Insert(Customer customer);
void Update(Customer customer);
void Delete(Customer customer);
}