Skip to content

Commit 44f8b9d

Browse files
Fix tests by supporting TryAddCascadingValue
1 parent a27e4c4 commit 44f8b9d

File tree

4 files changed

+108
-1
lines changed

4 files changed

+108
-1
lines changed

src/Components/Components/src/CascadingValueServiceCollectionExtensions.cs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using Microsoft.AspNetCore.Components;
5+
using Microsoft.Extensions.DependencyInjection.Extensions;
56

67
namespace Microsoft.Extensions.DependencyInjection;
78

@@ -50,4 +51,59 @@ public static IServiceCollection AddCascadingValue<TValue>(
5051
public static IServiceCollection AddCascadingValue<TValue>(
5152
this IServiceCollection serviceCollection, Func<IServiceProvider, CascadingValueSource<TValue>> sourceFactory)
5253
=> serviceCollection.AddScoped<ICascadingValueSupplier>(sourceFactory);
54+
55+
/// <summary>
56+
/// Adds a cascading value to the <paramref name="serviceCollection"/>, if none is already registered
57+
/// with the value type. This is equivalent to having a fixed <see cref="CascadingValue{TValue}"/> at
58+
/// the root of the component hierarchy.
59+
/// </summary>
60+
/// <typeparam name="TValue">The value type.</typeparam>
61+
/// <param name="serviceCollection">The <see cref="IServiceCollection"/>.</param>
62+
/// <param name="valueFactory">A callback that supplies a fixed value within each service provider scope.</param>
63+
/// <returns>The <see cref="IServiceCollection"/>.</returns>
64+
public static void TryAddCascadingValue<TValue>(
65+
this IServiceCollection serviceCollection, Func<IServiceProvider, TValue> valueFactory)
66+
{
67+
serviceCollection.TryAddEnumerable(
68+
ServiceDescriptor.Scoped<ICascadingValueSupplier, CascadingValueSource<TValue>>(
69+
sp => new CascadingValueSource<TValue>(() => valueFactory(sp), isFixed: true)));
70+
}
71+
72+
/// <summary>
73+
/// Adds a cascading value to the <paramref name="serviceCollection"/>, if none is already registered
74+
/// with the value type, regardless of the <paramref name="name"/>. This is equivalent to having a fixed
75+
/// <see cref="CascadingValue{TValue}"/> at the root of the component hierarchy.
76+
/// </summary>
77+
/// <typeparam name="TValue">The value type.</typeparam>
78+
/// <param name="serviceCollection">The <see cref="IServiceCollection"/>.</param>
79+
/// <param name="name">A name for the cascading value. If set, <see cref="CascadingParameterAttribute"/> can be configured to match based on this name.</param>
80+
/// <param name="valueFactory">A callback that supplies a fixed value within each service provider scope.</param>
81+
/// <returns>The <see cref="IServiceCollection"/>.</returns>
82+
public static void TryAddCascadingValue<TValue>(
83+
this IServiceCollection serviceCollection, string name, Func<IServiceProvider, TValue> valueFactory)
84+
{
85+
serviceCollection.TryAddEnumerable(
86+
ServiceDescriptor.Scoped<ICascadingValueSupplier, CascadingValueSource<TValue>>(
87+
sp => new CascadingValueSource<TValue>(name, () => valueFactory(sp), isFixed: true)));
88+
}
89+
90+
/// <summary>
91+
/// Adds a cascading value to the <paramref name="serviceCollection"/>, if none is already registered
92+
/// with the value type. This is equivalent to having a fixed <see cref="CascadingValue{TValue}"/> at
93+
/// the root of the component hierarchy.
94+
///
95+
/// With this overload, you can supply a <see cref="CascadingValueSource{TValue}"/> which allows you
96+
/// to notify about updates to the value later, causing recipients to re-render. This overload should
97+
/// only be used if you plan to update the value dynamically.
98+
/// </summary>
99+
/// <typeparam name="TValue">The value type.</typeparam>
100+
/// <param name="serviceCollection">The <see cref="IServiceCollection"/>.</param>
101+
/// <param name="sourceFactory">A callback that supplies a <see cref="CascadingValueSource{TValue}"/> within each service provider scope.</param>
102+
/// <returns>The <see cref="IServiceCollection"/>.</returns>
103+
public static void TryAddCascadingValue<TValue>(
104+
this IServiceCollection serviceCollection, Func<IServiceProvider, CascadingValueSource<TValue>> sourceFactory)
105+
{
106+
serviceCollection.TryAddEnumerable(
107+
ServiceDescriptor.Scoped<ICascadingValueSupplier, CascadingValueSource<TValue>>(sourceFactory));
108+
}
53109
}

src/Components/Components/src/PublicAPI.Unshipped.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ static Microsoft.AspNetCore.Components.SupplyParameterFromQueryProviderServiceCo
9191
static Microsoft.Extensions.DependencyInjection.CascadingValueServiceCollectionExtensions.AddCascadingValue<TValue>(this Microsoft.Extensions.DependencyInjection.IServiceCollection! serviceCollection, string! name, System.Func<System.IServiceProvider!, TValue>! valueFactory) -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
9292
static Microsoft.Extensions.DependencyInjection.CascadingValueServiceCollectionExtensions.AddCascadingValue<TValue>(this Microsoft.Extensions.DependencyInjection.IServiceCollection! serviceCollection, System.Func<System.IServiceProvider!, Microsoft.AspNetCore.Components.CascadingValueSource<TValue>!>! sourceFactory) -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
9393
static Microsoft.Extensions.DependencyInjection.CascadingValueServiceCollectionExtensions.AddCascadingValue<TValue>(this Microsoft.Extensions.DependencyInjection.IServiceCollection! serviceCollection, System.Func<System.IServiceProvider!, TValue>! valueFactory) -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
94+
static Microsoft.Extensions.DependencyInjection.CascadingValueServiceCollectionExtensions.TryAddCascadingValue<TValue>(this Microsoft.Extensions.DependencyInjection.IServiceCollection! serviceCollection, string! name, System.Func<System.IServiceProvider!, TValue>! valueFactory) -> void
95+
static Microsoft.Extensions.DependencyInjection.CascadingValueServiceCollectionExtensions.TryAddCascadingValue<TValue>(this Microsoft.Extensions.DependencyInjection.IServiceCollection! serviceCollection, System.Func<System.IServiceProvider!, Microsoft.AspNetCore.Components.CascadingValueSource<TValue>!>! sourceFactory) -> void
96+
static Microsoft.Extensions.DependencyInjection.CascadingValueServiceCollectionExtensions.TryAddCascadingValue<TValue>(this Microsoft.Extensions.DependencyInjection.IServiceCollection! serviceCollection, System.Func<System.IServiceProvider!, TValue>! valueFactory) -> void
9497
virtual Microsoft.AspNetCore.Components.NavigationManager.Refresh(bool forceReload = false) -> void
9598
virtual Microsoft.AspNetCore.Components.Rendering.ComponentState.DisposeAsync() -> System.Threading.Tasks.ValueTask
9699
virtual Microsoft.AspNetCore.Components.RenderTree.Renderer.AddPendingTask(Microsoft.AspNetCore.Components.Rendering.ComponentState? componentState, System.Threading.Tasks.Task! task) -> void

src/Components/Components/test/CascadingParameterTest.cs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -727,6 +727,51 @@ public void OmitsSingleDeliveryCascadingParametersWhenUpdatingDirectParameters()
727727
});
728728
}
729729

730+
[Fact]
731+
public void CanUseTryAddPatternForCascadingValuesInServiceCollection_ValueFactory()
732+
{
733+
// Arrange
734+
var services = new ServiceCollection();
735+
736+
// Act
737+
services.TryAddCascadingValue(_ => new Type1());
738+
services.TryAddCascadingValue(_ => new Type1());
739+
services.TryAddCascadingValue(_ => new Type2());
740+
741+
// Assert
742+
Assert.Equal(2, services.Count());
743+
}
744+
745+
[Fact]
746+
public void CanUseTryAddPatternForCascadingValuesInServiceCollection_NamedValueFactory()
747+
{
748+
// Arrange
749+
var services = new ServiceCollection();
750+
751+
// Act
752+
services.TryAddCascadingValue("Name1", _ => new Type1());
753+
services.TryAddCascadingValue("Name2", _ => new Type1());
754+
services.TryAddCascadingValue("Name3", _ => new Type2());
755+
756+
// Assert
757+
Assert.Equal(2, services.Count());
758+
}
759+
760+
[Fact]
761+
public void CanUseTryAddPatternForCascadingValuesInServiceCollection_CascadingValueSource()
762+
{
763+
// Arrange
764+
var services = new ServiceCollection();
765+
766+
// Act
767+
services.TryAddCascadingValue(_ => new CascadingValueSource<Type1>("Name1", new Type1(), false));
768+
services.TryAddCascadingValue(_ => new CascadingValueSource<Type1>("Name2", new Type1(), false));
769+
services.TryAddCascadingValue(_ => new CascadingValueSource<Type2>("Name3", new Type2(), false));
770+
771+
// Assert
772+
Assert.Equal(2, services.Count());
773+
}
774+
730775
private class SingleDeliveryValue(string text)
731776
{
732777
public string Text => text;
@@ -940,4 +985,7 @@ public void ChangeValue(string newValue)
940985
StringValue = newValue;
941986
}
942987
}
988+
989+
class Type1 { }
990+
class Type2 { }
943991
}

src/Components/Endpoints/src/DependencyInjection/RazorComponentsServiceCollectionExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ public static IRazorComponentsBuilder AddRazorComponents(this IServiceCollection
6363
services.TryAddScoped<EndpointRoutingStateProvider>();
6464
services.TryAddScoped<IRoutingStateProvider>(sp => sp.GetRequiredService<EndpointRoutingStateProvider>());
6565
services.AddSupplyValueFromQueryProvider();
66-
services.AddCascadingValue(sp => sp.GetRequiredService<EndpointHtmlRenderer>().HttpContext);
66+
services.TryAddCascadingValue(sp => sp.GetRequiredService<EndpointHtmlRenderer>().HttpContext);
6767

6868
// Form handling
6969
services.AddSupplyValueFromFormProvider();

0 commit comments

Comments
 (0)