Make ComponentFactory throw if you try to use [Inject] with a property that has no setter (otherwise it could be confusing)

This commit is contained in:
Steve Sanderson 2018-02-22 21:35:18 +00:00
parent b4a3c852c5
commit 3f9d358004
2 changed files with 29 additions and 17 deletions

View File

@ -52,16 +52,25 @@ namespace Microsoft.AspNetCore.Blazor.Components
// Do all the reflection up front
var injectableProperties = type.GetTypeInfo()
.GetProperties(_injectablePropertyBindingFlags)
.Where(p => p.GetCustomAttribute<InjectAttribute>() != null)
.Where(p => p.SetMethod != null);
.Where(p => p.GetCustomAttribute<InjectAttribute>() != null);
var injectables = injectableProperties.Select(property =>
(
propertyName: property.Name,
propertyType: property.PropertyType,
setter: (IPropertySetter)Activator.CreateInstance(
typeof(PropertySetter<,>).MakeGenericType(type, property.PropertyType),
property.SetMethod)
)).ToArray();
{
if (property.SetMethod == null)
{
throw new InvalidOperationException($"Cannot provide a value for property " +
$"'{property.Name}' on type '{type.FullName}' because the property " +
$"has no setter.");
}
return
(
propertyName: property.Name,
propertyType: property.PropertyType,
setter: (IPropertySetter)Activator.CreateInstance(
typeof(PropertySetter<,>).MakeGenericType(type, property.PropertyType),
property.SetMethod)
);
}).ToArray();
// Return an action whose closure can write all the injected properties
// without any further reflection calls (just typecasts)
@ -72,7 +81,7 @@ namespace Microsoft.AspNetCore.Blazor.Components
var serviceInstance = _serviceProvider.GetService(injectable.propertyType);
if (serviceInstance == null)
{
throw new InvalidOperationException($"Cannot provide value for property " +
throw new InvalidOperationException($"Cannot provide a value for property " +
$"'{injectable.propertyName}' on type '{type.FullName}'. There is no " +
$"registered service of type '{injectable.propertyType}'.");
}

View File

@ -42,13 +42,16 @@ namespace Microsoft.AspNetCore.Blazor.Test
}
[Fact]
public void IgnoresGetOnlyProperties()
public void ThrowsForInjectablePropertiesWithoutSetter()
{
// Arrange/Act
var component = InstantiateComponent<HasGetOnlyProperty>();
var ex = Assert.Throws<InvalidOperationException>(() =>
{
InstantiateComponent<HasGetOnlyPropertyWithInject>();
});
// Assert
Assert.Null(component.MyService);
Assert.Equal($"Cannot provide a value for property '{nameof(HasInjectableProperty.MyService)}' " +
$"on type '{typeof(HasGetOnlyPropertyWithInject).FullName}' because the property " +
$"has no setter.", ex.Message);
}
[Fact]
@ -59,7 +62,7 @@ namespace Microsoft.AspNetCore.Blazor.Test
InstantiateComponent<HasInjectableProperty>();
});
Assert.Equal($"Cannot provide value for property '{nameof(HasInjectableProperty.MyService)}' " +
Assert.Equal($"Cannot provide a value for property '{nameof(HasInjectableProperty.MyService)}' " +
$"on type '{typeof(HasInjectableProperty).FullName}'. There is no registered service " +
$"of type '{typeof(IMyService).FullName}'.", ex.Message);
}
@ -130,7 +133,7 @@ namespace Microsoft.AspNetCore.Blazor.Test
public static IMyService StaticPropertyWithoutInject { get; set; }
}
class HasGetOnlyProperty : TestComponent
class HasGetOnlyPropertyWithInject : TestComponent
{
[Inject] public IMyService MyService { get; }
}