Skip to content

Commit a1d49e1

Browse files
SteveSandersonMSnatemcmaster
authored andcommitted
Revert feature that resets unspecified parameters to default(type). Fixes #6864 (#6931)
1 parent 1fe7f5e commit a1d49e1

File tree

9 files changed

+36
-74
lines changed

9 files changed

+36
-74
lines changed

src/Components/Blazor/testassets/StandaloneApp/Pages/FetchData.cshtml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,14 @@ else
4848

4949
WeatherForecast[] forecasts;
5050

51-
protected override async Task OnParametersSetAsync()
51+
public override Task SetParametersAsync(ParameterCollection parameters)
5252
{
53-
// If no value was given in the URL for StartDate, apply a default
54-
if (StartDate == default)
55-
{
56-
StartDate = DateTime.Now;
57-
}
53+
StartDate = DateTime.Now;
54+
return base.SetParametersAsync(parameters);
55+
}
5856

57+
protected override async Task OnParametersSetAsync()
58+
{
5959
forecasts = await Http.GetJsonAsync<WeatherForecast[]>(
6060
$"sample-data/weather.json?date={StartDate.ToString("yyyy-MM-dd")}");
6161

src/Components/Components/src/Microsoft.AspNetCore.Components.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
<PropertyGroup>
44
<TargetFramework>netstandard2.0</TargetFramework>
55
<Description>Components feature for ASP.NET Core.</Description>
6-
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
76
<IsShippingPackage>true</IsShippingPackage>
87
</PropertyGroup>
98

src/Components/Components/src/ParameterCollectionExtensions.cs

Lines changed: 6 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ private readonly static ConcurrentDictionary<Type, WritersForType> _cachedWriter
2525
/// </summary>
2626
/// <param name="parameterCollection">The <see cref="ParameterCollection"/>.</param>
2727
/// <param name="target">An object that has a public writable property matching each parameter's name and type.</param>
28-
public unsafe static void SetParameterProperties(
28+
public static void SetParameterProperties(
2929
in this ParameterCollection parameterCollection,
3030
object target)
3131
{
@@ -41,17 +41,6 @@ public unsafe static void SetParameterProperties(
4141
_cachedWritersByType[targetType] = writers;
4242
}
4343

44-
// We only want to iterate through the parameterCollection once, and by the end of it,
45-
// need to have tracked which of the parameter properties haven't yet been written.
46-
// To avoid allocating any list/dictionary to track that, here we stackalloc an array
47-
// of flags and set them based on the indices of the writers we use.
48-
var numWriters = writers.WritersByIndex.Count;
49-
var numUsedWriters = 0;
50-
51-
// TODO: Once we're able to move to netstandard2.1, this can be changed to be
52-
// a Span<bool> and then the enclosing method no longer needs to be 'unsafe'
53-
bool* usageFlags = stackalloc bool[numWriters];
54-
5544
foreach (var parameter in parameterCollection)
5645
{
5746
var parameterName = parameter.Name;
@@ -62,9 +51,7 @@ public unsafe static void SetParameterProperties(
6251

6352
try
6453
{
65-
writerWithIndex.Writer.SetValue(target, parameter.Value);
66-
usageFlags[writerWithIndex.Index] = true;
67-
numUsedWriters++;
54+
writerWithIndex.SetValue(target, parameter.Value);
6855
}
6956
catch (Exception ex)
7057
{
@@ -73,23 +60,6 @@ public unsafe static void SetParameterProperties(
7360
$"type '{target.GetType().FullName}'. The error was: {ex.Message}", ex);
7461
}
7562
}
76-
77-
// Now we can determine whether any writers have not been used, and if there are
78-
// some unused ones, find them.
79-
for (var index = 0; numUsedWriters < numWriters; index++)
80-
{
81-
if (index >= numWriters)
82-
{
83-
// This should not be possible
84-
throw new InvalidOperationException("Ran out of writers before marking them all as used.");
85-
}
86-
87-
if (!usageFlags[index])
88-
{
89-
writers.WritersByIndex[index].SetDefaultValue(target);
90-
numUsedWriters++;
91-
}
92-
}
9363
}
9464

9565
internal static IEnumerable<PropertyInfo> GetCandidateBindableProperties(Type targetType)
@@ -125,12 +95,11 @@ private static void ThrowForUnknownIncomingParameterName(Type targetType, string
12595

12696
class WritersForType
12797
{
128-
public Dictionary<string, (int Index, IPropertySetter Writer)> WritersByName { get; }
129-
public List<IPropertySetter> WritersByIndex { get; }
98+
public Dictionary<string, IPropertySetter> WritersByName { get; }
13099

131100
public WritersForType(Type targetType)
132101
{
133-
var propertySettersByName = new Dictionary<string, IPropertySetter>(StringComparer.OrdinalIgnoreCase);
102+
WritersByName = new Dictionary<string, IPropertySetter>(StringComparer.OrdinalIgnoreCase);
134103
foreach (var propertyInfo in GetCandidateBindableProperties(targetType))
135104
{
136105
var shouldCreateWriter = propertyInfo.IsDefined(typeof(ParameterAttribute))
@@ -143,24 +112,14 @@ public WritersForType(Type targetType)
143112
var propertySetter = MemberAssignment.CreatePropertySetter(targetType, propertyInfo);
144113

145114
var propertyName = propertyInfo.Name;
146-
if (propertySettersByName.ContainsKey(propertyName))
115+
if (WritersByName.ContainsKey(propertyName))
147116
{
148117
throw new InvalidOperationException(
149118
$"The type '{targetType.FullName}' declares more than one parameter matching the " +
150119
$"name '{propertyName.ToLowerInvariant()}'. Parameter names are case-insensitive and must be unique.");
151120
}
152121

153-
propertySettersByName.Add(propertyName, propertySetter);
154-
}
155-
156-
// Now we know all the entries, construct the resulting list/dictionary
157-
// with well-defined indices
158-
WritersByIndex = new List<IPropertySetter>();
159-
WritersByName = new Dictionary<string, (int, IPropertySetter)>(StringComparer.OrdinalIgnoreCase);
160-
foreach (var pair in propertySettersByName)
161-
{
162-
WritersByName.Add(pair.Key, (WritersByIndex.Count, pair.Value));
163-
WritersByIndex.Add(pair.Value);
122+
WritersByName.Add(propertyName, propertySetter);
164123
}
165124
}
166125
}

src/Components/Components/src/Reflection/IPropertySetter.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,5 @@ namespace Microsoft.AspNetCore.Components.Reflection
66
internal interface IPropertySetter
77
{
88
void SetValue(object target, object value);
9-
10-
void SetDefaultValue(object target);
119
}
1210
}

src/Components/Components/src/Reflection/MemberAssignment.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,10 @@ public PropertySetter(MethodInfo setMethod)
4848
{
4949
_setterDelegate = (Action<TTarget, TValue>)Delegate.CreateDelegate(
5050
typeof(Action<TTarget, TValue>), setMethod);
51-
var propertyType = typeof(TValue);
5251
}
5352

5453
public void SetValue(object target, object value)
5554
=> _setterDelegate((TTarget)target, (TValue)value);
56-
57-
public void SetDefaultValue(object target)
58-
=> _setterDelegate((TTarget)target, default);
5955
}
6056
}
6157
}

src/Components/Components/test/ParameterCollectionAssignmentExtensionsTest.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ public void IncomingParameterMatchesInheritedDeclaredParameter_SetsValue()
7373
}
7474

7575
[Fact]
76-
public void NoIncomingParameterMatchesDeclaredParameter_SetValuesDefault()
76+
public void NoIncomingParameterMatchesDeclaredParameter_LeavesValueUnchanged()
7777
{
7878
// Arrange
7979
var existingObjectValue = new object();
@@ -90,9 +90,9 @@ public void NoIncomingParameterMatchesDeclaredParameter_SetValuesDefault()
9090
parameterCollection.SetParameterProperties(target);
9191

9292
// Assert
93-
Assert.Equal(0, target.IntProp);
94-
Assert.Null(target.StringProp);
95-
Assert.Null(target.ObjectPropCurrentValue);
93+
Assert.Equal(456, target.IntProp);
94+
Assert.Equal("Existing value", target.StringProp);
95+
Assert.Same(existingObjectValue, target.ObjectPropCurrentValue);
9696
}
9797

9898
[Fact]

src/Components/test/E2ETest/Tests/RoutingTest.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,10 @@ public void CanFollowLinkToPageWithParameters()
221221
AssertHighlightedLinks("With parameters", "With more parameters");
222222

223223
// Can remove parameters while remaining on same page
224+
// WARNING: This only works because the WithParameters component overrides SetParametersAsync
225+
// and explicitly resets its parameters to default when each new set of parameters arrives.
226+
// Without that, the page would retain the old value.
227+
// See https://github.com/aspnet/AspNetCore/issues/6864 where we reverted the logic to auto-reset.
224228
app.FindElement(By.LinkText("With parameters")).Click();
225229
WaitAssert.Equal("Your full name is Abc .", () => app.FindElement(By.Id("test-info")).Text);
226230
AssertHighlightedLinks("With parameters");

src/Components/test/testassets/BasicTestApp/RouterTest/WithParameters.cshtml

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,15 @@
55

66
@functions
77
{
8-
[Parameter]
9-
string FirstName { get; set; }
8+
[Parameter] string FirstName { get; set; }
109

11-
[Parameter]
12-
string LastName { get ; set; }
10+
[Parameter] string LastName { get ; set; }
11+
12+
public override Task SetParametersAsync(ParameterCollection parameters)
13+
{
14+
// Manually reset parameters to defaults so we don't retain any from an earlier URL
15+
FirstName = default;
16+
LastName = default;
17+
return base.SetParametersAsync(parameters);
18+
}
1319
}

src/Components/test/testassets/ComponentsApp.App/Pages/FetchData.cshtml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,14 @@ else
4848

4949
WeatherForecast[] forecasts;
5050

51-
protected override async Task OnParametersSetAsync()
51+
public override Task SetParametersAsync(ParameterCollection parameters)
5252
{
53-
// If no value was given in the URL for StartDate, apply a default
54-
if (StartDate == default)
55-
{
56-
StartDate = DateTime.Now;
57-
}
53+
StartDate = DateTime.Now;
54+
return base.SetParametersAsync(parameters);
55+
}
5856

57+
protected override async Task OnParametersSetAsync()
58+
{
5959
forecasts = await ForecastService.GetForecastAsync(StartDate);
6060
}
6161
}

0 commit comments

Comments
 (0)