Skip to content

WIP - Replace IObjectsFactory with IServiceProvider interface #1793

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 16 commits into
base: master
Choose a base branch
from

Conversation

maca88
Copy link
Contributor

@maca88 maca88 commented Jul 12, 2018

Here is an attempt to replace the IObjectsFactory with IServiceProvider interface based on #1781.
As discussed, with IServiceProvider we can get the service by the base type or interface without worrying whether the service is registered or not as it is designed to return null in case the service is not registered. I've added a default IServiceProvier implementation that has also the ability to register services in case the user does not use any IoC container and wants to pass a service instance. In addition, an additional method PropertiesHelper.GetInstance was added in order to be used by other NHibernate projects when instantiating a service via configuration properties.

@maca88 maca88 changed the title Replace IObjectsFactory with IServiceProvider interface. Replace IObjectsFactory with IServiceProvider interface Jul 12, 2018
@maca88 maca88 force-pushed the IServiceProvider branch from 353c2ea to c96e233 Compare July 12, 2018 18:17
{
using System.Threading.Tasks;
[TestFixture]
public class SettingsFactoryFixtureAsync
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This class should not be generated as there is nothing async, it is a bug related to async generator that I need to fix.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I released a new version of the async generator (0.8.2.10) that fixes the issue of generating non async methods.

@hazzik
Copy link
Member

hazzik commented Jul 12, 2018

Let's hold-on on this for a moment. The PR is a good starting point, but, I think, we need to discuss what we want to achieve and what direction shall we go.

@maca88
Copy link
Contributor Author

maca88 commented Jul 15, 2018

what we want to achieve

The aim of this PR is to achieve the ability to configure services like ICacheProvider by an IoC container without setting any configuration property.

what direction shall we go

With #1781 the IObjectsFactory will contain only one non-obsolete method that has the same functionality as the built-in IServiceProvider.GetService method, so I think the replacement of IObjectsFactory with IServiceProvider is the way to go.

Copy link
Member

@fredericDelaporte fredericDelaporte left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have rebased this on master by the way.

Avoid corrupting following tests in case of failure
Keep tests for an obsolete class, till it gets dropped
Fix regression: must use GetService instead of GetInstance for
ICurrentSessionContext, since it is optional and GetInstance does not
support it.
@fredericDelaporte
Copy link
Member

Here is a series of fix proposals addressing my review comments.

@fredericDelaporte
Copy link
Member

While looking into this, I have spotted a number of cases which will not play nice with dependency injection, due to not using the service provider, or forcing a default concrete class:

  • CreateLinqQueryProviderType
  • ConstructConverter
  • AbstractBytecodeProvider.CollectionTypeFactory
  • ConfigureProxyFactoryFactory

We should likely rework those cases too, probably in a dedicated PR.

@maca88
Copy link
Contributor Author

maca88 commented Aug 1, 2018

@fredericDelaporte thanks for fixing the mentioned issues, I am ok with them.

@hazzik
Copy link
Member

hazzik commented Aug 3, 2018

Hi all. I think the registration/container building logic should not be there.

@maca88
Copy link
Contributor Author

maca88 commented Aug 3, 2018

I've removed the registration logic and renamed the class to ActivatorServiceProvider, as I agree that it is out of scope about what NHibernate as an ORM library should provide.

@hazzik
Copy link
Member

hazzik commented Aug 4, 2018

Was thinking about this approach and found it might be inconvenient for an end user. For example, using other service provider other than supplied, an IoC/DI container which requires explicit components registration, for example, would require the user to register all NH services. I don't think that this is a desired behaviour.

I think we need to have some fallback mechanism, eg fallback to Activator.CreateInstance if IServiceProvider.GetService returns null. Thoughts?

I don't want to bring additional dependencies (eg Microsoft.Extensions.DependencyInjection) nor provide an ability to register the components (we're not building DI container after all).

@maca88
Copy link
Contributor Author

maca88 commented Aug 4, 2018

an IoC/DI container which requires explicit components registration, for example, would require the user to register all NH services

I didn't known that some IoC containers like Castle.Windsor require explicit registration for concrete types, thanks for pointing this out.

I think we need to have some fallback mechanism, eg fallback to Activator.CreateInstance if IServiceProvider.GetService returns null. Thoughts?

Yes, I also think that we should add a fallback mechanism that should try to instantiate concrete types with Activator.CreateInstance when ServiceProvider.GetService returns null. I will update this PR to reflect that.

@maca88
Copy link
Contributor Author

maca88 commented Aug 4, 2018

I've added the fallback only for NHibernate internal types and leaved the strictness for external types in order to respect the IoC container rules. If you think that we should have a fallback also for external type, I will change that.
Update:
The fallback is added for all types in order to avoid registering also types from NH family projects like NHibernate.Caches.

…requires an explicit registration for concrete types
@maca88 maca88 force-pushed the IServiceProvider branch from eb6e0e9 to b256937 Compare August 4, 2018 15:44
@fredericDelaporte
Copy link
Member

fredericDelaporte commented Aug 8, 2018

@hazzik, do you agree for merging or do you wish to have another look yourself before?

@fredericDelaporte fredericDelaporte added this to the 5.2 milestone Aug 8, 2018
@hazzik
Copy link
Member

hazzik commented Aug 8, 2018

I'll take another look.

@hazzik hazzik self-requested a review August 8, 2018 10:41
@hazzik hazzik modified the milestones: 5.2, 5.3 Oct 21, 2018
@fredericDelaporte
Copy link
Member

Postponing this to 5.3 is quite unfortunate. This PR changes public interfaces which were not yet released. Delaying it will cause more breaking changes to dodge, and more members to flag as obsolete, instead of just dropping them directly.

@hazzik
Copy link
Member

hazzik commented Nov 7, 2018

PR changes public interfaces which were not yet released

Which exact interface are you talking about?

@fredericDelaporte
Copy link
Member

I am talking about "interface" in its broad meaning, not just the technical C# interface:

  • Removal of class HibernateObjectsFactoryException.
  • Removal of setting objects-factory, replaced by service-provider.
  • Removal of HibernateConfiguration.ObjectsFactoryType property, replaced by ServiceProviderType.
  • Removal of Environment.PropertyObjectsFactory constant, replaced by PropertyServiceProvider.
  • Removal of Environment.ObjectsFactory property, replaced by ServiceProvider.
  • Removal of Environment.BuildObjectsFactory method, replaced by BuildServiceProvider.

@hazzik
Copy link
Member

hazzik commented Nov 7, 2018

I do not want this to go into an opposite direction of #1781 but rather in the same and add value rather than replace. What it means is that, in my mind, it would be better if IServiceProvider is hidden behind the IObjectsFactory, not replace it.

@fredericDelaporte
Copy link
Member

fredericDelaporte commented Nov 8, 2018

I do not see it as going into an opposite direction. For me, it is instead the same direction: removing specificities hindering dependency injection. I do neither see where is the added value in keeping an IObjectsFactory hiding away IServiceProvider.

I see a value for the case of Microsoft ILogger, because that interface lies in an extension, requiring an additional dependency people might not want. But IServiceProvider is instead in the standard.

The only value, that IObjectsFactory was having, was its obsolete methods, supporting cases not allowed by IServiceProvider. But these cases were removed specifically because they are not supported by many dependency injection frameworks. Sticking to IServiceProvider will avoid re-introducing new features not widely supported, for a thing that is a very basic need and which does not need fancy features.

It will also allow users to directly use any dependency injection framework supporting IServiceProvider, instead of having to code some boilerplate class encapsulating it in NHibernate custom IObjectsFactory. (Or instead of having NHibernate supply such a class, with then two ways of configuring DI: supplying a custom IObjectsFactory or supplying a IServiceProvider to be used by the default objects factory. Having two ways of doing the same thing is always a bit confusing.)

In my view, if IObjectsFactory is to stay while also directly supporting IServiceProvider, that is IObjectsFactory which should be hidden away from the user. It would be only internally used for resolving dependencies, while the user could setup its own IServiceProvider to be used by NHibernate "internal" objects factory.

@fredericDelaporte fredericDelaporte mentioned this pull request Nov 20, 2018
@fredericDelaporte fredericDelaporte changed the title Replace IObjectsFactory with IServiceProvider interface WIP - Replace IObjectsFactory with IServiceProvider interface Dec 13, 2018
@fredericDelaporte
Copy link
Member

Switched to WIP: since 5.2 has been released, this PR has now binary breaking changes.

@maulik-modi
Copy link

@fredericDelaporte , @hazzik and @maca88 , This is something very important to embrace MS DI Abstractions and be conformant

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants