As you already noted, the difference between IServiceProvider.GetService
and IServiceLocator.GetInstance
is that any IServiceProvider.GetService
implementation should return null
when the service isn't registered or when it can't be resolved for what ever reason, while IServiceLocator.GetInstance
implementations on the other hand should throw an exception in that case (and never return null
).
But note my use of the word 'should'. All the CSL adapters (for Windsor, Spring, Unity and StructureMap, etc) that are shipped with the Common Service Locator project (which owns the IServiceLocator
interface) don't adhere to the IServiceProvider
interface and they throw an exception when you call their IServiceProvider.GetService
method.
By breaking the contract, the designers of the CSL managed to make the IServiceProvider
interface utherly useless. You now simply can't rely on it to return null anymore, which is bad. Really bad. The only CSL adapter I know of that adheres to the contract is the Simple Injector adapter, but since all other implementations are broken, even this correctly implemented adapter is useless at that point, since there's no way you can safely swap implementations.
Does this count as a violation of Liskov
Absolutely. They broke the interface contract and implementations can't be substituted from one another.
The designers know about this, as can be seen from Glenn Block's comment on this thread:
Sounds like we might have messed up here. The idea of throwing an exception was an explicit design goal that we all agreed on. Making it implement IServiceProvider was more of a convenience, but sounds like this was overlooked.
The flaw has never been fixed, because the CSL has never been updated.