Home >

Castle ServiceIdResolver

19. November 2008

I like Castle, a lot. The thing that I like about it is not only its clean api&design, but also the extensibility points it has.

Sometimes, there are cases when you need to resolve a type that is not registered in the container. Such examples for those cases may be an array of all services of a specific type. An example to this can be found at hammet’s post

This post will be an answer to a question raised in the Castle Project User List.

The question is that he needs his service to be aware of his Id registered in windsor. This is possible with the use of ISubDependencyResolver. Even though this design seems violation of SoC, I believe that it will demonstrate the ISubDependencyResolver well enough.

Tests are first, here they are

public class SampleService1
{
    public SampleService1(string serviceId)
    {
        this.ServiceId = serviceId;
    }
    public string ServiceId { get; set; }
}
public class SampleService2
{
    public SampleService2(string serviceId)
    {
        this.ServiceId = serviceId;
    }
    public string ServiceId { get; set; }
}
public class SampleService3
{
    public SampleService3(int serviceId)
    {
        this.ServiceId = serviceId;
    }
    public int ServiceId { get; set; }
}
public class ServiceIdResolverTests
{
    public ServiceIdResolverTests()
    {
        this.container = new WindsorContainer();
        this.container.Kernel.Resolver.AddSubResolver(new ServiceIdResolver());
        this.container.Register(Component.For<SampleService1>().Named("service1"))
            .Register(Component.For<SampleService2>().Named("service2"))
            .Register(Component.For<SampleService3>().Named("service3"));
    }
    private readonly IWindsorContainer container;

    [Fact]
    public void CanResolveDependencyWithServiceId()
    {
        var s1 = container.Resolve<SampleService1>();
        var s2 = container.Resolve<SampleService2>();
        Assert.Equal("service1", s1.ServiceId);
        Assert.Equal("service2", s2.ServiceId);
        Assert.Throws<HandlerException>(() => container.Resolve<SampleService3>());
    }
}

Now comes to the implementation.

ISubDependencyResolver has 2 simple methods, namely CanResolve and Resolve. CanResolve tells the container that this resolver may handle the operation of resolving and resolve does the real work.

We should define a convention here, about when to resolve a dependency with the service’s id. My convention is if the parameter name is “serviceid”, then this means that the service wants to know about his id.

public class ServiceIdResolver : ISubDependencyResolver
{
    #region ISubDependencyResolver Members
    public bool CanResolve(CreationContext context, ISubDependencyResolver parentResolver,
                            ComponentModel model, DependencyModel dependency)
    {
        return dependency.DependencyKey.ToLowerInvariant().Equals("serviceid") &&
               dependency.TargetType == typeof(string);

    }
    public object Resolve(CreationContext context, ISubDependencyResolver parentResolver,
                            ComponentModel model, DependencyModel dependency)
    {
        return model.Name;
    }
    #endregion
}

In CanResolve method, we tell the container that we are able to resolve a dependency only when it is service id, and in the Resolve method we return that dependency to be the service id.

There are still missing points in the code, we should also check if this parameter is defined somewhere in configuration. If that is the case, we shouldn’t resolve it on our own, but leave the container handles this.

Very easy isn’t it?

kick it on DotNetKicks.com

, , ,

Comments

11/20/2008 1:46:30 PM #
Tuna, great info!

As usual all of this might seem easy, when you know your way around and understand what everything means. I did not have a lot of material to look things up in and not the time to really dive deep into windsor source code to find out, what is supposed to be going on.
I did not know what 'dependency' meant in the context, much less what the 'dependency key' was, (dependency/component)'model' - no idea, ...! I intellisensed around, but did not reach a point, where I could come up something bearing real meaning. Even reading your code now, I do not understand why the resolve method should return the model's name.

So - little code, yes, but easy, I wouldn't bet on it.

In the end I passed in a serviceid (==id) as a parameter and resolved by that, no subresolvers involved, just a service with a IKernel reference. Suboptimal for sure, but easy to understand one year from now.

And I am unsure, if your solution actually can do, what I was asking for at the list - to get something like
IDictionary<string, IOrderRule> ResolveAllWithKey()

But thanks a lot for clearing this up a bit, I wish I would have found something like your example a little while back. It would have helped me a great deal!
11/20/2008 5:28:06 PM #
Hello Jan,

You are right in saying that without diving deep, this solution wasn't apperant and there isn't many info about it. This post's aim was to show how easy things can be once you get famiiar with the tool you are using, not saying "this is really easy, how didn't you find it".

This post was an answer to your first question, I missed the second one. If i can find time and how to do that in castle way, I promise I'll send another post telling about it.
11/21/2008 11:52:42 AM #
Trackback from DotNetKicks.com

Castle ServiceIdResolver
7/23/2010 10:41:37 PM #
Castle Custom Component Activators

Castle Custom Component Activators
11/21/2010 4:22:52 AM #
Looks easy to me. I like Castle too.
11/25/2010 10:59:19 AM #
thats good article!!
12/15/2010 4:40:14 AM #
We are also very happy to now offer web hosting services, regardless of whether or not you want us to build you a website;
There’s no need to go scouring the net for a great web hosting service to compliment your new site…
GFsoul does web hosting and takes care of all the important details like domain name registration.
Our design and hosting services perfectly compliment each other; we are offering customers true “one-stop shopping” experience, and at extremely affordable prices. You won’t find customized web design and hosting at these amazingly low prices anywhere buy here.
Our web hosting services features all of the same appointments that other (better known) web hosting services can offer you, but with lots of great tech support, customization and a lower overall cost.
1/7/2011 10:05:00 PM #
I have to say my english just isn t ok so Is there any articles about this topic in other languages? I really hope u will answer me in this subject.
1/10/2011 3:57:08 AM #
so easyyyyyy! just what I needed! thanks!C
3/19/2011 11:37:24 AM #
Awesome article you have written. I am currently looking for this kind of info
3/22/2011 7:13:00 PM #
I can't say that I agree with the article completely but I have still learned something from this piece.  Keep informing us.
3/22/2011 8:16:51 PM #
I see there is some very good information in this article. Please continue with the work that you are doing
3/22/2011 8:18:59 PM #
Great article! So happy to finally see a decent post about tis topic.  I will bookmark it so that I may come back and read more.
3/22/2011 11:44:11 PM #
It is actually hilarious you ought to write about this since I was initially just wondering about it the this past week. You've portrayed my views accurately. Good.
3/23/2011 11:20:21 AM #
Apple now has Rhapsody as an app, which is a great start, but it is currently hampered by the inability to store locally on your iPod, and has a dismal 64kbps bit rate. If this changes, then it will somewhat negate this advantage for the Zune, but the 10 songs per month will still be a big plus in Zune Pass' favor.
3/23/2011 4:25:06 PM #
thanks !!  very helpful post!
Comments are closed