Explorar el Código

Avoid null refs in BlazorIgntior when Disposed

Fixes https://github.com/aspnet/AspNetCore/issues/14257
Pranav K hace 6 años
padre
commit
0e7c873d62

+ 1 - 0
docs/BuildFromSource.md

@@ -27,6 +27,7 @@ Building ASP.NET Core on Windows requires:
         ```ps1
         PS> ./eng/scripts/InstallJdk.ps1
         ```
+* Chrome - Selenium-based tests require a version of Chrome to be installed. Download and install it from [https://www.google.com/chrome]
 
 ### macOS/Linux
 

+ 4 - 2
src/Components/Components.sln

@@ -238,6 +238,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.HttpsP
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorServerApp", "Samples\BlazorServerApp\BlazorServerApp.csproj", "{BBF37AF9-8290-4B70-8BA8-0F6017B3B620}"
 EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Ignitor", "Ignitor", "{29B5A306-7273-4649-8B04-26234D71ADBD}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -1583,8 +1585,8 @@ Global
 		{DA137BD4-F7F1-4D53-855F-5EC40CEA36B0} = {2FC10057-7A0A-4E34-8302-879925BC0102}
 		{0CDAB70B-71DC-43BE-ACB7-AD2EE3541FFB} = {2FC10057-7A0A-4E34-8302-879925BC0102}
 		{F88118E1-6F4A-4F89-B047-5FFD2889B9F0} = {2FC10057-7A0A-4E34-8302-879925BC0102}
-		{A78CE874-76B7-46FE-8009-1ED5258BA0AA} = {D6712550-0DA2-49C8-88E1-F04CAB982BF4}
-		{FC2A1EB0-A116-4689-92B7-239B1DCCF4CA} = {D6712550-0DA2-49C8-88E1-F04CAB982BF4}
+		{A78CE874-76B7-46FE-8009-1ED5258BA0AA} = {29B5A306-7273-4649-8B04-26234D71ADBD}
+		{FC2A1EB0-A116-4689-92B7-239B1DCCF4CA} = {29B5A306-7273-4649-8B04-26234D71ADBD}
 		{74D21785-2FAB-4266-B7C4-E311EC8EE0DF} = {7260DED9-22A9-4E9D-92F4-5E8A4404DEAF}
 		{E4C01A3F-D3C1-4639-A6A9-930E918843DD} = {7260DED9-22A9-4E9D-92F4-5E8A4404DEAF}
 		{DE297C91-B3E9-4C6F-B74D-0AF9EFEBF684} = {A27FF193-195B-4474-8E6C-840B2E339373}

+ 7 - 57
src/Components/Ignitor/src/BlazorClient.cs

@@ -56,7 +56,7 @@ namespace Ignitor
 
         private CancellableOperation<CapturedAttachComponentCall> NextAttachComponentReceived { get; set; }
 
-        private CancellableOperation<CapturedRenderBatch> NextBatchReceived { get; set; }
+        internal CancellableOperation<CapturedRenderBatch> NextBatchReceived { get; set; }
 
         private CancellableOperation<string> NextErrorReceived { get; set; }
 
@@ -88,7 +88,7 @@ namespace Ignitor
 
         public Task<CapturedRenderBatch> PrepareForNextBatch(TimeSpan? timeout)
         {
-            if (NextBatchReceived?.Completion != null)
+            if (NextBatchReceived != null && !NextBatchReceived.Disposed)
             {
                 throw new InvalidOperationException("Invalid state previous task not completed");
             }
@@ -100,7 +100,7 @@ namespace Ignitor
 
         public Task<CapturedJSInteropCall> PrepareForNextJSInterop(TimeSpan? timeout)
         {
-            if (NextJSInteropReceived?.Completion != null)
+            if (NextJSInteropReceived != null && !NextJSInteropReceived.Disposed)
             {
                 throw new InvalidOperationException("Invalid state previous task not completed");
             }
@@ -112,7 +112,7 @@ namespace Ignitor
 
         public Task<string> PrepareForNextDotNetInterop(TimeSpan? timeout)
         {
-            if (NextDotNetInteropCompletionReceived?.Completion != null)
+            if (NextDotNetInteropCompletionReceived != null && !NextDotNetInteropCompletionReceived.Disposed)
             {
                 throw new InvalidOperationException("Invalid state previous task not completed");
             }
@@ -124,7 +124,7 @@ namespace Ignitor
 
         public Task<string> PrepareForNextCircuitError(TimeSpan? timeout)
         {
-            if (NextErrorReceived?.Completion != null)
+            if (NextErrorReceived != null && !NextErrorReceived.Disposed)
             {
                 throw new InvalidOperationException("Invalid state previous task not completed");
             }
@@ -136,7 +136,7 @@ namespace Ignitor
 
         public Task<Exception> PrepareForNextDisconnect(TimeSpan? timeout)
         {
-            if (NextDisconnect?.Completion != null)
+            if (NextDisconnect != null && !NextDisconnect.Disposed)
             {
                 throw new InvalidOperationException("Invalid state previous task not completed");
             }
@@ -396,7 +396,7 @@ namespace Ignitor
             NextJSInteropReceived?.Completion?.TrySetResult(null);
         }
 
-        private void OnRenderBatch(int id, byte[] data)
+        protected virtual void OnRenderBatch(int id, byte[] data)
         {
             var capturedBatch = new CapturedRenderBatch(id, data);
 
@@ -499,56 +499,6 @@ namespace Ignitor
             return element;
         }
 
-        private class CancellableOperation<TResult>
-        {
-            public CancellableOperation(TimeSpan? timeout)
-            {
-                Timeout = timeout;
-                Initialize();
-            }
-
-            public TimeSpan? Timeout { get; }
-
-            public TaskCompletionSource<TResult> Completion { get; set; }
-
-            public CancellationTokenSource Cancellation { get; set; }
-
-            public CancellationTokenRegistration CancellationRegistration { get; set; }
-
-            private void Initialize()
-            {
-                Completion = new TaskCompletionSource<TResult>(TaskContinuationOptions.RunContinuationsAsynchronously);
-                Completion.Task.ContinueWith(
-                    (task, state) =>
-                    {
-                        var operation = (CancellableOperation<TResult>)state;
-                        operation.Dispose();
-                    },
-                    this,
-                    TaskContinuationOptions.ExecuteSynchronously); // We need to execute synchronously to clean-up before anything else continues
-                if (Timeout != null && Timeout != System.Threading.Timeout.InfiniteTimeSpan && Timeout != TimeSpan.MaxValue)
-                {
-                    Cancellation = new CancellationTokenSource(Timeout.Value);
-                    CancellationRegistration = Cancellation.Token.Register(
-                        (self) =>
-                        {
-                            var operation = (CancellableOperation<TResult>)self;
-                            operation.Completion.TrySetCanceled(operation.Cancellation.Token);
-                            operation.Cancellation.Dispose();
-                            operation.CancellationRegistration.Dispose();
-                        },
-                        this);
-                }
-            }
-
-            private void Dispose()
-            {
-                Completion = null;
-                Cancellation.Dispose();
-                CancellationRegistration.Dispose();
-            }
-        }
-
         private string[] ReadMarkers(string content)
         {
             content = content.Replace("\r\n", "").Replace("\n", "");

+ 64 - 0
src/Components/Ignitor/src/CancellableOperation.cs

@@ -0,0 +1,64 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Ignitor
+{
+    internal class CancellableOperation<TResult>
+    {
+        public CancellableOperation(TimeSpan? timeout)
+        {
+            Timeout = timeout;
+
+            Completion = new TaskCompletionSource<TResult>(TaskContinuationOptions.RunContinuationsAsynchronously);
+            Completion.Task.ContinueWith(
+                (task, state) =>
+                {
+                    var operation = (CancellableOperation<TResult>)state;
+                    operation.Dispose();
+                },
+                this,
+                TaskContinuationOptions.ExecuteSynchronously); // We need to execute synchronously to clean-up before anything else continues
+
+            if (Timeout != null && Timeout != System.Threading.Timeout.InfiniteTimeSpan && Timeout != TimeSpan.MaxValue)
+            {
+                Cancellation = new CancellationTokenSource(Timeout.Value);
+                CancellationRegistration = Cancellation.Token.Register(
+                    (self) =>
+                    {
+                        var operation = (CancellableOperation<TResult>)self;
+                        operation.Completion.TrySetCanceled(operation.Cancellation.Token);
+                        operation.Cancellation.Dispose();
+                        operation.CancellationRegistration.Dispose();
+                    },
+                    this);
+            }
+        }
+
+        public TimeSpan? Timeout { get; }
+
+        public TaskCompletionSource<TResult> Completion { get; }
+
+        public CancellationTokenSource Cancellation { get; }
+
+        public CancellationTokenRegistration CancellationRegistration { get; }
+
+        public bool Disposed { get; private set; }
+
+        private void Dispose()
+        {
+            if (Disposed)
+            {
+                return;
+            }
+
+            Disposed = true;
+            Completion.TrySetCanceled(Cancellation.Token);
+            Cancellation.Dispose();
+            CancellationRegistration.Dispose();
+        }
+    }
+}

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
src/Components/Web.JS/dist/Release/blazor.server.js


+ 6 - 8
src/Shared/E2ETesting/BrowserFixture.cs

@@ -108,7 +108,7 @@ namespace Microsoft.AspNetCore.E2ETesting
             var instance = await SeleniumStandaloneServer.GetInstanceAsync(output);
 
             var attempt = 0;
-            var maxAttempts = 3;
+            const int maxAttempts = 3;
             do
             {
                 try
@@ -132,18 +132,16 @@ namespace Microsoft.AspNetCore.E2ETesting
 
                     return (driver, logs);
                 }
-                catch
+                catch (Exception ex)
                 {
-                    if (attempt >= maxAttempts)
-                    {
-                        throw new InvalidOperationException("Couldn't create a Selenium remote driver client. The server is irresponsive");
-                    }
+                    output.WriteLine($"Error initializing RemoteWebDriver: {ex.Message}");
                 }
+
                 attempt++;
+
             } while (attempt < maxAttempts);
 
-            // We will never get here. Keeping the compiler happy.
-            throw new InvalidOperationException("Couldn't create a Selenium remote driver client. The server is unresponsive");
+            throw new InvalidOperationException("Couldn't create a Selenium remote driver client. The server is irresponsive");
         }
     }
 }

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio