HowTo: Registering services through configuration

Topics: User Forum
Apr 4, 2007 at 5:26 PM
Edited Apr 4, 2007 at 9:12 PM
Julian and I have written an article that discusses one possible way to register services through configuration. This is one of the requested features for WCSF (see WorkItem 7540). Please let us know what you think about it and if it fulfills your expectations.

How-To: Registering services through configuration in WCSF


Julián Domínguez
http://staff.southworks.net/blogs/jdominguez

Ezequiel Jadib
http://staff.southworks.net/blogs/ejadib

Apr 4, 2007 at 7:39 PM
I won't get a chance to play with the extension until this evening, but it looks like a good first step that addresses a big problem in extensibility IMHO.

You didn't mention this in the article - any reason why you didn't provide the ability to register services to a particular module? Right now everything is a global service.

Just to confirm, all dependency injection still occurs as normal, correct?

If I register a couple of service like:

<services>
   <service registerAs="MyInterfaces.IMyService, MyInterfaces" type="MyImplementations.MyService, MyImplementations"/>
   <service registerAs="MyInterfaces.IMyService2, MyInterfaces" type="MyImplementations.MyService2, MyImplementations"/>
</services>

and MyService2 depends on IMyService:

Public class MyService2(IMyService service)
{
   // ...
}

everything will be injected properly?

And just to brainstorm with you, I often have dependencies on settings in web.config and primitive types:

<services>
   <service registerAs="MyInterfaces.IMyService, MyInterfaces" type="MyImplementations.MyService, MyImplementations">
      <property name="connectionString" value="Data Source=...." />
   </service>
</services>

with the MyService constructor looking like:

public class MyService(string connectionString)
{
  // ...
}

It is often useful to just refer to a value in AppSettings in those cases.

Anyway, I like the way it looks and will definitely try it out later. I would love to see additional enhancements, but this looks like a great start.

Regards,

Dave

_____________________

David Hayden
Microsoft MVP C#
Apr 4, 2007 at 9:12 PM
Hi David, thank you for your feedback, it's very valuable to us.
As you correctly said, the dependency injection ocurrs normally, and sequentially (if MyService2 depends on MyService1, they should appear in the correct order for them to work properly).

Regarding the second comment about primitive types:
CAB implements something similar to this, but not that similar. If we should add this enhancement, I think that the best way is to imitate CAB's behavior in this. The config file should result in something of this sort:
<services>
   <service registerAs="MyInterfaces.IMyService, MyInterfaces" 
            type="MyImplementations.MyService, MyImplementations" 
            connectionString="Data Source=..." />
</services>

But the main difference with your suggestion, is the way MyService should be implemented. Instead of adding these configuration parameters to the constructor (this would require doing lots of changes, as ObjectBuilder could not automatically create an instance using this constructor), the service could implement an interface (it could be the same as Microsoft.Practices.CompositeUI.IConfigurable that comes with CAB) that takes care of this. After the service is built with ObjectBuilder, we could then call the IConfigurable.Configure method, passing a NameValueCollection to the service.

As for the comment on registering a service as a Module service, what we thought when we made that, is that if you need a particular service for a module, that module would be coupled in some way with the service, and didn't find it that useful for a service implementation to be switched without rebuilding, but of course, we could be wrong, as you are already suggesting this :)
To allow this, we should change some configuration classes from CWAB (not really change them, but rather use a different ModulesConfigurationSection implementation) and we wanted to avoid this until we get some feedback from the community and realize this is the way to go.

Julián Domínguez
http://staff.southworks.net/blogs/jdominguez
Apr 4, 2007 at 11:38 PM
Edited Apr 4, 2007 at 11:39 PM
Hi Julián,

Thanks for the tip that services are required to be registered in a particular order based on dependencies. I assume this means you instantiate services as you read them from configuration and don't have a feature or plan to build a feature that discovers dependencies and instantiate services in the correct order. This would also suggest that adding services both programmatically and via configuration that have inter-dependencies could be problematic.

I am cool with adding properties on the service tag. Saves me a bit of typing and looks better.

That is an interesting limitation of ObjectBuilder you mention. I typically like constructor injection as it better describes the required dependencies. Setter injection and use of IConfigurable imply optional dependencies. I would prefer not to use IConfigurable and go with standard dependency injection practices, but if you are limited by ObjectBuilder what choice do you have. I realize it is also important to be consistent between both the Web Client and Smart Client implementations. I am just a little surprised you didn't get a bit of pushback from the CAB developers implementing IConfigurable.

As far as registering local services, it is important because often you provide a global service for say caching, but you want the ability to allow modules to implement their own implementation. The Caching Interface is the same, but the process is that the module will first look at its collection of services for an implementation first, and if not found, look to a default global implementation. This gives us a nice way to override global services in certain modules and still allow other modules to use the default global service. I think it is a nifty feature and perhaps use it more than others.

Regards,

Dave

_________________________

David Hayden
Microsoft MVP C#