Skip to content

Commit 8f99347

Browse files
committed
Merge branch 'main' into darc-main-1709b9ed-50a0-4e28-b9b8-0e3759aee720
2 parents 6fbf14b + 051aa95 commit 8f99347

File tree

144 files changed

+4110
-913
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

144 files changed

+4110
-913
lines changed

.editorconfig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,9 @@ dotnet_diagnostic.CA1846.severity = suggestion
244244
dotnet_diagnostic.CA2008.severity = suggestion
245245
# CA2012: Use ValueTask correctly
246246
dotnet_diagnostic.CA2012.severity = suggestion
247+
# IDE0044: Make field readonly
248+
dotnet_diagnostic.IDE0044.severity = suggestion
249+
247250

248251
# CA2016: Forward the 'CancellationToken' parameter to methods that take one
249252
dotnet_diagnostic.CA2016.severity = suggestion

eng/Versions.props

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -250,9 +250,9 @@
250250
<PlaywrightSharpVersion>0.192.0</PlaywrightSharpVersion>
251251
<PollyExtensionsHttpVersion>3.0.0</PollyExtensionsHttpVersion>
252252
<PollyVersion>7.2.2</PollyVersion>
253-
<SeleniumSupportVersion>4.0.0-beta2</SeleniumSupportVersion>
253+
<SeleniumSupportVersion>4.0.0-beta4</SeleniumSupportVersion>
254254
<SeleniumWebDriverChromeDriverVersion>91.0.4472.1900</SeleniumWebDriverChromeDriverVersion>
255-
<SeleniumWebDriverVersion>4.0.0-beta2</SeleniumWebDriverVersion>
255+
<SeleniumWebDriverVersion>4.0.0-beta4</SeleniumWebDriverVersion>
256256
<SerilogExtensionsLoggingVersion>1.4.0</SerilogExtensionsLoggingVersion>
257257
<SerilogSinksFileVersion>4.0.0</SerilogSinksFileVersion>
258258
<StackExchangeRedisVersion>2.2.4</StackExchangeRedisVersion>

src/Components/Authorization/test/AuthorizeRouteViewTest.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Components.Authorization
1616
{
1717
public class AuthorizeRouteViewTest
1818
{
19-
private readonly static IReadOnlyDictionary<string, object> EmptyParametersDictionary = new Dictionary<string, object>();
19+
private static readonly IReadOnlyDictionary<string, object> EmptyParametersDictionary = new Dictionary<string, object>();
2020
private readonly TestAuthenticationStateProvider _authenticationStateProvider;
2121
private readonly TestRenderer _renderer;
2222
private readonly RouteView _authorizeRouteViewComponent;
@@ -35,6 +35,7 @@ public AuthorizeRouteViewTest()
3535
serviceCollection.AddSingleton<AuthenticationStateProvider>(_authenticationStateProvider);
3636
serviceCollection.AddSingleton<IAuthorizationPolicyProvider, TestAuthorizationPolicyProvider>();
3737
serviceCollection.AddSingleton<IAuthorizationService>(_testAuthorizationService);
38+
serviceCollection.AddSingleton<NavigationManager, TestNavigationManager>();
3839

3940
_renderer = new TestRenderer(serviceCollection.BuildServiceProvider());
4041
_authorizeRouteViewComponent = new AuthorizeRouteView();
@@ -424,5 +425,9 @@ protected override void BuildRenderTree(RenderTreeBuilder builder)
424425
builder.CloseComponent();
425426
}
426427
}
428+
429+
class TestNavigationManager : NavigationManager
430+
{
431+
}
427432
}
428433
}

src/Components/Components.slnf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@
6969
"src\\Http\\Routing.Abstractions\\src\\Microsoft.AspNetCore.Routing.Abstractions.csproj",
7070
"src\\Http\\Routing\\src\\Microsoft.AspNetCore.Routing.csproj",
7171
"src\\Http\\WebUtilities\\src\\Microsoft.AspNetCore.WebUtilities.csproj",
72+
"src\\Identity\\ApiAuthorization.IdentityServer\\src\\Microsoft.AspNetCore.ApiAuthorization.IdentityServer.csproj",
73+
"src\\Identity\\EntityFrameworkCore\\src\\Microsoft.AspNetCore.Identity.EntityFrameworkCore.csproj",
74+
"src\\Identity\\UI\\src\\Microsoft.AspNetCore.Identity.UI.csproj",
7275
"src\\JSInterop\\Microsoft.JSInterop\\src\\Microsoft.JSInterop.csproj",
7376
"src\\Middleware\\CORS\\src\\Microsoft.AspNetCore.Cors.csproj",
7477
"src\\Middleware\\Diagnostics.Abstractions\\src\\Microsoft.AspNetCore.Diagnostics.Abstractions.csproj",
@@ -96,8 +99,10 @@
9699
"src\\Mvc\\Mvc\\src\\Microsoft.AspNetCore.Mvc.csproj",
97100
"src\\Razor\\Razor.Runtime\\src\\Microsoft.AspNetCore.Razor.Runtime.csproj",
98101
"src\\Razor\\Razor\\src\\Microsoft.AspNetCore.Razor.csproj",
102+
"src\\Security\\Authentication\\Cookies\\src\\Microsoft.AspNetCore.Authentication.Cookies.csproj",
99103
"src\\Security\\Authorization\\Core\\src\\Microsoft.AspNetCore.Authorization.csproj",
100104
"src\\Security\\Authorization\\Policy\\src\\Microsoft.AspNetCore.Authorization.Policy.csproj",
105+
"src\\Security\\CookiePolicy\\src\\Microsoft.AspNetCore.CookiePolicy.csproj",
101106
"src\\Servers\\Connections.Abstractions\\src\\Microsoft.AspNetCore.Connections.Abstractions.csproj",
102107
"src\\Servers\\IIS\\IISIntegration\\src\\Microsoft.AspNetCore.Server.IISIntegration.csproj",
103108
"src\\Servers\\IIS\\IIS\\src\\Microsoft.AspNetCore.Server.IIS.csproj",

src/Components/Components/src/BindConverter.cs

Lines changed: 94 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
using System.Diagnostics.CodeAnalysis;
88
using System.Globalization;
99
using System.Reflection;
10+
using System.Text;
11+
using System.Text.Json;
1012

1113
namespace Microsoft.AspNetCore.Components
1214
{
@@ -523,7 +525,7 @@ public static bool TryConvertToString(object? obj, CultureInfo? culture, out str
523525
return ConvertToStringCore(obj, culture, out value);
524526
}
525527

526-
internal readonly static BindParser<string?> ConvertToString = ConvertToStringCore;
528+
internal static readonly BindParser<string?> ConvertToString = ConvertToStringCore;
527529

528530
private static bool ConvertToStringCore(object? obj, CultureInfo? culture, out string? value)
529531
{
@@ -556,8 +558,8 @@ public static bool TryConvertToNullableBool(object? obj, CultureInfo? culture, o
556558
return ConvertToNullableBoolCore(obj, culture, out value);
557559
}
558560

559-
internal readonly static BindParser<bool> ConvertToBool = ConvertToBoolCore;
560-
internal readonly static BindParser<bool?> ConvertToNullableBool = ConvertToNullableBoolCore;
561+
internal static readonly BindParser<bool> ConvertToBool = ConvertToBoolCore;
562+
internal static readonly BindParser<bool?> ConvertToNullableBool = ConvertToNullableBoolCore;
561563

562564
private static bool ConvertToBoolCore(object? obj, CultureInfo? culture, out bool value)
563565
{
@@ -1278,8 +1280,18 @@ private static bool ConvertToNullableEnum<T>(object? obj, CultureInfo? culture,
12781280

12791281
private static class FormatterDelegateCache
12801282
{
1281-
private readonly static ConcurrentDictionary<Type, Delegate> _cache = new ConcurrentDictionary<Type, Delegate>();
1283+
private static readonly ConcurrentDictionary<Type, Delegate> _cache = new ConcurrentDictionary<Type, Delegate>();
12821284

1285+
private static MethodInfo? _makeArrayFormatter;
1286+
1287+
[UnconditionalSuppressMessage(
1288+
"ReflectionAnalysis",
1289+
"IL2060:MakeGenericMethod",
1290+
Justification = "The referenced methods don't have any DynamicallyAccessedMembers annotations. See https://github.com/mono/linker/issues/1727")]
1291+
[UnconditionalSuppressMessage(
1292+
"ReflectionAnalysis",
1293+
"IL2075:MakeGenericMethod",
1294+
Justification = "The referenced methods don't have any DynamicallyAccessedMembers annotations. See https://github.com/mono/linker/issues/1727")]
12831295
public static BindFormatter<T> Get<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>()
12841296
{
12851297
if (!_cache.TryGetValue(typeof(T), out var formatter))
@@ -1366,6 +1378,12 @@ private static class FormatterDelegateCache
13661378
{
13671379
formatter = (BindFormatter<T>)FormatEnumValueCore<T>;
13681380
}
1381+
else if (typeof(T).IsArray)
1382+
{
1383+
var method = _makeArrayFormatter ??= typeof(FormatterDelegateCache).GetMethod(nameof(MakeArrayFormatter), BindingFlags.NonPublic | BindingFlags.Static)!;
1384+
var elementType = typeof(T).GetElementType()!;
1385+
formatter = (Delegate)method.MakeGenericMethod(elementType).Invoke(null, null)!;
1386+
}
13691387
else
13701388
{
13711389
formatter = MakeTypeConverterFormatter<T>();
@@ -1377,6 +1395,36 @@ private static class FormatterDelegateCache
13771395
return (BindFormatter<T>)formatter;
13781396
}
13791397

1398+
private static BindFormatter<T[]> MakeArrayFormatter<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>()
1399+
{
1400+
var elementFormatter = Get<T>();
1401+
1402+
return FormatArrayValue;
1403+
1404+
string? FormatArrayValue(T[] value, CultureInfo? culture)
1405+
{
1406+
if (value.Length == 0)
1407+
{
1408+
return "[]";
1409+
}
1410+
1411+
var builder = new StringBuilder("[\"");
1412+
builder.Append(JsonEncodedText.Encode(elementFormatter(value[0], culture)?.ToString() ?? string.Empty));
1413+
builder.Append('\"');
1414+
1415+
for (var i = 1; i < value.Length; i++)
1416+
{
1417+
builder.Append(", \"");
1418+
builder.Append(JsonEncodedText.Encode(elementFormatter(value[i], culture)?.ToString() ?? string.Empty));
1419+
builder.Append('\"');
1420+
}
1421+
1422+
builder.Append(']');
1423+
1424+
return builder.ToString();
1425+
}
1426+
}
1427+
13801428
private static BindFormatter<T> MakeTypeConverterFormatter<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>()
13811429
{
13821430
var typeConverter = TypeDescriptor.GetConverter(typeof(T));
@@ -1400,15 +1448,20 @@ string FormatWithTypeConverter(T value, CultureInfo? culture)
14001448

14011449
internal static class ParserDelegateCache
14021450
{
1403-
private readonly static ConcurrentDictionary<Type, Delegate> _cache = new ConcurrentDictionary<Type, Delegate>();
1451+
private static readonly ConcurrentDictionary<Type, Delegate> _cache = new ConcurrentDictionary<Type, Delegate>();
14041452

14051453
private static MethodInfo? _convertToEnum;
14061454
private static MethodInfo? _convertToNullableEnum;
1455+
private static MethodInfo? _makeArrayTypeConverter;
14071456

14081457
[UnconditionalSuppressMessage(
14091458
"ReflectionAnalysis",
14101459
"IL2060:MakeGenericMethod",
14111460
Justification = "The referenced methods don't have any DynamicallyAccessedMembers annotations. See https://github.com/mono/linker/issues/1727")]
1461+
[UnconditionalSuppressMessage(
1462+
"ReflectionAnalysis",
1463+
"IL2075:MakeGenericMethod",
1464+
Justification = "The referenced methods don't have any DynamicallyAccessedMembers annotations. See https://github.com/mono/linker/issues/1727")]
14121465
public static BindParser<T> Get<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>()
14131466
{
14141467
if (!_cache.TryGetValue(typeof(T), out var parser))
@@ -1503,6 +1556,12 @@ internal static class ParserDelegateCache
15031556
var method = _convertToNullableEnum ??= typeof(BindConverter).GetMethod(nameof(ConvertToNullableEnum), BindingFlags.NonPublic | BindingFlags.Static)!;
15041557
parser = method.MakeGenericMethod(innerType).CreateDelegate(typeof(BindParser<T>), target: null);
15051558
}
1559+
else if (typeof(T).IsArray)
1560+
{
1561+
var method = _makeArrayTypeConverter ??= typeof(ParserDelegateCache).GetMethod(nameof(MakeArrayTypeConverter), BindingFlags.NonPublic | BindingFlags.Static)!;
1562+
var elementType = typeof(T).GetElementType()!;
1563+
parser = (Delegate)method.MakeGenericMethod(elementType).Invoke(null, null)!;
1564+
}
15061565
else
15071566
{
15081567
parser = MakeTypeConverterConverter<T>();
@@ -1514,6 +1573,36 @@ internal static class ParserDelegateCache
15141573
return (BindParser<T>)parser;
15151574
}
15161575

1576+
private static BindParser<T[]?> MakeArrayTypeConverter<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>()
1577+
{
1578+
var elementParser = Get<T>();
1579+
1580+
return ConvertToArray;
1581+
1582+
bool ConvertToArray(object? obj, CultureInfo? culture, out T[]? value)
1583+
{
1584+
if (obj is not Array initialArray)
1585+
{
1586+
value = default;
1587+
return false;
1588+
}
1589+
1590+
var convertedArray = new T[initialArray.Length];
1591+
1592+
for (var i = 0; i < initialArray.Length; i++)
1593+
{
1594+
if (!elementParser(initialArray.GetValue(i), culture, out convertedArray[i]!))
1595+
{
1596+
value = default;
1597+
return false;
1598+
}
1599+
}
1600+
1601+
value = convertedArray;
1602+
return true;
1603+
}
1604+
}
1605+
15171606
private static BindParser<T> MakeTypeConverterConverter<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>()
15181607
{
15191608
var typeConverter = TypeDescriptor.GetConverter(typeof(T));

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@
77
<IsAspNetCoreApp>true</IsAspNetCoreApp>
88
<Nullable>enable</Nullable>
99
<Trimmable>true</Trimmable>
10+
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
1011
</PropertyGroup>
1112

1213
<ItemGroup>
1314
<Compile Include="$(ComponentsSharedSourceRoot)src\ArrayBuilder.cs" LinkBase="RenderTree" />
1415
<Compile Include="$(ComponentsSharedSourceRoot)src\JsonSerializerOptionsProvider.cs" />
1516
<Compile Include="$(ComponentsSharedSourceRoot)src\HotReloadFeature.cs" LinkBase="HotReload" />
1617
<Compile Include="$(SharedSourceRoot)LinkerFlags.cs" LinkBase="Shared" />
18+
<Compile Include="$(SharedSourceRoot)QueryStringEnumerable.cs" LinkBase="Shared" />
1719
</ItemGroup>
1820

1921
<ItemGroup>

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ Microsoft.AspNetCore.Components.CascadingTypeParameterAttribute
5757
Microsoft.AspNetCore.Components.CascadingTypeParameterAttribute.CascadingTypeParameterAttribute(string! name) -> void
5858
Microsoft.AspNetCore.Components.CascadingTypeParameterAttribute.Name.get -> string!
5959
Microsoft.AspNetCore.Components.RenderTree.Renderer.GetEventArgsType(ulong eventHandlerId) -> System.Type!
60+
Microsoft.AspNetCore.Components.SupplyParameterFromQueryAttribute
61+
Microsoft.AspNetCore.Components.SupplyParameterFromQueryAttribute.Name.get -> string?
62+
Microsoft.AspNetCore.Components.SupplyParameterFromQueryAttribute.Name.set -> void
63+
Microsoft.AspNetCore.Components.SupplyParameterFromQueryAttribute.SupplyParameterFromQueryAttribute() -> void
6064
abstract Microsoft.AspNetCore.Components.ErrorBoundaryBase.OnErrorAsync(System.Exception! exception) -> System.Threading.Tasks.Task!
6165
override Microsoft.AspNetCore.Components.LayoutComponentBase.SetParametersAsync(Microsoft.AspNetCore.Components.ParameterView parameters) -> System.Threading.Tasks.Task!
6266
static Microsoft.AspNetCore.Components.ParameterView.FromDictionary(System.Collections.Generic.IDictionary<string!, object?>! parameters) -> Microsoft.AspNetCore.Components.ParameterView

src/Components/Components/src/Reflection/ComponentProperties.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ namespace Microsoft.AspNetCore.Components.Reflection
1212
{
1313
internal static class ComponentProperties
1414
{
15-
private const BindingFlags _bindablePropertyFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.IgnoreCase;
15+
internal const BindingFlags BindablePropertyFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.IgnoreCase;
1616

1717
// Right now it's not possible for a component to define a Parameter and a Cascading Parameter with
1818
// the same name. We don't give you a way to express this in code (would create duplicate properties),
1919
// and we don't have the ability to represent it in our data structures.
20-
private readonly static ConcurrentDictionary<Type, WritersForType> _cachedWritersByType
20+
private static readonly ConcurrentDictionary<Type, WritersForType> _cachedWritersByType
2121
= new ConcurrentDictionary<Type, WritersForType>();
2222

2323
public static void ClearCache() => _cachedWritersByType.Clear();
@@ -162,15 +162,15 @@ static void SetProperty(object target, PropertySetter writer, string parameterNa
162162
}
163163

164164
internal static IEnumerable<PropertyInfo> GetCandidateBindableProperties([DynamicallyAccessedMembers(Component)] Type targetType)
165-
=> MemberAssignment.GetPropertiesIncludingInherited(targetType, _bindablePropertyFlags);
165+
=> MemberAssignment.GetPropertiesIncludingInherited(targetType, BindablePropertyFlags);
166166

167167
[DoesNotReturn]
168168
private static void ThrowForUnknownIncomingParameterName([DynamicallyAccessedMembers(Component)] Type targetType,
169169
string parameterName)
170170
{
171171
// We know we're going to throw by this stage, so it doesn't matter that the following
172172
// reflection code will be slow. We're just trying to help developers see what they did wrong.
173-
var propertyInfo = targetType.GetProperty(parameterName, _bindablePropertyFlags);
173+
var propertyInfo = targetType.GetProperty(parameterName, BindablePropertyFlags);
174174
if (propertyInfo != null)
175175
{
176176
if (!propertyInfo.IsDefined(typeof(ParameterAttribute)) && !propertyInfo.IsDefined(typeof(CascadingParameterAttribute)))
@@ -223,7 +223,7 @@ private static void ThrowForCaptureUnmatchedValuesConflict(Type targetType, stri
223223
private static void ThrowForMultipleCaptureUnmatchedValuesParameters([DynamicallyAccessedMembers(Component)] Type targetType)
224224
{
225225
var propertyNames = new List<string>();
226-
foreach (var property in targetType.GetProperties(_bindablePropertyFlags))
226+
foreach (var property in targetType.GetProperties(BindablePropertyFlags))
227227
{
228228
if (property.GetCustomAttribute<ParameterAttribute>()?.CaptureUnmatchedValues == true)
229229
{

src/Components/Components/src/RenderTree/Renderer.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ private async void RenderRootComponentsOnHotReload()
130130
// Before re-rendering the root component, also clear any well-known caches in the framework
131131
_componentFactory.ClearCache();
132132
ComponentProperties.ClearCache();
133+
Routing.QueryParameterValueSupplier.ClearCache();
133134

134135
await Dispatcher.InvokeAsync(() =>
135136
{

src/Components/Components/src/RouteView.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44
#nullable disable warnings
55

66
using System;
7+
using System.Collections.Generic;
78
using System.Reflection;
89
using System.Threading.Tasks;
910
using Microsoft.AspNetCore.Components.Rendering;
11+
using Microsoft.AspNetCore.Components.Routing;
1012

1113
namespace Microsoft.AspNetCore.Components
1214
{
@@ -20,6 +22,9 @@ public class RouteView : IComponent
2022
private readonly RenderFragment _renderPageWithParametersDelegate;
2123
private RenderHandle _renderHandle;
2224

25+
[Inject]
26+
private NavigationManager NavigationManager { get; set; }
27+
2328
/// <summary>
2429
/// Gets or sets the route data. This determines the page that will be
2530
/// displayed and the parameter values that will be supplied to the page.
@@ -90,6 +95,17 @@ private void RenderPageWithParameters(RenderTreeBuilder builder)
9095
builder.AddAttribute(1, kvp.Key, kvp.Value);
9196
}
9297

98+
var queryParameterSupplier = QueryParameterValueSupplier.ForType(RouteData.PageType);
99+
if (queryParameterSupplier is not null)
100+
{
101+
// Since this component does accept some parameters from query, we must supply values for all of them,
102+
// even if the querystring in the URI is empty. So don't skip the following logic.
103+
var url = NavigationManager.Uri;
104+
var queryStartPos = url.IndexOf('?');
105+
var query = queryStartPos < 0 ? default : url.AsMemory(queryStartPos);
106+
queryParameterSupplier.RenderParametersFromQueryString(builder, query);
107+
}
108+
93109
builder.CloseComponent();
94110
}
95111
}

0 commit comments

Comments
 (0)