@@ -45,9 +45,9 @@ public static void SetProperties(in ParameterView parameters, object target)
45
45
ThrowForUnknownIncomingParameterName ( targetType , parameterName ) ;
46
46
throw null ; // Unreachable
47
47
}
48
- else if ( writer . Cascading && ! parameter . Cascading )
48
+ else if ( ! writer . AcceptsDirectParameters && ! parameter . Cascading )
49
49
{
50
- // We don't allow you to set a cascading parameter with a non-cascading value. Put another way:
50
+ // We don't allow you to set a cascading parameter with a non-cascading (direct) value. Put another way:
51
51
// cascading parameters are not part of the public API of a component, so it's not reasonable
52
52
// for someone to set it directly.
53
53
//
@@ -56,13 +56,23 @@ public static void SetProperties(in ParameterView parameters, object target)
56
56
ThrowForSettingCascadingParameterWithNonCascadingValue ( targetType , parameterName ) ;
57
57
throw null ; // Unreachable
58
58
}
59
- else if ( ! writer . Cascading && parameter . Cascading )
59
+ else if ( ! writer . AcceptsCascadingParameters && parameter . Cascading )
60
60
{
61
61
// We're giving a more specific error here because trying to set a non-cascading parameter
62
62
// with a cascading value is likely deliberate (but not supported), or is a bug in our code.
63
63
ThrowForSettingParameterWithCascadingValue ( targetType , parameterName ) ;
64
64
throw null ; // Unreachable
65
65
}
66
+ else if ( parameter . Cascading && writer . AcceptsDirectParameters && writer . AcceptsCascadingParameters )
67
+ {
68
+ // Today, the only case where this is possible is when a property is annotated with both
69
+ // ParameterAttribute and SupplyParameterFromQueryAttribute. If that happens, we want to
70
+ // prefer the directly supplied value over the cascading value.
71
+ if ( parameters . HasDirectParameter ( parameterName ) )
72
+ {
73
+ continue ;
74
+ }
75
+ }
66
76
67
77
SetProperty ( target , writer , parameterName , parameter . Value ) ;
68
78
}
@@ -82,7 +92,7 @@ public static void SetProperties(in ParameterView parameters, object target)
82
92
83
93
if ( writers . TryGetValue ( parameterName , out var writer ) )
84
94
{
85
- if ( ! writer . Cascading && parameter . Cascading )
95
+ if ( ! writer . AcceptsCascadingParameters && parameter . Cascading )
86
96
{
87
97
// Don't allow an "extra" cascading value to be collected - or don't allow a non-cascading
88
98
// parameter to be set with a cascading value.
@@ -91,7 +101,7 @@ public static void SetProperties(in ParameterView parameters, object target)
91
101
ThrowForSettingParameterWithCascadingValue ( targetType , parameterName ) ;
92
102
throw null ; // Unreachable
93
103
}
94
- else if ( writer . Cascading && ! parameter . Cascading )
104
+ else if ( writer . AcceptsCascadingParameters && ! parameter . Cascading )
95
105
{
96
106
// Allow unmatched parameters to collide with the names of cascading parameters. This is
97
107
// valid because cascading parameter names are not part of the public API. There's no
@@ -196,8 +206,8 @@ private static void ThrowForUnknownIncomingParameterName([DynamicallyAccessedMem
196
206
private static void ThrowForSettingCascadingParameterWithNonCascadingValue ( Type targetType , string parameterName )
197
207
{
198
208
throw new InvalidOperationException (
199
- $ "Object of type ' { targetType . FullName } ' has a property matching the name ' { parameterName } ', " +
200
- $ "but it does not have [ { nameof ( ParameterAttribute ) } ] applied .") ;
209
+ $ "The property ' { parameterName } ' on component type ' { targetType . FullName } ' cannot be set " +
210
+ $ "explicitly because it only accepts cascading values .") ;
201
211
}
202
212
203
213
[ DoesNotReturn ]
@@ -279,8 +289,12 @@ public WritersForType([DynamicallyAccessedMembers(Component)] Type targetType)
279
289
}
280
290
}
281
291
282
- var isParameter = parameterAttribute != null || cascadingParameterAttribute != null ;
283
- if ( ! isParameter )
292
+ // A property cannot accept direct parameters if it's annotated with a cascading value attribute, unless it's a
293
+ // SupplyParameterFromQueryAttribute. This is to retain backwards compatibility with previous versions of the
294
+ // SupplyParameterFromQuery feature that did not utilize cascading values, and thus did not have this limitation.
295
+ var acceptsDirectParameters = parameterAttribute is not null && cascadingParameterAttribute is null or SupplyParameterFromQueryAttribute ;
296
+ var acceptsCascadingParameters = cascadingParameterAttribute is not null ;
297
+ if ( ! acceptsDirectParameters && ! acceptsCascadingParameters )
284
298
{
285
299
continue ;
286
300
}
@@ -294,7 +308,8 @@ public WritersForType([DynamicallyAccessedMembers(Component)] Type targetType)
294
308
295
309
var propertySetter = new PropertySetter ( targetType , propertyInfo )
296
310
{
297
- Cascading = cascadingParameterAttribute != null ,
311
+ AcceptsDirectParameters = acceptsDirectParameters ,
312
+ AcceptsCascadingParameters = acceptsCascadingParameters ,
298
313
} ;
299
314
300
315
if ( _underlyingWriters . ContainsKey ( propertyName ) )
0 commit comments