1

I have console host application. In here I use IoC container as provider of instance, and want to pass contract interface into ServiceHost constructor. Obviously, it says I can't do it with interfaces.

Why do ServiceHost even need it? I attach custom provider if he want to instantiate it! Even more, I don't want to pass instances into it - it should be by demand.

How to make ServiceHost only from interface (keep in mind all neccessary bindings already in IoC)?

Example:

var host = new ServiceHost(typeof(IMyContract), address);

So, basicaly, by specifying InstanceProvider you should aquire this behavior. But Microsoft forcefuly ask for concrete implementation type, even if I provided instance factory and may not have concrete implementation type!

Franz Wimmer
  • 1,418
  • 2
  • 18
  • 34
eocron
  • 5,589
  • 16
  • 40
  • Maybe a code example would be helpful and make your question clearer. – ead Jul 22 '16 at 09:07
  • Added code example. – eocron Jul 22 '16 at 09:31
  • I'm guessing this is WCF that you are using? You should clear that out. Also which IoC container you are using. If it is WCF and Unity you are using take a look at [this](https://msdn.microsoft.com/en-us/library/hh273093(v=vs.100).aspx) and [this](https://unitywcf.codeplex.com/). NuGet package can be found [here](https://www.nuget.org/packages/Unity.WCF.4/). – Michael Jul 23 '16 at 17:03
  • You maybe misunderstood. IoC basicaly means dependency resolving, so I want to resolve ServiceHost dependency on specific type by specifing only contract interface of it. In other words, InstanceProvider should do it by himself only, not ServiceHost by throwing some stupid exceptions from constructor. – eocron Jul 24 '16 at 15:46
  • It's still unclear what you're trying to inject and what the difficulties are. Asking "why" isn't productive, the answer is going to be _"Because it was designed that way"_. – CodeCaster Jul 24 '16 at 15:59
  • 1
    http://stackoverflow.com/questions/2454850/how-do-i-pass-values-to-the-constructor-on-my-wcf-service – Hans Passant Jul 24 '16 at 16:03
  • Last is exactly what reside at msdn. It will throw exception if I pass contract interface in constructor. – eocron Jul 24 '16 at 16:21
  • `ServiceHost` does not support given contract only. It needs an implementation. That is by design. In order to get this to work you need a custom `ServiceHost`, an `IInstanceProvider`, and an `IContractBehaviour`. See this [article](http://www.devtrends.co.uk/blog/introducing-unity.wcf-providing-easy-ioc-integration-for-your-wcf-services). – Michael Jul 30 '16 at 21:51
  • I managed to do this without implementation. By simply tracking bindings. So, I pretty much can write only contract name and IoC will do everything for me. – eocron Jul 31 '16 at 21:00

2 Answers2

0

The Problem

The constructor of ServiceHost takes either a class type or an existing instance of your service, where serviceType has to be a class with a parameterless constructor:

public ServiceHost(Type serviceType, params Uri[] baseAddresses);
public ServiceHost(object singletonInstance, params Uri[] baseAddresses);

The Solution

To use the latter constructor, your service implementation has to be marked with InstanceContextMode.Single as ServiceBehavior:

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class Service : IService
{
    // ...
}

Conclusion

Now you can use whatever injection container you like to create your service and your service can even have a constructor with parameters.

Example

public class DiscoveryService
{
    private readonly IService _service;

    private ServiceHost _serviceHost;

    public DiscoveryService(IService service)
    {
        _service = service;

        // ...
    }

    private void StartServerMode()
    {
        _serviceHost = new ServiceHost(_service);
        _serviceHost.Open();
        // ...
    }
}
Franz Wimmer
  • 1,418
  • 2
  • 18
  • 34
  • You didn't understand question. Main reason for IoC is to hide concrete implementation and lazy load some dependencies. By specifiyng Type or Instance in ServiceHost constructor you destroy one of this principles. – eocron Sep 13 '16 at 07:16
  • 1
    That's not correct. You can easily pass the service instance via an interface parameter to your ViewModel constructor (or whatever class you host your service in) and pass it to the ServiceHost. I added an example to my answer. – Franz Wimmer Sep 13 '16 at 08:11
  • 1
    Thanks, now I uderstand, you created bootstrap class. But, what about lazyness? When you start ~30 services, it can hurt a lot. Remember, service host creates instances of services only when it actually needed. – eocron Sep 13 '16 at 08:31
  • If the DI container creates the service class itself, it basically doesn't do anything (in my case, the constructor is nearly empty). Only when the ServiceHost is opened, the service will listen on the network for incoming requests. – Franz Wimmer Sep 13 '16 at 08:35
  • Yeap, and will create instance if someone touch it's API, through default factory, of course. But in this case you will load *everything* what passed into your service constructors on application startup. This is cold start problem. – eocron Sep 13 '16 at 08:41
  • This is a problem you can't solve in your WCF layer, your DI container has to handle this appropriately. – Franz Wimmer Sep 13 '16 at 08:43
0

The simple reason is internally ServiceHost has a method CreateImplmentation which will call the default constructor for the passed in type.

When you pass a interface as the type there is no constructor to call. It will not automatically search your program for imperilmenters of the interface, it is the responsibility of your code (or the DI library you use) to find those implementations and pass in the Type values for them.

One way you can make it search is by implementing a custom IInstanceProvider which will know how to resolve the type you passed in into a instance.

Scott Chamberlain
  • 116,967
  • 28
  • 260
  • 389
  • It will throw exception about invalid interface type BEFORE this type will be passed to provider. So, no, this won't work. – eocron Sep 13 '16 at 07:33