2

A class has a unique constructor taking IMyInterface as its argument. If I define a concrete type of IMyInterface and registers it to StructureMap then there is no issue and my class can be instanciated with this concrete type.

However, in some cases, no concrete type will be registered. In that case, I would like to receive null for the IMyInterface parameter. Instead I get an exception:

StructureMap Exception Code: 202 No Default Instance defined for PluginFamily IMyInterface.

Is it possible to define a default value for a missing plugin?

Context: my class, which is a service, uses the Spark view engine and defines some default namespaces. The service uses a ISparkNamespacesProvider (IMyInterface) to add aditional namespaces. The client app may register such a provider or not. That's why the constructor of the service will receive either a provider or none.

Nicolas Cadilhac
  • 4,680
  • 5
  • 41
  • 62

2 Answers2

2

Taken from here:

For<IService>().Use<MyService>()
 .Ctor<IMyInterface>("nameOfParameter").Is(null);

But You should think about why Your class is dependent on IMyInterface. If it's optional - that's a code smell. Maybe You should refactor it out as method argument for method that needs it or as settable property.

There shouldn't be need for switching between concrete implementation and null. When composing dependency graph at composition root, You should know exactly what will be Your dependencies w/o .If(isSomething()).Use<MyService>().Ctor<IMyInterface>(null).

You might want to check out this tekpub presentation and this book (look for so called MEAP access) about DI and IOC.


One way to accomplish what You want is using so called 'poor man dependency injection'. That is - to define second constructor:

public MyClass():this(null){...}

But I wouldn't recommend that.

Community
  • 1
  • 1
Arnis Lapsa
  • 45,880
  • 29
  • 115
  • 195
  • 1
    null has to be cast to IMyInterface to avoid an ambiguous call. And unfortunately it doesn't work. When I define a concrete type and registers it to SM, null is still passed. So it seems your code does not define a default param but a forced value for this param. If I remove your code, the concrete type is used. – Nicolas Cadilhac Oct 06 '10 at 21:33
  • @Nicolas There should be only one concrete implementation specified at configuration. Otherwise - Your design quite likely is wrong. – Arnis Lapsa Oct 06 '10 at 21:35
  • @Nicolas maybe You could post here class that takes `IMyInterface`? Constructor and part that uses `IMyInterface`. – Arnis Lapsa Oct 06 '10 at 21:37
  • @Nicolas why exactly there are cases where concrete implementation is unknown? – Arnis Lapsa Oct 06 '10 at 21:38
  • I'm not switching between null or a concrete type dynamically. At init time, I either define a concrete type or none (in other terms, client app A will define one, and client app B will define none). – Nicolas Cadilhac Oct 06 '10 at 21:43
  • @Nicolas So - there are 2 composition roots. Client app A should have it's own structuremap registry, separated from client app B (they can have shared parts to avoid dupe code). That does not eliminate my doubts that optional dependency shouldn't be passed through ctor though. – Arnis Lapsa Oct 06 '10 at 21:47
  • I can't define a second constrcutor like that. SM would choose the first one except if I force it to always should the second one. – Nicolas Cadilhac Oct 06 '10 at 22:06
  • Yeah, that part of my answer is wrong. Anyway - You should definitely write 2nd composition root and consider if that dependency is really dependency for whole class. – Arnis Lapsa Oct 06 '10 at 22:10
  • @Arnie - "There should be only one concrete implementation specified at configuration. Otherwise - Your design quite likely is wrong." Huh? One of the great things about interfaces is that it allows you to vary behavior without the consumer knowing about it. That said, I think wanting to pass null in some cases is a code smell, if anything you might want to implement a null version of the interface, much like your might have a null log writer that does nothing. See http://en.wikipedia.org/wiki/Null_Object_pattern for a better explanation. – Robin Clowers Oct 06 '10 at 23:45
  • @Robin - This is exactly the temporary workaround I have: a default implementation of the interface which returns an empty collection of namespaces. – Nicolas Cadilhac Oct 06 '10 at 23:51
  • @Robin not that. abstractions are for making code more loosely coupled indeed but that's not what I'm talking about. I'm talking about composition root configuration - SM registries, initialization of them. at that point - there should be known one specific implementation. Otherwise - there are 2 composition roots. – Arnis Lapsa Oct 07 '10 at 10:27
  • @ArnisL. there's a very good reason for switching between null and concrete implementation. Feature toggle. The new feature would depend on another class. But if the feature is still hidden, you don't want to get the dependent class involved as the constructor could potentially throw an exception thus crashing your application. – Sleeper Smith Nov 14 '13 at 01:31
0

StructureMap now supports this case via UseIfNone https://structuremap.github.io/registration/fallback-services/

Malcolm
  • 1,239
  • 1
  • 14
  • 25