0

So, I have implemented a stateful Wcf Service self-hosted inside a windows service.
I use this service as a remote hardware driver (kind of).
As the service has to force serialed access to the underlying hardware, I set the service as a unique single instance with the attribute:

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]

It works correctly but now i want to have Castle manage dependencies for me, and here troubles start.
I found out that dependency injection and Single Instance Mode do not work well together (here is a reference, but you can find many more googling)...

Please note that I cannot use standard singletons provided by Castle as I need a different instance for every device installed in the system (there can be multiple at the same time). So using Castle default lifetime is not an option for me.

EDIT
As requested, I added the code I use to register and resolve the service, even if I think it's quite standard and there is nothing to underline.
This is the code I use to register the service:

container.Register(Component.For<IMyService>().ImplementedBy<MyService>().LifeStyle.Transient);

And this is the code I use to resolve the service:

public ServiceHostBase Build<T>(SelfHostConfiguration configuration)
{
    // Service configuration is done by code, not by App.config
    Uri[] uris = configuration.Select(e => e.Uri).ToArray();

    var serviceName = typeof(T).AssemblyQualifiedName;
    DefaultServiceHostFactory factory = new DefaultServiceHostFactory();
    var serviceHost = factory.CreateServiceHost(serviceName, uris);
    return serviceHost;
}

Nothing special, really, still maybe it'll be useful.

The question: is there anybody that was able to make Castle and InstanceContextMode.Single work together? Is it even possible?
Can you share your solution/ideas?

Community
  • 1
  • 1
andreapier
  • 2,958
  • 2
  • 38
  • 50
  • If Windsor is providing your instances, do you need to still specify this attribute? As discussed in the other question you reference, Singleton is the default life cycle for Windsor so simply removing the attribute should mean there is only a single instance of your service. – Phil Degenhardt Sep 24 '15 at 01:04
  • Yes I do, because I have N different service instances (say 5), and each one drives one specific peripheral. If I use Castle's singletons I get the same service instance instead of 5 different instances. I added a brief explaination to the question. thanks for pointing this out – andreapier Sep 24 '15 at 13:43
  • Ok. Can you please show your registration code? It will help to see how these multiple instances are registered with Windsor. – Phil Degenhardt Sep 24 '15 at 22:32
  • @PhilDegenhardt Added code – andreapier Sep 25 '15 at 07:55
  • 1. You are registering a singleton with Castle, not one instance per device. 2. You are not using Castle to resolve the service. – Phil Degenhardt Sep 25 '15 at 21:13
  • The simplest way to integrate Windsor with WCF is to use WCF Facility. – Phil Degenhardt Sep 25 '15 at 21:15
  • 1. I'm registering with transient lifestyle, so a new instance is returned each time a resolve is called. There is no Castle singleton unless I'm missing something. 2. Why not? 3. I'm already using Wcf facility.... I think code is better than words, can you provide some sample? – andreapier Sep 28 '15 at 07:40
  • Apologies. Was reading the code on my phone and missed the lifestyle-transient. I believe the point in my answer still stands though: using the ServiceBehavior attribute with InstanceContextMode.Single will cause Windsor to be bypassed. – Phil Degenhardt Sep 28 '15 at 07:59
  • You say you need one instance per peripheral. How are you discovering the peripherals? Are they definitively known at deployment-time, start-up-time or at run-time? – Phil Degenhardt Sep 28 '15 at 08:20
  • 1
    Then you will register a singleton instance per device at startup time. Since you will have multiple instances of IMyService you will need to make sure they are named and then you will use these names when configuring your WCF Facility to create an endpoint for each. – Phil Degenhardt Oct 06 '15 at 00:00
  • @PhilDegenhardt This is a great idea! I succesfully implemented it and it works very well. If you put it in an answer I will be glad to set it as the correct one. Thank you very much, I didn't think about it! – andreapier Oct 12 '15 at 06:37

1 Answers1

1

When using the WCF Facility you should remove the ServiceBehavior attribute and rely upon Windsor to manage your service instance lifecycle. If you set the InstanceContextMode to Single it will cause WCF to use its own instance management and effectively bypass Windsor.

The default instance context mode in WCF will vary depending on the binding (usually PerSession or PerCall) but in most cases it should work properly with whatever life style you specify when registering with Windsor/WCF Facility.

UPDATE

Assuming that the details about each device you want to expose consist only of 'name' and 'port' and that those details can be discovered at start-up time, you could register and expose a singleton service for each device as follows:

var devices = GetDevices();
foreach (var device in devices)
{
    container.Register(
        Component.For<IMyService>()
            .ImplementedBy<MyService>()
            .Named("MyService:" + device.Name)
            .LifestyleSingleton()
            .DependsOn(Dependency.OnValue("devicePort", device.Port))
            .AsWcfService(new DefaultServiceModel()
                .AddEndpoints(
                    WcfEndpoint
                        .BoundTo(binding)
                        .At(new EndpointAddress("net.tcp://localhost/MyService/" + device.Name)))
            ));
}
Phil Degenhardt
  • 7,215
  • 3
  • 35
  • 46
  • So your suggestion is to implement my own lifestyle... I tried and had a hard time. the docs seems to point out it's a very trivial task, but I couldn't make it work. I think I'll need some way to say if I'm asking for a new instance or an already existing one, and I really don't know how to do it. Can you share some code please? – andreapier Sep 25 '15 at 07:57
  • Also, I don't see the point of the link to the docs you provided... It has nothing to do with lifestyles... Maybe you wanted to link some other page? – andreapier Sep 25 '15 at 08:01
  • The link was to the page that says you should remove the attribute if using WCF Facility. – Phil Degenhardt Sep 25 '15 at 20:57