9

Our team had recently a big struggle of deciding whether it is a good practice or not for the .NET Core class libraries to register their own implementations by the fact of providing a IServiceCollection extension methods like AddMyServices().

My point was that it is good to do this because:

  • Top level application does not need to know all the details of the underlying library it is going to use,
  • Top level application (usually Startup class) is not polluted with references to all the namespaces required to register its implementation.
  • If top level application wants to provide its own custom implementation of some interfaces defined in the referenced library, it still can do it. .NET Core dependency injection allows multiple registrations.
  • If there is more applications referencing this class library, you would not need to copy paste a block of e.g. AddTransient lines to each application.

Counterarguments were that:

  • Some example applications use the approach of registering all the implementations in the top level Startup method.
  • The above approach is only used for features (but it creates semantic doubts around what can be called a feature and what not). Still class library can name features it implements and provide separate AddFeatureXYZ() methods in the IServiceCollection extension class.
  • Using AddService() extension method which registers all the implementations it may provide, may impact the performance of DI container, which makes sense in case where certain class library provide many impementations but only few are used. But a developer still have a freedom of calling AddServices() or not.

I wanted to ask about it more experienced .NET Core developers about their approaches with all the pros, which maybe I am missing. If there are any strong arguments for using the second approach I didn't list here, I would really love to get acquainted with it.

PS. This question was moved from StackOverflow as it was marked as more opinion based. In my opinion it is touching the core priciples of object oriented programming, and the question is not to find out what majority of developers is choosing, but about why somebody favours one approach against the other.

Thanks, Radek

1 Answer 1

4

The ASP.Net core docs recommend it

Each services.Add{SERVICE_NAME} extension method adds (and potentially configures) services. For example, services.AddMvc() adds the services Razor Pages and MVC require. We recommended that apps follow this convention. Place extension methods in the Microsoft.Extensions.DependencyInjection namespace to encapsulate groups of service registrations.

But I don't.

One of the most annoying things about configuring plugins is trying to guess the extension method to use to configure them. Or I should say, the version that you have of them as the name seems to change between versions and frameworks

Secondly, often these rolled up registration methods don't expose all the things you might want to override or configure on the underlying services. The whole point of the service manager is so you can replace out dependencies when required, but the extension method doing it for you can prevent that.

But perhaps most importantly, I don't think that this convention has taken hold yet. There seem to be some competing philosophies when it comes to startup.cs and program.cs. If you only support one method you are going to be on someone's wrong side.

I would provide the extension method, but in a separate optional package. Allow users to manually register the components if they want or use the extension method for a default setup.

2
  • Yes, I agree on the fact it is somewhat annoying to find the extension method that does it. But having one method, where you register all the things the library implements is very handy and does not strip you from the freedom of overriding it or even calling it or not. Personally I would lean towards what Ninject is doing, that is through some reflections mechanism, class librariers get automatically registered in the container. And again, in my opinion polluting the top level module with all the details of referenced libraries is agains encapsulation principle of OOP. Nov 29, 2018 at 12:18
  • I've found with some packages, they make the individual registrations private or internal and only expose the extension method.
    – Ewan
    Nov 29, 2018 at 15:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.