Skip to content

Commit 9f9fbd0

Browse files
authored
Fix some issues with Ignitor (#15276)
* Avoid null ref when FormatException is not set * Handle errors when the client is canceled but an operation is in progress
1 parent 8c77190 commit 9f9fbd0

File tree

12 files changed

+132
-84
lines changed

12 files changed

+132
-84
lines changed

src/Components/Ignitor/src/BlazorClient.cs

Lines changed: 70 additions & 59 deletions
Large diffs are not rendered by default.

src/Components/Ignitor/src/CancellableOperation.cs

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,37 +5,50 @@
55
using System.Threading;
66
using System.Threading.Tasks;
77

8+
#nullable enable
89
namespace Ignitor
910
{
1011
internal class CancellableOperation<TResult>
1112
{
12-
public CancellableOperation(TimeSpan? timeout)
13+
public CancellableOperation(TimeSpan? timeout, CancellationToken cancellationToken)
1314
{
1415
Timeout = timeout;
1516

1617
Completion = new TaskCompletionSource<TResult>(TaskContinuationOptions.RunContinuationsAsynchronously);
1718
Completion.Task.ContinueWith(
1819
(task, state) =>
1920
{
20-
var operation = (CancellableOperation<TResult>)state;
21+
var operation = (CancellableOperation<TResult>)state!;
2122
operation.Dispose();
2223
},
2324
this,
2425
TaskContinuationOptions.ExecuteSynchronously); // We need to execute synchronously to clean-up before anything else continues
2526

27+
28+
Cancellation = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
29+
2630
if (Timeout != null && Timeout != System.Threading.Timeout.InfiniteTimeSpan && Timeout != TimeSpan.MaxValue)
2731
{
28-
Cancellation = new CancellationTokenSource(Timeout.Value);
29-
CancellationRegistration = Cancellation.Token.Register(
30-
(self) =>
31-
{
32-
var operation = (CancellableOperation<TResult>)self;
33-
operation.Completion.TrySetCanceled(operation.Cancellation.Token);
34-
operation.Cancellation.Dispose();
35-
operation.CancellationRegistration.Dispose();
36-
},
37-
this);
32+
Cancellation.CancelAfter(Timeout.Value);
3833
}
34+
35+
CancellationRegistration = Cancellation.Token.Register(
36+
(self) =>
37+
{
38+
var operation = (CancellableOperation<TResult>)self!;
39+
40+
if (cancellationToken.IsCancellationRequested)
41+
{
42+
// The operation was externally canceled before it timed out.
43+
Dispose();
44+
return;
45+
}
46+
47+
operation.Completion.TrySetException(new TimeoutException($"The operation timed out after {Timeout}."));
48+
operation.Cancellation?.Dispose();
49+
operation.CancellationRegistration.Dispose();
50+
},
51+
this);
3952
}
4053

4154
public TimeSpan? Timeout { get; }
@@ -62,3 +75,4 @@ private void Dispose()
6275
}
6376
}
6477
}
78+
#nullable restore

src/Components/Ignitor/src/ComponentState.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
namespace Ignitor
55
{
6+
#nullable enable
67
public class ComponentState
78
{
89
public ComponentState(int componentId)
@@ -11,6 +12,7 @@ public ComponentState(int componentId)
1112
}
1213

1314
public int ComponentId { get; }
14-
public IComponent Component { get; }
15+
public IComponent? Component { get; }
1516
}
17+
#nullable restore
1618
}

src/Components/Ignitor/src/ContainerNode.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System;
55
using System.Collections.Generic;
66

7+
#nullable enable
78
namespace Ignitor
89
{
910
public abstract class ContainerNode : Node
@@ -82,3 +83,4 @@ public void RemoveLogicalChild(int childIndex)
8283
}
8384
}
8485
}
86+
#nullable restore

src/Components/Ignitor/src/ElementHive.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33

44
using System;
55
using System.Collections.Generic;
6+
using System.Diagnostics.CodeAnalysis;
67

8+
#nullable enable
79
namespace Ignitor
810
{
911
public class ElementHive
@@ -35,7 +37,7 @@ public void Update(RenderBatch batch)
3537
}
3638
}
3739

38-
public bool TryFindElementById(string id, out ElementNode element)
40+
public bool TryFindElementById(string id, [NotNullWhen(true)] out ElementNode? element)
3941
{
4042
foreach (var kvp in Components)
4143
{
@@ -49,7 +51,7 @@ public bool TryFindElementById(string id, out ElementNode element)
4951
element = null;
5052
return false;
5153

52-
bool TryGetElementFromChildren(Node node, out ElementNode foundNode)
54+
bool TryGetElementFromChildren(Node node, out ElementNode? foundNode)
5355
{
5456
if (node is ElementNode elementNode &&
5557
elementNode.Attributes.TryGetValue("id", out var elementId) &&
@@ -81,6 +83,7 @@ private void UpdateComponent(RenderBatch batch, int componentId, ArrayBuilderSeg
8183
{
8284
component = new ComponentNode(componentId);
8385
Components.Add(componentId, component);
86+
8487
}
8588

8689
ApplyEdits(batch, component, 0, edits);
@@ -199,7 +202,7 @@ private void ApplyEdits(RenderBatch batch, ContainerNode parent, int childIndex,
199202

200203
case RenderTreeEditType.StepOut:
201204
{
202-
parent = parent.Parent;
205+
parent = parent.Parent ?? throw new InvalidOperationException($"Cannot step out of {parent}");
203206
currentDepth--;
204207
childIndexAtCurrentDepth = currentDepth == 0 ? childIndex : 0; // The childIndex is only ever nonzero at zero depth
205208
break;
@@ -469,3 +472,4 @@ public PermutationListEntry(int from, int to)
469472
}
470473
}
471474
}
475+
#nullable restore

src/Components/Ignitor/src/ElementNode.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System.Threading.Tasks;
88
using Microsoft.AspNetCore.SignalR.Client;
99

10+
#nullable enable
1011
namespace Ignitor
1112
{
1213
public class ElementNode : ContainerNode
@@ -87,7 +88,7 @@ internal Task SelectAsync(HubConnection connection, string value)
8788
return DispatchEventCore(connection, Serialize(webEventDescriptor), Serialize(args));
8889
}
8990

90-
public Task ClickAsync(HubConnection connection)
91+
internal Task ClickAsync(HubConnection connection)
9192
{
9293
if (!Events.TryGetValue("click", out var clickEventDescriptor))
9394
{
@@ -129,3 +130,4 @@ public ElementEventDescriptor(string eventName, ulong eventId)
129130
}
130131
}
131132
}
133+
#nullable restore

src/Components/Ignitor/src/Error.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

4+
#nullable enable
45
namespace Ignitor
56
{
67
public class Error
78
{
8-
public string Stack { get; set; }
9+
public string? Stack { get; set; }
910
}
1011
}
12+
#nullable restore

src/Components/Ignitor/src/IComponent.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
using System;
2-
using System.Collections.Generic;
3-
using System.Text;
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
43

54
namespace Ignitor
65
{

src/Components/Ignitor/src/Node.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

4+
#nullable enable
5+
46
namespace Ignitor
57
{
68
public abstract class Node
79
{
8-
public virtual ContainerNode Parent { get; set; }
10+
public virtual ContainerNode? Parent { get; set; }
911
}
1012
}
13+
14+
#nullable restore

src/Components/Ignitor/src/NodeSerializer.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
using System;
55
using System.IO;
66

7+
#nullable enable
8+
79
namespace Ignitor
810
{
911
internal static class NodeSerializer
@@ -96,7 +98,7 @@ private void SerializeElement(ElementNode elementNode)
9698
if (attribute.Value != null)
9799
{
98100
Write("=\"");
99-
Write(attribute.Value.ToString());
101+
Write(attribute.Value.ToString()!);
100102
Write("\"");
101103
}
102104
}
@@ -113,7 +115,7 @@ private void SerializeElement(ElementNode elementNode)
113115
if (properties.Value != null)
114116
{
115117
Write("=\"");
116-
Write(properties.Value.ToString());
118+
Write(properties.Value.ToString()!);
117119
Write("\"");
118120
}
119121
}
@@ -194,3 +196,4 @@ private void WriteIndent()
194196
}
195197
}
196198
}
199+
#nullable restore

0 commit comments

Comments
 (0)