Shared Services Registry

Over time, we were fortunate enough to have a Common Service Locator (CSL) for resolving services from an unknown source. However, there has never been any container-agnostic solution for registering these services in the first place. We have always encountered the problem of associating our composition code with a specific IoC container and, in addition, striving to use this container throughout our application.

I feel like maybe I'm trying to achieve the impossible here, but does anyone have any ideas on how to create a shared service registry (CSR)?

My initial idea was to use MEF to solve different IContainerIntegrator (one class for each container technology), which, in turn, use MEF to resolve different IXXXContainerBinding (one interface for each technology). Users could then develop applications around container bindings and simply transfer the bindings to the BIN directory to create a plug-in architecture. If they wanted to use the new container technology, they just needed to develop a new IContainerIntegrator class and an accompanying IXXXContainerBinding , which they would then use to write their own bindings. When the application starts, the CSR merges all container instances into a single CSL using the ServiceLocatorAggregator class.

It works for me, but I ran into the following problems:

  • Any binding that causes calls in the current (incomplete) container is unstable, as previous registrations may be overridden by subsequent associations. This includes the bindings that objects must allow to make registration decisions (ie, “Bind this if they exist”).
  • There may be two bindings that provide the same set of services. However, we want to “bind” these registrations. For instance. "I want services A and C to bind to X, and services B and D to bind Y."
  • Containers allow services on their own with auto-wire dependencies of requested services. For instance. 'container.Bind <This> .To <That> ()' will automatically implement the implementation using the services allowed from the "container" and not from the aggregated service locator.

Please yell at me if I completely skipped this point, but isn't this the most untied solution for dependency management? It would be nice? I am going to start a large corporate project with a plug-in architecture. I do not want to bind to a specific IoC container.

(ps) This question relates to a container agnostic composition that supports detection. Please do not enter the discussion about SL vs DI. SL is used in composition, so I mentioned so much here).

+3
source share
2 answers

The most untied (and best) solution you can achieve is the realization that free communication is best achieved using principles and patterns instead of specific technologies.

Use Constructor Injection throughout the application. Ensuring that none of your application layers need to reference any container at all . Then compile the entire application graph in the root application .

You do not need to use a DI container for this, but if you decide to use a DI container, you must isolate it from the composition Root . This means that if you later decide to switch to another container, you will only need to change the root composition. However, Poor Man DI is also an option.

+9
source

There are many tricks you can use to avoid having to depend on a specific IoC container for most of your code, the easiest of which is using constructor injection. If you are configured to use the Locator Service template, simply create your own Locator Service class, which wraps the actual core of the IoC container that you plan to use.

Thus, the point of the IoC container is to achieve “control inversion”: i.e. moving the control from the lower levels up. This means that you need to have a dot near the "top" (or "root") application that actually knows about all the service implementations that it is going to use, as well as about your specific IoC implementation. This should be limited to several classes. Typically, the “Context Root" of an application is the place where you will initialize your IoC container and Service Locator. There must be a specific module or group of modules that takes care of setting up all your bindings.

If you want to enable the use of plugins, you need to create a specific API for their use and compliance. Just letting other packages define new IoC bindings is a recipe for disaster, because you don't know how well these different packages will play together.

ASP.NET MVC 3 is a good example of this. They have specific factory locators that you override in the global Application_Start method. To implement one of these factories, you must comply with the API that they provide to you. But you can create an implementation that uses any IoC container you want, or nothing at all. You do not change the "bindings" at all. You simply tell the infrastructure that for the current application you want to use this factory to create controllers or model metadata providers instead of using the factory by default.

To use another example that is more applicable to your specific example, consider the ISearchProvider case. You may have a built-in LuceneProvider , and perhaps one of your plugins may provide GoogleProvider . Which of these suppliers do you want to use? The mere presence of GoogleProviderPlugin means LuceneProvider is no longer available? Should searches somehow combine the results of both of these providers? Should a user select one or more providers from the user interface?

Regardless of the answer to these questions, the end point is that you want your application to control this, not the plugin. Instead of giving the blanche plugin card for blanking with your DI bindings, you want to tell the plugin: "I allow you to define additional search providers, and here is how you can register them." They can be registered in various ways, including annotations / class attributes or the simple presence of a class that implements this interface. But the important point is that there is an API that specifically defines what they can “connect to” and what you need from anyone who creates the plugin.

Now, if GoogleProvider has dependencies defined in the plugin, this plugin can resolve these dependencies, but it wants to. Hopefully he will use some kind of IoC container, but if he doesn’t, then there is no skin from your back. You can still be agnostic about the container they use, if any.

If there are certain services that you expect from SearchProvider , you can enable these services or factories for these services as part of the initialization API for your plugin. Thus, your plugin can access these services without thinking about your IoC container application.

+1
source

Source: https://habr.com/ru/post/887998/


All Articles