How to set a default constructor argument to null with StructureMap? - dependency-injection

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.

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.

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

Related

Autofac DI, type not assignable to service

I simply cannot figure this out. Using Autofac with .Net core 2.0 and trying to resolve some simple dependencies. Feel like I've tried everything so my current code doesn't reflect everything I've tried.
Here is one of the exceptions I'm getting from Autofac
None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type
'Elucidate.Core.Application.ValuesController' can be invoked with the available services and parameters: Cannot resolve parameter 'Elucidate.Core.Data.Repository.IRepository'1[Elucidate.Core.Model.User.IUser]rep' of constructor 'Void .ctor(Elucidate.Core.Data.Repository.IRepository`
Here is where I'm trying to get the dependency injected
public ValuesController(IRepository<IUser> rep)
Here is how I'm registering the types in an autofac module
builder.RegisterType<User>().As<IUser>();
builder.RegisterType<CoreUserStore<User>>();
builder.RegisterType(typeof(Repository<User>)).As<Repository<IUser>>();
builder.RegisterType<EntityFrameworkModelContext<User>>(); //.As<IModelContext>();
What am I doing wrong? I'm new to autofac, used to Unity which seems to be extinct.
The ValuesController constructor is expecting IRepository<IUser> and you haven't wired the correct type in Autofac.
You need to register the concrete repository type as the implemented interface, note the .As<IRepository...:
builder.RegisterType(typeof(Repository<User>)).As<IRepository<IUser>>();
Or alternatively "ask" for the concrete type in the constructor.
public ValuesController(Repository<IUser> rep)
The first is probably the preferred approach. You can also do:
builder.RegisterType<Repository<User>>().AsImplementedInterfaces();
Which will register the concrete type as all implemented interfaces.

Maintaining a single instance of a concrete class with unity

When using unity, if i attempt to inject a concrete type that i havent explicitly registered with the container, unity will attempt to locate the current type and will instantiate a new one for me, before injecting it into the class that depends upon it.
How can i ensure that only a single instance of this type is used? Do i need to explicitly register an instance with the container beforehand?
From MSDN:
You can use the Unity container to generate instances of any object that has a public constructor (in other words, objects that you can create using the new operator), without registering a mapping for that type with the container. When you call the Resolve method and specify the default instance of a type that is not registered, the container simply calls the constructor for that type and returns the result.
So simply put, yes, you have to register a mapping for your type to be able to use it as singleton in your app. You can achieve it using RegisterInstance method or RegisterType and providing the ContainerControlledLifetimeManager as the lifetime manager.

Telling StructureMap to use another Constructor

I have a class with 2 constructors.
MyClass()
and
MyClass(IMyService service)
How do I tell StructureMap then whenever I do a 'new MyClass()' it should actually call the second constructor and not the first constructor.
Please help.
If you call new MyClass(), then StructureMap is not involved at all. No amount of StructureMap configuration will change the behavior.
If you call ObjectFactory.GetInstance<MyClass>(), StructureMap will by default call the constructor with more parameters.
If you want StructureMap to use a different constructor, you can specify the constructor (via PHeiberg's answer):
x.SelectConstructor<IMyClass>(() => new MyClass(null));
Or you can just tell StructureMap explicitly how to create the instance using the overload of Use() that accepts a Func<>:
x.For<IMyClass>().Use(ctx => new MyClass(ctx.GetInstance<IMyService>()))
Joshua's answer is covering all aspects. As a side note in order to configure Structuremap to choose a specific constructor without hardcoding the arguments to the constructor as done in Joshua's example you can use the SelectContructor method:
x.SelectConstructor<MyService>(() => new MyService());
The lambda in the SelectConstructor method call should invoke the needed constructor (put nulls or any value of the correct type for all parameters present). See the documentation for further info.
When using a DI container like structuremap it's best to have just a single constructor on every class. This constructor has to resolve all the dependencies of the class, if IMyService is a dependency (which looks a bit strange though) this should always be resolved when instantiating so the parameterless constructor is not needed.

StructureMap Constructor arguments

I'm new to structureMap. How do I define constructor arguments for the following class with fluent configuration? Thanks
public BlobContainer(CloudStorageAccount account
, string containerName
, string contentType
, BlobContainerPermissions blobContainerPermissions)
{
}
For primitive types you would go about as #ozczecho answered:
For<BlobContainer>()
.Use<BlobContainer>()
.Ctor<string>("containerName").Is("theContainerName")
.Ctor<string>("contentType").Is("theContentType");
provided that the values are known at registration time. You can do it this way for non-primitive types as well, but you lose the flexibility that the container gives you this way. It's better to define a default or named instance and use that instead (the container will automatically resolve default instances for you). By defining defaults you can easily change all the dependencies on a type in your application by changing just one registation.
For<CloudStorageAccount>().Use<TheCloudStorageAccountType>();
If a dependency is a concrete type with a constructor having dependencies that are known to structuremap you don't have to register it with the container, it will be automatically resolved.
So if CloudStorageAccount is a concrete class you only need to register it's dependencies in Structure Map.
For<BlobContainer>()
.HybridHttpOrThreadLocalScoped()
.Use<BlobContainer>()
.Ctor<CloudStorageAccount >("account").Is(...)
.Ctor<string >("containerName").Is(...)
.Ctor<string >("contentType").Is(...)
.Ctor<BlobContainerPermissions >("blobContainerPermissions").Is(...);

Can Autofac do automatic self-binding?

I know some DI frameworks support this (e.g. Ninject), but I specifically want to know if it's possible with Autofac.
I want to be able to ask an Autofac container for a concrete class, and get back an instance with all appropriate constructor dependencies injected, without ever registering that concrete class. I.e., if I never bind it explicitly, then automatically bind the concrete class to itself, as if I had called builder.Register<MyClass>();
A good example of when this would be useful is ViewModels. In MVVM, the layering is such that only the View depends on the ViewModel, and that via loose typing, and you don't unit-test the View anyway. So there's no need to mock the ViewModel for tests -- and therefore there's no reason to have an interface for each ViewModel. So in this case, the usual DI pattern of "register this interface to resolve to this class" is unnecessary complexity. Explicit self-binding, like builder.Register<MyClass>();, also feels like an unnecessary step when dealing with something as straightforward as a concrete class.
I'm aware of the reflection-based registration example in the Autofac docs, but that's not to my taste either. I don't want the complexity (and slowness) of registering every possible class ahead of time; I want the framework to give me what I need when I need it. Convention over configuration, and all that.
Is there any way to configure Autofac so it can say "Oh, this is a concrete type, and nobody registered it yet, so I'll just act like it had been registered with default settings"?
builder.RegisterTypesMatching(type => type.IsClass)
If you look at the source you will see that RegisterTypesMatching (and RegisterTypesFromAssembly) is NOT DOING ANY REFLECTION. All Autofac is doing in this case is registering a rule that accepts a type or not. In my example above I accept any type that is a class.
In the case of RegisterTypesFromAssembly, Autofac registers a rule that says "if the type you're trying to resolve have Assembly == the specified assembly, then I will give you an instance".
So:
no type reflection is done at register time
any type that matches the criteria will be resolved
Compared to register the concrete types directly, this will have a perf hit at resolve time since Autofac will have to figure out e.g. constructor requirements. That said, if you go with default instance scope, which is singleton, you take the hit only the first time you resolve that type. Next time it will use the already created singleton instance.
Update: in Autofac 2 there is a better way of making the container able to resolve anything. This involves the AnyConcreteTypeNotAlreadyRegistered registration source.
what about:
builder.RegisterTypesFromAssembly(Assembly.GetExecutingAssembly());
no reflection is done, as Peter Lillevold points out.

Resources