I'm trying to find a way in Autofac to support specific properties injection instead of overall properties injection. Authought Autofac currently provides PropertiesAutowired to support an overall properties injection, but in some cases I need only specific properties injection (like [Inject] attribute used in NInject).
Here I found a snippet (WithPropertiesAutowired, provided by Alexandr Nikitin, thanks!) in this post that the codes can support specific properties injections:
public static class PropertiesAutowiredExtensions
{
// Extension that registers only needed properties
// Filters by property name for simplicity
public static IRegistrationBuilder<TLimit, TReflectionActivatorData, TRegistrationStyle>
WithPropertiesAutowiredExcept<TLimit, TReflectionActivatorData, TRegistrationStyle>(
this IRegistrationBuilder<TLimit, TReflectionActivatorData, TRegistrationStyle> registrationBuilder,
params string[] propertiesNames)
where TReflectionActivatorData : ReflectionActivatorData
{
var type = ((IServiceWithType)registrationBuilder.RegistrationData.Services.Single()).ServiceType;
foreach (var property in type
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(pi => pi.CanWrite && !propertiesNames.Contains(pi.Name)))
{
// There's no additional checks like in PropertiesAutowired for simplicity
// You can add them from Autofac.Core.Activators.Reflection.AutowiringPropertyInjector.InjectProperties
var localProperty = property;
registrationBuilder.WithProperty(
new ResolvedParameter(
(pi, c) =>
{
PropertyInfo prop;
return pi.TryGetDeclaringProperty(out prop) &&
prop.Name == localProperty.Name;
},
(pi, c) => c.Resolve(localProperty.PropertyType)));
}
return registrationBuilder;
}
// From Autofac.Util.ReflectionExtensions
public static bool TryGetDeclaringProperty(this ParameterInfo pi, out PropertyInfo prop)
{
var mi = pi.Member as MethodInfo;
if (mi != null && mi.IsSpecialName && mi.Name.StartsWith("set_", StringComparison.Ordinal)
&& mi.DeclaringType != null)
{
prop = mi.DeclaringType.GetProperty(mi.Name.Substring(4));
return true;
}
prop = null;
return false;
}
}
it works fine in general cases. But when I use the codes in a LifeTime scope, it fails:
using (var scope = container.BeginLifetimeScope(
builder => {
builder.RegisterInstance(SomeInstance).As<ISomeInstance>()
.WithPropertiesAutowired("Property1", "Property2"); }))
{
...
}
Here is the error message:
The type 'Autofac.Builder.SimpleActivatorData' cannot be used as type parameter 'TReflectionActivatorData' in the generic type or method
'....AutofacHelpers.WithPropertiesAutowired<TLimit,TReflectionActivatorData,TRegistrationStyle>(
Autofac.Builder.IRegistrationBuilder<TLimit,TReflectionActivatorData,TRegistrationStyle>, params string[])'.
There is no implicit reference conversion from 'Autofac.Builder.SimpleActivatorData' to 'Autofac.Builder.ReflectionActivatorData'.
It seems WithPropertiesAutowired can only be used in a Container, but not for LitfeTime scope. How can I resolve this issue?