Dependency injection bindings through an IOC container can
be achieved by different ways. For e.g. you can use an XML file based
configuration for registering types or use an imperative code block for
registration. Both of these methods use an explicit way if registering and
resolving types.
Another common and an easy approach is to use attributes to
register and resolve types. In this post, we'll extend the SharePoint service
locator, to register types based on attributes to the container, which can be
later used to resolve the mappings.
Creating the
attribute:
public class SetAutoRegistration : Attribute, ISpAttribute
{
public Type InterfaceType { get; private set; }
public string Key { get; private set; }
public SetAutoRegistration(Type interfaceType) : this(interfaceType, string.Empty)
{
}
public SetAutoRegistration(Type interfaceType, string key)
{
InterfaceType = interfaceType;
Key = key;
}
}
Creating a mappings
object to define type mappings:
public class Mapping
{
public Type FType { get; private set; }
public Type TType { get; private set; }
public string Key { get; private set; }
public Mapping(Type fType, Type tType, string key)
{
FType = fType;
TType = tType;
Key = key;
}
}
Extending the
ServiceLocator class to add type based mappings:
[SharePointPermission(SecurityAction.InheritanceDemand,
ObjectModel = true)]
[SharePointPermission(SecurityAction.LinkDemand,
ObjectModel = true)]
public void RegisterTypeMapping(Type fromType, Type toType)
{
RegisterTypeMapping(fromType, toType, null);
}
[SharePointPermission(SecurityAction.InheritanceDemand,
ObjectModel = true)]
[SharePointPermission(SecurityAction.LinkDemand,
ObjectModel = true)]
public void RegisterTypeMapping(Type fromType, Type toType, string key)
{
var typeMappings = GetConfigData();
var newTypeMapping = new TypeMapping(fromType, toType, null) { InstantiationType = InstantiationType.NewInstanceForEachRequest };
RemovePreviousMappingsForFromType(typeMappings,
newTypeMapping);
typeMappings.Add(newTypeMapping);
SetTypeMappingsList(typeMappings);
}
[SharePointPermission(SecurityAction.InheritanceDemand,
ObjectModel = true)]
[SharePointPermission(SecurityAction.LinkDemand,
ObjectModel = true)]
public void RemoveTypeMappings(Type type)
{
var typeMappings = GetConfigData();
foreach (var mapping in typeMappings.ToArray())
{
if (mapping.FromType == type.AssemblyQualifiedName)
{
typeMappings.Remove(mapping);
}
}
SetTypeMappingsList(typeMappings);
}
Using reflection to
register types to service locator during feature activating:
var assembly = Assembly.Load(assemblyToProbe);
var typesToAdd =
assembly.GetTypes().Where(x =>
x.GetCustomAttributes(typeof (SetAutoRegistration), false).Length > 0);
types.AddRange(typesToAdd);
var mappings =
BuildMappingsFromTypes(types);
foreach (var mapping in mappings)
{
if (mapping.Key == string.Empty)
serviceLocatorConfig.RegisterTypeMapping(mapping.FType, mapping.TType);
else
serviceLocatorConfig.RegisterTypeMapping(mapping.FType, mapping.TType,
mapping.Key);
}
Attribute based
registration in action:
[SetAutoRegistration(typeof(IMyRepository))]
public class MyRepository : BaseRepository<MyEntity>, IMyRepository
{
You can use the same approach to register types to
activating service locator for the test cases.