10

I have a WCF service that implements two service contracts...

public class MyService : IService1, IService2

and I am self-hosting the service...

host = new ServiceHost(typeof(MyService));

Everything was working fine when the service implemented only one service contract, but when I attempt to set up autofac to register both like this:

host.AddDependencyInjectionBehavior<IService1>(_container);
host.AddDependencyInjectionBehavior<IService2>(_container);

... it throws an exception on the second one, reporting:

The value could not be added to the collection, as the collection already contains an item of the same type: 'Autofac.Integration.Wcf.AutofacDependencyInjectionServiceBehavior'. This collection only supports one instance of each type.

At first glance I thought this was saying my two contracts were somehow being seen as the same type but on second reading I believe it is saying that the AutofacDependencyInjectionServiceBehavior is the type in question, i.e. I cannot use it twice!

And yet, I found this post that explicitly showed using it multiple times in a slightly different form:

foreach (var endpoint in host.Description.Endpoints)
{
  var contract = endpoint.Contract;
  Type t = contract.ContractType;
  host.AddDependencyInjectionBehavior(t, container);
}

Unfortunately, that gave the very same error message.

Is it possible to register more than one service contract on one service and, if so, how?

Community
  • 1
  • 1
Michael Sorens
  • 35,361
  • 26
  • 116
  • 172

2 Answers2

7

In fact you can register multiple endpoint for a single host with Autofac.

That is true that you cannot add multiple AutofacDependencyInjectionServiceBehavior but this behaviour iterates through all the endpoints and registers them in the ApplyDispatchBehavior method: source

In order to make this work you need to register your service AsSelf()

builder.RegisterType<MyService>();

Then you can configure your endpoint normally:

host = new ServiceHost(typeof(MyService));
host.AddServiceEndpoint(typeof(IService1), binding, string.Empty);
host.AddServiceEndpoint(typeof(IService2), binding, string.Empty);

And finally you need to call the AddDependencyInjectionBehavior with the sevicehost type itself:

host.AddDependencyInjectionBehavior<MyService>(container);

Here is a small sample project (based on the documentation) which demonstrates this behavior.

nemesv
  • 138,284
  • 16
  • 416
  • 359
0

Update (the bold text) based on @nemesv's answer:

Further investigation revealed that with autofac one cannot register multiple endpoints on a single ServiceHost if one registers the WCF service contracts. (See @nemesv's answer for the correct way to do it.)

Here is why:

Either form of this extension method...

host.AddDependencyInjectionBehavior<IService1>(_container);
host.AddDependencyInjectionBehavior(t, container);

...resolves down to adding a ServiceBehavior (according to Alex Meyer-Gleaves initial announcement of WCF integration in autofac)...

host.Description.Behaviors.Add(behavior);

Now this Behaviors property is an instance of KeyedByTypeCollection<TItem>, which can hold only only one object of a given type. Since the behavior being added will always be an instance of AutofacDependencyInjectionServiceBehavior, one can therefore only add one endpoint.

QED

The workaround is to use multiple ServiceHosts, each with a single endpoint.

(As a point of interest, I would be curious to know the impact on performance and scalability between those two approaches.)

Michael Sorens
  • 35,361
  • 26
  • 116
  • 172
  • Wouldn't inheriting from AutofacDependencyInjectionServiceBehavior and readding instance of that help? – Arek Bal Dec 23 '16 at 22:14