On IServiceProvider what are the differences between the GetRequiredService and GetService methods? - dependency-injection

What are the differences between IServiceProvider.GetRequiredService() and IServiceProvider.GetService()?
When is it a better idea to use GetRequiredService()?

You should rarely have to call these methods at all, as you should use constructor injection where ever possible.
In rare cases, such as factories or to dynamically instantiate command handlers, you can resolve it yourself.
That being said, you should use GetRequiredService where you require the service. It will throw an exception, when the service is not registered.
GetService on the other side is for optional dependencies, which will just return null when there is no such service registered.

The difference is that GetService<T>() returns null if it can't find the service. GetRequiredService<T>() throws an InvalidOperationException instead.

Related

Can CDI dependency injection be optional?

In Spring DI, declaring an autowired field as Optional enables a client to not inject any value to it. Is this possible using Java EE's CDI? I tried Optional and it fails. I want to know if there is an equivalent mechanism I can use.
Here is what I tried:
public class OmeletteMaker implements EggMaker{
public static void main(String[] args){
WeldContainer container = new Weld().initialize();
OmeletteMaker omeletteMaker = container.instance().select(OmeletteMaker.class).get();
}
#Inject
Optional<Vegetable> vegetable;
}
I get an error message:
Exception in thread "main" org.jboss.weld.exceptions.DeploymentException: WELD-001408 Unsatisfied dependencies for type [Optional] with qualifiers [#Default] at injection point [[BackedAnnotatedField] #Inject cafeteria.OmeletteMaker.vegetable]
There are many questions lurking in this seemingly simple question. I'll try to answer them bearing in mind the spirit of the question.
First, as a general rule, if you #Inject a Fred, that Fred cannot be null unless Fred is in #Dependent scope, and even then a producer method or custom bean will have to explicitly be written to return null. There are edge cases but in all modern CDI implementations this is a good rule of thumb to bear in mind.
Second, Optional isn't special. From the standpoint of CDI, an Optional is just another Java object, so see my first statement above. If you have something that produces an Optional (like a producer method) then it cannot make a null Optional (unless, again, the production is defined to be in the #Dependent scope—and if you were writing such a method to make Optional instances and returning null you are definitely going to confuse your users). If you are in control of producing Optional instances, then you can make them any way you like.
Third, in case you want to test to see if there is a managed bean or a producer of some kind for a Fred, you can, as one of the comments on your question indicates, inject a Provider<Fred> or an Instance<Fred>. These are "made" by the container automatically: you don't have to write anything special to produce them yourself. A Provider<Fred> is an accessor of Fred instances and does not attempt to acquire an instance until its get() method is called.
An Instance is a Provider and an Iterable of all known Freds and can additionally tell you whether (a) it is "unsatisfied"—there are no producers of Fred at all—and (b) it is "resolvable"—i.e. there is exactly one producer of Fred.
Fourth, the common idiom in cases where you want to see if something is there is to inject an Instance parameterized with the type you want, and then check its isResolvable() method. If that returns true, then you can call its get() method and trust that its return value will be non-null (assuming the thing it makes is not in #Dependent scope).
I hope this is helpful!

StructureMap specific constructor - how should parameters be initialized?

Given the following piece of a StructureMap registry
For<ILogger>().Use(LogFactory.CreateLogger());
For<Scheduler>().Use(() => new Scheduler(ObjectFactory.GetInstance<ILogger>()));
...is this a good way of providing an ILogger to the Scheduler? It works - but I'm curious to know if it's a poor way of providing a type that the container is configured to provide, or whether it's my only option given the scenario... the scenario being that the Scheduler type itself has other constructors which I cannot change, nor do I care for - but they are needed, so I need to specify this particular constructor rather than using a straight For<x>().Use<y>();
It would be best if the registered service has exactly one public constructor. This makes it unambiguous what dependencies a service makes and makes it very clear which constructor will be selected by the container, and it allows you to register types using the more flexible Use<T>(), and makes the composition root less likely to be changed when the constructor changed.
However, as you said, in your case you can't change the constructors of that type, so you will have to fall back. There are multiple ways to select the proper constructor with StructureMap, but registering a delegate is the best way, since this gives you compile time support.

Registering Transaction Event Handlers in neo4j

I'm currently using Spring Data with Neo4j and have subclassed the SpringRestGraphDatabase to allow the registration of specific transaction event handlers.
I call the registerTransactionEventHandler method to do so. Unfortunately I always get the following exception:
Caused by: java.lang.UnsupportedOperationException: null
at org.neo4j.rest.graphdb.AbstractRemoteDatabase.registerTransactionEventHandler(AbstractRemoteDatabase.java:52) ~[neo4j-rest-graphdb-1.6.jar:1.6]
at org.neo4j.rest.graphdb.RestGraphDatabase.registerTransactionEventHandler(RestGraphDatabase.java:28) ~[neo4j-rest-graphdb-1.6.jar:1.6]
By looking closely at the AbstractRemote I see that it always throws an exception:
public <T> TransactionEventHandler<T> registerTransactionEventHandler( TransactionEventHandler<T> tTransactionEventHandler ) {
throw new UnsupportedOperationException();
}
The RestGraphDatabase doesn't provide an implementation for the register method hence the exception. I'm not sure what alternatives to use, especially as I'm extending SpringRestGraphDatabase.
Is there a cleaner alternative?
(I'm using v2.1.0.M1)
Yeah,
the exposure of these handlers would be very costly over the network. Depending on what you want to do, I would suggest writing a custom plugin to expose your operations and register what you need via a REST endpoint, see http://docs.neo4j.org/chunked/snapshot/server-plugins.html

How to set a default constructor argument to null with StructureMap?

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/

Construtor/Setter Injection using IoC in HttpHandler, is it possible?

I've ran into a rather hairy problem. There is probably a simple solution to this but I can't find it!
I have a custom HttpHandler that I want to process a request, log certain info then enter the details in the database. I'm using NUnit and Castle Windsor.
So I have two interfaces; one for logging the other for data entry, which are constructor injected. I quickly found out that there is no way to call the constructor as the default parameterless constructor is always called instead.
So I thought I would use Setter injection and let Castle windsor sort it out. This actually works as when I use container.Resolve<CustomHttpHandler>(); I can check that the logger is not null. (In Application_Start in Global.asax.cs)
The problem is although Castle Windsor can create the instance the http application is not using it??? I think??
Basically the whole reason for doing it this way was to be able to test the logger and data repository code in isolation via mocking and unit testing.
Any ideas how I can go about solving this problem?
Thanks!
Not possible, at least not directly. IHttpHandler objects are instantiated by the ASP.NET runtime and it doesn't allow Windsor to get involved in its creation. You can either:
Pull dependencies, by using the container as a service locator.
Set up a base handler that creates, injects and delegates to your own handlers (see how Spring does it)
Use the container as a service locator for another service that handles the entire request (as saret explained)
What you could do is have the HttpHandler call out to another object that actually handles the request. so in your HttpHandler's ProcessRequest method you would do something like this:
public void ProcessRequest(HttpContext context)
{
var myHandlerObject = container.Resolve<HandlerObject>();
myHandlerObject.ProcessRequest(context or some state/info that is required)
}

Resources