How to prevent Unity overwriting existing mappings with AutoRegistration

非 Y 不嫁゛ 提交于 2019-12-22 10:39:30

问题


Unity 3 offers new capabilities for AutoRegistration (Registration by Convention) such as:

container.RegisterTypes(
    AllClasses.FromLoadedAssemblies(),  //uses reflection
    WithMappings.FromMatchingInterface, //Matches Interfaces to implementations by name
    WithName.Default);

This code will register all types that implement their similarly named interfaces, against those interfaces. For example, class MyService : IMyService will be registered automatically as though you had written the following:

container.RegisterType<IMyService, MyService >();

My Question: What if I want this most of the time, but I want to choose a different implementation for one of my interfaces, even though a similarly named implementation exists?

See: Patterns and practices on CodePlex

An important article to read explaining why you would want to do this is Jeremy Miller's Convention Over Configuration article


回答1:


What stops you from overriding the automated mapping with a custom set loaded from configuration (which - if empty - means that no default mapping is overridden):

 // have your auto registration
 container.RegisterTypes(
   AllClasses.FromLoadedAssemblies(),  //uses reflection
   WithMappings.FromMatchingInterface, //Matches Interfaces to implementations by name
   WithName.Default);

 // and override it when necessary
 container.LoadConfiguration();

where the configuration is

<?xml version="1.0" encoding="utf-8" ?>
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
<container>
    <register type="IMyService" mapTo="OverriddenServiceImpl" />
</container>
</unity>

or

<?xml version="1.0" encoding="utf-8" ?>
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
<container>
        ...nothing, do not override defaults ...
</container>
</unity>

Moving the optional configuration to an XML file has the advantage - you can reconfigure the system without the need to recompile it.




回答2:


Unity has always used a "last in wins" rule for configuration. So do your autoconfig on the container first, then do the overrides afterwards. The last set configuration (regardless of how it happens) will be the one in the container.




回答3:


I ended up using Wiktor's approach but with a slight variation because I was not in a position to get onto .NET 4.5 in time to get my solution live. So I was unable to use Auto-Registration.

Instead, I loaded any xml configuration first using

container.LoadConfiguration();

It is important to recognize that in many cases, there is a default implementation of an abstraction, used %90+ of the time. In fact, often, the default is always used except when dependencies are mocked for testing. Therefore, it is a good idea to make it easy to register defaults.

I have a convention on my team that defaults are registered by a registration class within the assembly containing the defaults. The registration class is discoverable via reflection. Often, the interface or abstract class will be in a different, contracts assembly.

Registrations are always wrapped in the guard clause:

if (!container.IsRegistered<IMyService>())
{
    container.RegisterType<IMyService, MyService>()
}

I also added an extension method to IUnityContainer to make this a little less verbose for my devs

    public static IUnityContainer RegisterIfUnRegistered<TAbstraction, TImplementation>(
         this IUnityContainer container) where TImplementation : TAbstraction 
    {
        if (!container.IsRegistered <TAbstraction>())
        {
            container.RegisterType<TAbstraction, TImplementation>();
        }
        return container; //Make it fluent
    }

There are various overloads to this, taking named registrations and factory registrations etc.

Now, the default implementations are discovered 99% of the time, but they can be overridden in xml as per Wiktor's suggestion.

This might seem a bit too much like smoke and mirrors. Auto registration often does feel like that. It has been available in Castle Windsor and other dependency container frameworks for years. Shame we had to wait 11 years for it to be available in Microsoft's offering. Hmmm. I digress.

As long as the convention of registering defaults in the implementing assembly is followed, it becomes very easy to unit test and debug registrations.

Remember however, that the code that performs the registration by reflecting assemblies or by calling the registration classes directly should run very close to the main method in your executable. This is your Composition Root. See Mark Seeman's blog for more info on Dependency Injection. He wrote the book on DI. I highly recommend this.



来源:https://stackoverflow.com/questions/16299221/how-to-prevent-unity-overwriting-existing-mappings-with-autoregistration

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!