I believe I can shed some light on your questions. I, too, was wondering why the concrete type was registered along with a registration mapping the same concrete type to its interface.
I did a search to discover if anyone else encountered the same issue, thinking I may have done something wrong. But I ended up at this Codeplex discussion thread: Registration convention generates two registrations for each mapping. In this thread, randylevy (in the 3rd to last post) states that this is the default behavior when a LifetimeManager
and/or injection members are specified as part of the convention:
In terms of the behavior you are seeing, I believe this is by design. If you specify a
LifetimeManager
orinjectionMembers
then Unity will register any types passed in with the supplied values. This makes sense in general because the user has specified the various configuration they desire for the types passed in.For example you can also use registration by convention to just register types:
container.RegisterTypes( AllClasses.FromLoadedAssemblies(false, false, false, false), WithMappings.None, WithName.Default, t => new ContainerControlledLifetimeManager(), null, true);
So in this case all classes (lets say
Class1
) will be registered as singletons (ContainerControlledLifetimeManager
) with no interface mapping (WithMappings.None
). If the lifetime manager was not specified thenClass1
would not have been registered. But because the lifetime manager is specified the registration needs to be setup to use the correct user specified lifetime manager.
I believe that answers your question as to why there is a concrete type mapping in addition to the interface type mapping for a given type when using registration by convention. As the OP on that discussion thread stated, I too wish that there was some option you could set in the registration by convention class to disable the concrete type mapping.
In the end however, I'm not sure it makes a huge difference. If you're programming against contracts (e.g. using the interface type for the constructor/method/property arguments), then the container will always resolve using the interface mapping registration; and if any injection/interception is setup on that interface registration, then when resolved, the type should have the appropriate objects injected and the configured interception should occur.
At where I work, we have several different types of common registrations that need to occur, i.e. services, repositories, and other categories of classes/interfaces. For the sake of example, let's suppose I have a whole bunch of Service classes that need to be registered with their interfaces and which also have validators associated with them. The naming convention is MyService
and a corresponding interface IMyService
and a corresponding validator MyServiceValidator
. I have created a ServiceRegistrationConvention
class to accomplish this as follows:
public class ServiceRegistrationConvention : RegistrationConvention
{
/// <summary>
/// Gets a function to get the types that will be requested for
/// each type to configure.
/// </summary>
public override Func<Type, IEnumerable<Type>> GetFromTypes()
{
return WithMappings.FromMatchingInterface;
}
/// <summary>
/// Gets a function to get the additional
/// <see cref="T:Microsoft.Practices.Unity.InjectionMember" />
/// objects for the registration of each type. Defaults to no injection members.
/// </summary>
public override Func<Type, IEnumerable<InjectionMember>> GetInjectionMembers()
{
return GetServiceValidator;
}
/// <summary>
/// Gets a function to get the
/// <see cref="T:Microsoft.Practices.Unity.LifetimeManager" />
/// for the registration of each type. Defaults to no
/// lifetime management (e.g. transient).
/// </summary>
public override Func<Type, LifetimeManager> GetLifetimeManager()
{
// Where I work, we use this lifetime manager for everyting.
// I wouldn't recommend this right off the bat--I'm looking
// into changing this, personally, but right now, this is
// what we use and it works for our MVC application.
return WithLifetime.Custom<PerRequestLifetimeManager>;
}
/// <summary>
/// Gets a function to get the name to use for the registration of each type.
/// </summary>
public override Func<Type, string> GetName()
{
return WithName.Default;
}
/// <summary>
/// Gets types to register.
/// </summary>
public override IEnumerable<Type> GetTypes()
{
// You may want to further restrict the search for classes to register
// by doing some sort of namespace matching:
//
// t.Namespace.StartsWith(
// "MyCompanyNamespacePrefix", StringComparison.Ordinal
// )
//
// for example.
return AllClasses.FromLoadedAssemblies()
.Where(t => t.Name.EndsWith("Service", StringComparison.Ordinal));
}
/// <summary>
/// Given a type, get the type's corresponding validator, if any.
/// </summary>
private IEnumerable<InjectionMember> GetServiceValidator(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
// In our case, the validators live in the same assembly
// as the class its validating...
string matchingValidatorName = string.Concat(type.Name, "Validator");
Type vType = AllClasses.FromAssemblies(new[] { type.Assembly })
.FirstOrDefault(t =>
string.Equals(t.Name, matchingValidatorName, StringComparison.Ordinal)
);
return (vType != null) ?
new List<InjectionMember>
{
new Interceptor<InterfaceInterceptor>(),
new InterceptionBehavior(vType)
}
:
null;
}
}
Again, so long as you're always resolving the type from its interface, everything should work just fine.
UPDATE: Well, unfortunately, interception is not working correctly. When I discover the issue, I'll be sure to update my answer.
UPDATE: This does work exactly as written here. I had an error with another configuration that caused the whole application to fail. Once I fixed that error, interception is occurring as expected.