public static Func <Task> Create(out SyncPoint syncPoint) { var handler = Create(1, out var syncPoints); syncPoint = syncPoints[0]; return(handler); }
/// <summary> /// Creates a re-entrant function that waits for sync points in sequence. /// </summary> /// <param name="count">The number of sync points to expect</param> /// <param name="syncPoints">The <see cref="SyncPoint"/> objects that can be used to coordinate the sync point</param> /// <returns></returns> public static Func <Task> Create(int count, out SyncPoint[] syncPoints) { // Need to use a local so the closure can capture it. You can't use out vars in a closure. var localSyncPoints = new SyncPoint[count]; for (var i = 0; i < count; i += 1) { localSyncPoints[i] = new SyncPoint(); } syncPoints = localSyncPoints; var counter = 0; return(() => { if (counter >= localSyncPoints.Length) { return Task.CompletedTask; } else { var syncPoint = localSyncPoints[counter]; counter += 1; return syncPoint.WaitToContinue(); } }); }
public async Task GlobalFiltersRunBeforeHubSpecificFilters() { using (StartVerifiableLog()) { var syncPoint1 = SyncPoint.Create(3, out var syncPoints1); var syncPoint2 = SyncPoint.Create(3, out var syncPoints2); var serviceProvider = HubConnectionHandlerTestUtils.CreateServiceProvider(services => { services.AddSignalR(options => { options.AddFilter(new SyncPointFilter(syncPoints1)); }) .AddHubOptions <MethodHub>(options => { options.AddFilter(new SyncPointFilter(syncPoints2)); }); }, LoggerFactory); var connectionHandler = serviceProvider.GetService <HubConnectionHandler <MethodHub> >(); using (var client = new TestClient()) { var connectionHandlerTask = await client.ConnectAsync(connectionHandler); await syncPoints1[0].WaitForSyncPoint().OrTimeout(); // Second filter wont run yet because first filter is waiting on SyncPoint Assert.False(syncPoints2[0].WaitForSyncPoint().IsCompleted); syncPoints1[0].Continue(); await syncPoints2[0].WaitForSyncPoint().OrTimeout(); syncPoints2[0].Continue(); await client.Connected.OrTimeout(); var invokeTask = client.InvokeAsync(nameof(MethodHub.Echo), "Hello world!"); await syncPoints1[1].WaitForSyncPoint().OrTimeout(); // Second filter wont run yet because first filter is waiting on SyncPoint Assert.False(syncPoints2[1].WaitForSyncPoint().IsCompleted); syncPoints1[1].Continue(); await syncPoints2[1].WaitForSyncPoint().OrTimeout(); syncPoints2[1].Continue(); var message = await invokeTask.OrTimeout(); Assert.Null(message.Error); client.Dispose(); await syncPoints1[2].WaitForSyncPoint().OrTimeout(); // Second filter wont run yet because first filter is waiting on SyncPoint Assert.False(syncPoints2[2].WaitForSyncPoint().IsCompleted); syncPoints1[2].Continue(); await syncPoints2[2].WaitForSyncPoint().OrTimeout(); syncPoints2[2].Continue(); await connectionHandlerTask.OrTimeout(); } } }
public async Task SerializingTwoMessagesFromTheSameProtocolSimultaneouslyResultsInOneCachedItemAsync(int numberOfSerializationsToPreCache) { var invocation = new InvocationMessage("Foo", new object[0]); var message = new SerializedHubMessage(invocation); // "Pre-cache" the requested number of serializations (so we can test scenarios involving each of the fields and the fallback list) for (var i = 0; i < numberOfSerializationsToPreCache; i++) { _ = message.GetSerializedMessage(new DummyHubProtocol($"p{i}")); } var onWrite = SyncPoint.Create(2, out var syncPoints); var protocol = new DummyHubProtocol("test", () => onWrite().Wait()); // Serialize once, but hold at the Hub Protocol var firstSerialization = Task.Run(() => message.GetSerializedMessage(protocol)); await syncPoints[0].WaitForSyncPoint(); // Serialize again, which should hit the lock var secondSerialization = Task.Run(() => message.GetSerializedMessage(protocol)); Assert.False(secondSerialization.IsCompleted); // Release both instances of the syncpoint syncPoints[0].Continue(); syncPoints[1].Continue(); // Everything should finish and only one serialization should be written await firstSerialization.DefaultTimeout(); await secondSerialization.DefaultTimeout(); Assert.Collection(message.GetAllSerializations().Skip(numberOfSerializationsToPreCache).ToArray(), serializedMessage => { Assert.Equal("test", serializedMessage.ProtocolName); Assert.Equal(DummyHubProtocol.DummySerialization, serializedMessage.Serialized.ToArray()); }); }