EDIT Come spiegato nel commento di Steven, il ContractClass
e ContractClassFor
sono contrassegnati con [Conditional("CONTRACTS_FULL")]
, questa soluzione può introdurre bug per questi attributi. Vedi il commento di Steven per una spiegazione migliore.
Non so alcun meccanismi che consentono filtro globale sulle immatricolazioni registrate con il metodo RegisterAssemblyTypes
. L'unica soluzione per filtrare la registrazione utilizzando questo metodo è utilizzare il metodo Where
come mostrato nell'esempio di codice.
Quando una registrazione è registrata in un ComponentRegistry
non è possibile rimuoverlo dal registro.
Se non si desidera utilizzare il metodo Where
in ogni registrazione, è possibile creare un altro metodo.
public static class ContractClassRegistrationExtensions
{
public static IRegistrationBuilder<TLimit, TScanningActivatorData, TRegistrationStyle> NotContractClass<TLimit, TScanningActivatorData, TRegistrationStyle>(this IRegistrationBuilder<TLimit, TScanningActivatorData, TRegistrationStyle> registration) where TScanningActivatorData : ScanningActivatorData
{
if (registration == null)
{
throw new ArgumentNullException("registration");
}
return registration.Where(t => t.GetCustomAttribute<ContractClassForAttribute>() == null);
}
}
Utilizzando questo metodo, invece di
builder.RegisterAssemblyTypes(ThisAssembly)
.Where(t=> t.GetCustomAttribute<ContractClassForAttribute>() == null)
.As<IFoo>();
Sarete in grado di scrivere:
builder.RegisterAssemblyTypes(ThisAssembly)
.NotContractClass()
.As<IFoo>();
Non è una vera soluzione ma è la soluzione che userei in un caso simile.
A proposito, se si vuole veramente qualcosa di magico usando Autofac, è possibile implementare un IRegistrationSource
public class FilterRegistrationSource : IRegistrationSource
{
private static MethodInfo _createFilteredRegistrationMethod = typeof(FilterRegistrationSource).GetMethod("CreateFilteredRegistration");
public Boolean IsAdapterForIndividualComponents
{
get
{
return false;
}
}
public IEnumerable<IComponentRegistration> RegistrationsFor(Service service, Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor)
{
IServiceWithType serviceWithType = service as IServiceWithType;
if (serviceWithType == null)
{
yield break;
}
Type serviceType = serviceWithType.ServiceType;
if (!serviceType.IsClosedTypeOf(typeof(IEnumerable<>)))
{
yield break;
}
Type elementType = new Type[] { serviceType }.Concat(serviceType.GetInterfaces())
.Where(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IEnumerable<>))
.Select(t => t.GetGenericArguments()[0])
.First();
yield return (IComponentRegistration)FilterRegistrationSource._createFilteredRegistrationMethod.MakeGenericMethod(elementType)
.Invoke(this, new Object[] { serviceWithType });
}
public IComponentRegistration CreateFilteredRegistration<T>(IServiceWithType serviceWithType)
{
return RegistrationBuilder.ForDelegate((cc, p) => cc.ComponentRegistry
.RegistrationsFor(serviceWithType.ChangeType(typeof(T)))
.Where(r => !r.Activator.LimitType.GetCustomAttributes(typeof(ContractClassForAttribute), false).Any())
.Select(r => r.Activator.ActivateInstance(cc, p))
.Cast<T>())
.As((Service)serviceWithType)
.CreateRegistration();
}
}
È possibile registrare in questo modo: builder.RegisterSource(new FilterRegistrationSource())
Non ho ancora testato la pena di prestazioni di questa soluzione, usala con cautela.
Un'altra soluzione interessante sarebbe utilizzare AOP per personalizzare il modo in cui si registrano le registrazioni.
Questo è molto fragile e sconsiglio di provare a filtrare i tipi che sono contrassegnati con '[ContractClass]' o '[ContractClassFor] perché questi stessi attributi sono contrassegnati con' [Conditional ("CONTRACTS_FULL")] 'attributo, il che significa che quando l'assembly è compilato senza il simbolo di compilazione condizionale' CONTRACTS_FULL', il tipo diventerà un tipo 'normale' e sarà nuovamente registrato. È probabile che gli sviluppatori rimuovano questo simbolo nella configurazione RELEASE. Quindi il problema è che questo bug comparirà solo in UAT o in produzione dove effettivamente usi una build di rilascio. – Steven
@ Grazie per questa informazione, non ero a conoscenza di questa caratteristica. Ho modificato la mia risposta. –