diff --git a/src/CI/azp-dotnet-dist.yaml b/src/CI/azp-dotnet-dist.yaml
index bafcc806..02e66263 100644
--- a/src/CI/azp-dotnet-dist.yaml
+++ b/src/CI/azp-dotnet-dist.yaml
@@ -16,7 +16,7 @@ steps:
- task: DotNetCoreCLI@2
displayName: 'dotnet push to UiPath-Internal'
- condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master'))
+ condition: succeeded()
inputs:
command: push
packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg'
@@ -24,7 +24,7 @@ steps:
- task: PublishSymbols@2
displayName: 'Publish Symbols to UiPath Azure Artifacts Symbol Server'
- condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master'))
+ condition: succeeded()
inputs:
symbolsFolder: $(Build.SourcesDirectory)
searchPattern: '**/UiPath.CoreIpc/bin/**/UiPath.CoreIpc.pdb'
diff --git a/src/CI/azp-dotnet.yaml b/src/CI/azp-dotnet.yaml
index 0af4fc84..515a8ea1 100644
--- a/src/CI/azp-dotnet.yaml
+++ b/src/CI/azp-dotnet.yaml
@@ -1,4 +1,10 @@
steps:
+ - task: DotNetCoreCLI@2
+ displayName: '$(Label_DotNet) Restore, build and pack'
+ inputs:
+ projects: '$(DotNet_SessionSolution)'
+ arguments: '--configuration $(DotNet_BuildConfiguration) -p:Version="$(FullVersion)" -p:DefineConstantsEx="CI"'
+
- task: DotNetCoreCLI@2
displayName: '$(Label_DotNet) Run unit tests'
inputs:
diff --git a/src/CI/azp-initialization.yaml b/src/CI/azp-initialization.yaml
index 3cc0d0a3..2fd099a2 100644
--- a/src/CI/azp-initialization.yaml
+++ b/src/CI/azp-initialization.yaml
@@ -1,4 +1,20 @@
steps:
+ - powershell: |
+ Write-Host "##vso[task.setvariable variable=DotnetRuntimeVersion;]8.0.0"
+ Write-Host "##vso[task.setvariable variable=DOTNET_NOLOGO;]true"
+ displayName: 'Use .NET Runtime 8.0.0'
+
+ - task: UseDotNet@2
+ displayName: 'Use .NET SDK 6.0.317'
+ inputs:
+ packageType: 'sdk'
+ version: '6.0.317'
+
+ - task: UseDotNet@2
+ displayName: 'Use .NET SDK 8.x'
+ inputs:
+ packageType: 'sdk'
+ version: 8.x
# Read $(Version) from the UiPath.CoreIpc.csproj file
- powershell: |
diff --git a/src/CI/azp-nodejs.yaml b/src/CI/azp-nodejs.yaml
index 52f7d934..ee14c6bf 100644
--- a/src/CI/azp-nodejs.yaml
+++ b/src/CI/azp-nodejs.yaml
@@ -48,7 +48,7 @@
inputs:
workingDirectory: $(NodeJS_ProjectPath)
script: 'npm test'
-
+
- task: PublishTestResults@2
displayName: 'Publish Web Test Results'
condition: succeededOrFailed()
diff --git a/src/CI/azp-start.yaml b/src/CI/azp-start.yaml
index d659af93..d51e5497 100644
--- a/src/CI/azp-start.yaml
+++ b/src/CI/azp-start.yaml
@@ -10,7 +10,7 @@ variables:
DotNet_MainProjectName: 'UiPath.CoreIpc'
DotNet_MainProjectPath: './src/UiPath.CoreIpc/UiPath.CoreIpc.csproj'
DotNet_ArtifactName: 'NuGet package'
-
+
NodeJS_DotNet_BuildConfiguration: 'Debug'
NodeJS_ProjectPath: './src/Clients/js'
NodeJS_ArchivePath: './src/Clients/js/dist/pack/nodejs.zip'
@@ -23,32 +23,32 @@ stages:
- stage: Build
displayName: '🏭 Build'
jobs:
- # The following 3 jobs will run in parallel:
- - job:
- displayName: '.NET on Windows'
- pool:
+ # The following 3 jobs will run in parallel:
+ - job:
+ displayName: '.NET on Windows'
+ pool:
vmImage: 'windows-2022'
- steps:
- - template: azp-initialization.yaml
- - template: azp-dotnet.yaml
- - template: azp-dotnet-dist.yaml
-
- - job:
- displayName: 'node.js on Windows'
- pool:
+ steps:
+ - template: azp-initialization.yaml
+ - template: azp-dotnet.yaml
+ - template: azp-dotnet-dist.yaml
+
+ - job:
+ displayName: 'node.js on Windows'
+ pool:
vmImage: 'windows-2022'
- steps:
- - template: azp-initialization.yaml
- - template: azp-nodejs.yaml
- - template: azp-nodejs-dist.yaml
-
- - job:
- displayName: 'node.js on Ubuntu'
- pool:
- vmImage: 'ubuntu-20.04'
- steps:
- - template: azp-initialization.yaml
- - template: azp-nodejs.yaml
+ steps:
+ - template: azp-initialization.yaml
+ - template: azp-nodejs.yaml
+ - template: azp-nodejs-dist.yaml
+
+ - job:
+ displayName: 'node.js on Ubuntu'
+ pool:
+ vmImage: 'ubuntu-20.04'
+ steps:
+ - template: azp-initialization.yaml
+ - template: azp-nodejs.yaml
- stage: Publish
displayName: 🚚 Publish
diff --git a/src/Clients/js/dotnet/UiPath.CoreIpc.NodeInterop/Contracts.cs b/src/Clients/js/dotnet/UiPath.CoreIpc.NodeInterop/Contracts.cs
index 0a725bab..d86c0d8e 100644
--- a/src/Clients/js/dotnet/UiPath.CoreIpc.NodeInterop/Contracts.cs
+++ b/src/Clients/js/dotnet/UiPath.CoreIpc.NodeInterop/Contracts.cs
@@ -2,7 +2,7 @@
using System.Threading;
using System.Threading.Tasks;
-namespace UiPath.CoreIpc.NodeInterop;
+namespace UiPath.Ipc.NodeInterop;
internal static class Contracts
{
diff --git a/src/Clients/js/dotnet/UiPath.CoreIpc.NodeInterop/Program.cs b/src/Clients/js/dotnet/UiPath.CoreIpc.NodeInterop/Program.cs
index 17f23329..02792bdd 100644
--- a/src/Clients/js/dotnet/UiPath.CoreIpc.NodeInterop/Program.cs
+++ b/src/Clients/js/dotnet/UiPath.CoreIpc.NodeInterop/Program.cs
@@ -7,10 +7,10 @@
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;
-using UiPath.CoreIpc.NamedPipe;
-using UiPath.CoreIpc.WebSockets;
+using UiPath.Ipc.NamedPipe;
+using UiPath.Ipc.WebSockets;
-namespace UiPath.CoreIpc.NodeInterop;
+namespace UiPath.Ipc.NodeInterop;
using static Contracts;
using static ServiceImpls;
diff --git a/src/Clients/js/dotnet/UiPath.CoreIpc.NodeInterop/ServiceImpls.cs b/src/Clients/js/dotnet/UiPath.CoreIpc.NodeInterop/ServiceImpls.cs
index 0a436080..3b9706f1 100644
--- a/src/Clients/js/dotnet/UiPath.CoreIpc.NodeInterop/ServiceImpls.cs
+++ b/src/Clients/js/dotnet/UiPath.CoreIpc.NodeInterop/ServiceImpls.cs
@@ -3,7 +3,7 @@
using System.Threading;
using System.Threading.Tasks;
-namespace UiPath.CoreIpc.NodeInterop;
+namespace UiPath.Ipc.NodeInterop;
using static Contracts;
diff --git a/src/Clients/js/dotnet/UiPath.CoreIpc.NodeInterop/Signalling.cs b/src/Clients/js/dotnet/UiPath.CoreIpc.NodeInterop/Signalling.cs
index aba44d91..76d667f4 100644
--- a/src/Clients/js/dotnet/UiPath.CoreIpc.NodeInterop/Signalling.cs
+++ b/src/Clients/js/dotnet/UiPath.CoreIpc.NodeInterop/Signalling.cs
@@ -2,7 +2,7 @@
using Newtonsoft.Json.Converters;
using System;
-namespace UiPath.CoreIpc.NodeInterop;
+namespace UiPath.Ipc.NodeInterop;
internal static class Signalling
{
diff --git a/src/CoreIpc.sln b/src/CoreIpc.sln
index b69f1d5f..3ae701b3 100644
--- a/src/CoreIpc.sln
+++ b/src/CoreIpc.sln
@@ -13,6 +13,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UiPath.CoreIpc.Tests", "UiP
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{676A208A-2F08-4749-A833-F8D2BCB1B147}"
ProjectSection(SolutionItems) = preProject
+ Directory.Build.targets = Directory.Build.targets
NuGet.Config = NuGet.Config
EndProjectSection
EndProject
diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets
new file mode 100644
index 00000000..4979abb6
--- /dev/null
+++ b/src/Directory.Build.targets
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/src/IpcSample.ConsoleClient/Client.cs b/src/IpcSample.ConsoleClient/Client.cs
index 36515be2..177ab7bf 100644
--- a/src/IpcSample.ConsoleClient/Client.cs
+++ b/src/IpcSample.ConsoleClient/Client.cs
@@ -1,9 +1,9 @@
using System.Text;
using System.Diagnostics;
-using UiPath.CoreIpc.NamedPipe;
+using UiPath.Ipc.NamedPipe;
using Microsoft.Extensions.DependencyInjection;
-namespace UiPath.CoreIpc.Tests;
+namespace UiPath.Ipc.Tests;
class Client
{
@@ -32,7 +32,7 @@ private static async Task RunTestsAsync(CancellationToken cancellationToken)
var serviceProvider = ConfigureServices();
var callback = new ComputingCallback { Id = "custom made" };
var computingClientBuilder = new NamedPipeClientBuilder("test", serviceProvider)
- .SerializeParametersAsObjects().CallbackInstance(callback).AllowImpersonation().RequestTimeout(TimeSpan.FromSeconds(2));
+ .CallbackInstance(callback).AllowImpersonation().RequestTimeout(TimeSpan.FromSeconds(2));
var stopwatch = Stopwatch.StartNew();
int count = 0;
try
@@ -40,7 +40,6 @@ private static async Task RunTestsAsync(CancellationToken cancellationToken)
var computingClient = computingClientBuilder.ValidateAndBuild();
var systemClient =
new NamedPipeClientBuilder("test")
- .SerializeParametersAsObjects()
.RequestTimeout(TimeSpan.FromSeconds(2))
.Logger(serviceProvider)
.AllowImpersonation()
@@ -67,7 +66,7 @@ private static async Task RunTestsAsync(CancellationToken cancellationToken)
Console.WriteLine($"[TEST 3] sum of 3 complexe number is: {result3.A}+{result3.B}i", cancellationToken);
// test 4: call IPC service method without parameter or return
- await systemClient.DoNothing(cancellationToken);
+ await systemClient.FireAndForget(cancellationToken);
Console.WriteLine($"[TEST 4] invoked DoNothing()");
//((IDisposable)systemClient).Dispose();
diff --git a/src/IpcSample.ConsoleClient/IpcSample.ConsoleClient.csproj b/src/IpcSample.ConsoleClient/IpcSample.ConsoleClient.csproj
index a313c304..709ab56e 100644
--- a/src/IpcSample.ConsoleClient/IpcSample.ConsoleClient.csproj
+++ b/src/IpcSample.ConsoleClient/IpcSample.ConsoleClient.csproj
@@ -14,9 +14,9 @@
-
-
-
-
+
+
+
+
diff --git a/src/IpcSample.ConsoleClient/Polyfills.cs b/src/IpcSample.ConsoleClient/Polyfills.cs
new file mode 100644
index 00000000..3f9caea2
--- /dev/null
+++ b/src/IpcSample.ConsoleClient/Polyfills.cs
@@ -0,0 +1,30 @@
+#if NETFRAMEWORK
+
+namespace System.Diagnostics.CodeAnalysis;
+
+using static AttributeTargets;
+
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+[AttributeUsage(Parameter | Property | ReturnValue, AllowMultiple = true)]
+internal sealed class NotNullIfNotNullAttribute : Attribute
+{
+ ///
+ /// Gets the associated parameter name.
+ /// The output will be non- if the argument to the
+ /// parameter specified is non-.
+ ///
+ public string ParameterName { get; }
+
+ ///
+ /// Initializes the attribute with the associated parameter name.
+ ///
+ ///
+ /// The associated parameter name.
+ /// The output will be non- if the argument to the
+ /// parameter specified is non-.
+ ///
+ public NotNullIfNotNullAttribute(string parameterName) =>
+ ParameterName = parameterName;
+}
+#endif
\ No newline at end of file
diff --git a/src/IpcSample.ConsoleClient/TcpClient.cs b/src/IpcSample.ConsoleClient/TcpClient.cs
index 0768ebc6..2d1aa7a4 100644
--- a/src/IpcSample.ConsoleClient/TcpClient.cs
+++ b/src/IpcSample.ConsoleClient/TcpClient.cs
@@ -1,10 +1,10 @@
using System.Text;
using System.Diagnostics;
-using UiPath.CoreIpc.Tcp;
+using UiPath.Ipc.Tcp;
using Microsoft.Extensions.DependencyInjection;
using System.Net;
-namespace UiPath.CoreIpc.Tests;
+namespace UiPath.Ipc.Tests;
class TcpClient
{
@@ -35,7 +35,7 @@ private static async Task RunTestsAsync(CancellationToken cancellationToken)
var serviceProvider = ConfigureServices();
var callback = new ComputingCallback { Id = "custom made" };
var computingClientBuilder = new TcpClientBuilder(SystemEndPoint, serviceProvider)
- .SerializeParametersAsObjects().CallbackInstance(callback)/*.EncryptAndSign("localhost")*/.RequestTimeout(TimeSpan.FromSeconds(2));
+ .CallbackInstance(callback)/*.EncryptAndSign("localhost")*/.RequestTimeout(TimeSpan.FromSeconds(2));
var stopwatch = Stopwatch.StartNew();
int count = 0;
try
@@ -43,7 +43,6 @@ private static async Task RunTestsAsync(CancellationToken cancellationToken)
var computingClient = computingClientBuilder.ValidateAndBuild();
var systemClient =
new TcpClientBuilder(SystemEndPoint)
- .SerializeParametersAsObjects()
//.EncryptAndSign("localhost")
.RequestTimeout(TimeSpan.FromSeconds(2))
.Logger(serviceProvider)
diff --git a/src/IpcSample.ConsoleClient/WebSocketClient.cs b/src/IpcSample.ConsoleClient/WebSocketClient.cs
index e6c93422..376bd3f1 100644
--- a/src/IpcSample.ConsoleClient/WebSocketClient.cs
+++ b/src/IpcSample.ConsoleClient/WebSocketClient.cs
@@ -1,8 +1,8 @@
using System.Text;
using System.Diagnostics;
-using UiPath.CoreIpc.WebSockets;
+using UiPath.Ipc.WebSockets;
using Microsoft.Extensions.DependencyInjection;
-namespace UiPath.CoreIpc.Tests;
+namespace UiPath.Ipc.Tests;
class WebSocketClient
{
static async Task _Main(string[] args)
@@ -32,7 +32,7 @@ private static async Task RunTestsAsync(CancellationToken cancellationToken)
Uri uri = new("ws://localhost:1212/wsDemo/");
var serviceProvider = ConfigureServices();
var callback = new ComputingCallback { Id = "custom made" };
- var computingClientBuilder = new WebSocketClientBuilder(uri, serviceProvider).SerializeParametersAsObjects()
+ var computingClientBuilder = new WebSocketClientBuilder(uri, serviceProvider)
.CallbackInstance(callback)/*.EncryptAndSign("localhost")*/.RequestTimeout(TimeSpan.FromSeconds(2));
var stopwatch = Stopwatch.StartNew();
int count = 0;
@@ -40,7 +40,7 @@ private static async Task RunTestsAsync(CancellationToken cancellationToken)
{
var computingClient = computingClientBuilder.ValidateAndBuild();
var systemClient =
- new WebSocketClientBuilder(uri).SerializeParametersAsObjects()
+ new WebSocketClientBuilder(uri)
//.EncryptAndSign("localhost")
.RequestTimeout(TimeSpan.FromSeconds(2))
.Logger(serviceProvider)
diff --git a/src/IpcSample.ConsoleServer/IpcSample.ConsoleServer.csproj b/src/IpcSample.ConsoleServer/IpcSample.ConsoleServer.csproj
index 2c9744b6..93d37b89 100644
--- a/src/IpcSample.ConsoleServer/IpcSample.ConsoleServer.csproj
+++ b/src/IpcSample.ConsoleServer/IpcSample.ConsoleServer.csproj
@@ -14,10 +14,10 @@
-
-
-
-
+
+
+
+
diff --git a/src/IpcSample.ConsoleServer/Server.cs b/src/IpcSample.ConsoleServer/Server.cs
index 8e9ad9e4..35f24b8f 100644
--- a/src/IpcSample.ConsoleServer/Server.cs
+++ b/src/IpcSample.ConsoleServer/Server.cs
@@ -1,8 +1,8 @@
using Microsoft.Extensions.DependencyInjection;
using System.Diagnostics;
-using UiPath.CoreIpc.NamedPipe;
+using UiPath.Ipc.NamedPipe;
-namespace UiPath.CoreIpc.Tests;
+namespace UiPath.Ipc.Tests;
class Server
{
diff --git a/src/IpcSample.ConsoleServer/TcpServer.cs b/src/IpcSample.ConsoleServer/TcpServer.cs
index 172a7725..9660ec87 100644
--- a/src/IpcSample.ConsoleServer/TcpServer.cs
+++ b/src/IpcSample.ConsoleServer/TcpServer.cs
@@ -1,9 +1,9 @@
using Microsoft.Extensions.DependencyInjection;
using System.Diagnostics;
using System.Net;
-using UiPath.CoreIpc.Tcp;
+using UiPath.Ipc.Tcp;
-namespace UiPath.CoreIpc.Tests;
+namespace UiPath.Ipc.Tests;
class TcpServer
{
diff --git a/src/IpcSample.ConsoleServer/WebSocketServer.cs b/src/IpcSample.ConsoleServer/WebSocketServer.cs
index 322c1d65..44727483 100644
--- a/src/IpcSample.ConsoleServer/WebSocketServer.cs
+++ b/src/IpcSample.ConsoleServer/WebSocketServer.cs
@@ -2,8 +2,8 @@
using System.Diagnostics;
using System.Net;
using System.Net.WebSockets;
-using UiPath.CoreIpc.WebSockets;
-namespace UiPath.CoreIpc.Tests;
+using UiPath.Ipc.WebSockets;
+namespace UiPath.Ipc.Tests;
class WebSocketServer
{
//private static readonly Timer _timer = new Timer(_ =>
diff --git a/src/UiPath.CoreIpc.Tests/ComputingTests.cs b/src/UiPath.CoreIpc.Tests/ComputingTests.cs
index 6c562dd9..7cd7c0d5 100644
--- a/src/UiPath.CoreIpc.Tests/ComputingTests.cs
+++ b/src/UiPath.CoreIpc.Tests/ComputingTests.cs
@@ -1,4 +1,4 @@
-namespace UiPath.CoreIpc.Tests;
+namespace UiPath.Ipc.Tests;
public abstract class ComputingTests : TestBase where TBuilder : ServiceClientBuilder
{
@@ -14,7 +14,7 @@ public ComputingTests()
.AddEndpoint()
.ValidateAndBuild();
_computingHost.RunAsync(GuiScheduler);
- _computingClient = ComputingClientBuilder(GuiScheduler).SerializeParametersAsObjects().ValidateAndBuild();
+ _computingClient = ComputingClientBuilder(GuiScheduler).ValidateAndBuild();
}
protected abstract TBuilder ComputingClientBuilder(TaskScheduler taskScheduler = null);
[Fact]
@@ -58,7 +58,7 @@ public async Task ClientCancellation()
[Fact]
public async Task ClientTimeout()
{
- var proxy = ComputingClientBuilder().SerializeParametersAsObjects().RequestTimeout(TimeSpan.FromMilliseconds(10)).ValidateAndBuild();
+ var proxy = ComputingClientBuilder().RequestTimeout(TimeSpan.FromMilliseconds(10)).ValidateAndBuild();
proxy.Infinite().ShouldThrow().Message.ShouldBe($"{nameof(_computingClient.Infinite)} timed out.");
await proxy.GetCallbackThreadName(new Message { RequestTimeout = RequestTimeout });
((IDisposable)proxy).Dispose();
diff --git a/src/UiPath.CoreIpc.Tests/EndpointTests.cs b/src/UiPath.CoreIpc.Tests/EndpointTests.cs
index e62db908..618acf7c 100644
--- a/src/UiPath.CoreIpc.Tests/EndpointTests.cs
+++ b/src/UiPath.CoreIpc.Tests/EndpointTests.cs
@@ -1,4 +1,4 @@
-namespace UiPath.CoreIpc.Tests;
+namespace UiPath.Ipc.Tests;
public class EndpointTests : IDisposable
{
@@ -34,13 +34,11 @@ private NamedPipeClientBuilder ComputingC
.AllowImpersonation()
.RequestTimeout(RequestTimeout)
.CallbackInstance(_computingCallback)
- .SerializeParametersAsObjects()
.TaskScheduler(taskScheduler);
private ISystemService CreateSystemService() => SystemClientBuilder().ValidateAndBuild();
private NamedPipeClientBuilder SystemClientBuilder() =>
new NamedPipeClientBuilder(PipeName, _serviceProvider)
.CallbackInstance(_systemCallback)
- .SerializeParametersAsObjects()
.RequestTimeout(RequestTimeout)
.AllowImpersonation();
public void Dispose()
@@ -66,7 +64,7 @@ public async Task Callback()
private async Task CallbackCore()
{
var proxy = new NamedPipeClientBuilder(PipeName)
- .SerializeParametersAsObjects().RequestTimeout(RequestTimeout).AllowImpersonation().ValidateAndBuild();
+ .RequestTimeout(RequestTimeout).AllowImpersonation().ValidateAndBuild();
var message = new SystemMessage { Text = Guid.NewGuid().ToString() };
var computingTask = _computingClient.SendMessage(message);
var systemTask = _systemClient.SendMessage(message);
@@ -89,7 +87,7 @@ public async Task MissingCallback()
{
exception = ex;
}
- exception.Message.ShouldBe("Callback contract mismatch. Requested System.IDisposable, but it's UiPath.CoreIpc.Tests.ISystemCallback.");
+ exception.Message.ShouldBe("Callback contract mismatch. Requested System.IDisposable, but it's UiPath.Ipc.Tests.ISystemCallback.");
exception.Is().ShouldBeTrue();
}
[Fact]
diff --git a/src/UiPath.CoreIpc.Tests/Implementation/ComputingCallback.cs b/src/UiPath.CoreIpc.Tests/Implementation/ComputingCallback.cs
index 7938f812..259d5c80 100644
--- a/src/UiPath.CoreIpc.Tests/Implementation/ComputingCallback.cs
+++ b/src/UiPath.CoreIpc.Tests/Implementation/ComputingCallback.cs
@@ -1,4 +1,4 @@
-namespace UiPath.CoreIpc.Tests;
+namespace UiPath.Ipc.Tests;
public interface IComputingCallback
{
diff --git a/src/UiPath.CoreIpc.Tests/Implementation/ComputingService.cs b/src/UiPath.CoreIpc.Tests/Implementation/ComputingService.cs
index 908ee1f0..b52c69b0 100644
--- a/src/UiPath.CoreIpc.Tests/Implementation/ComputingService.cs
+++ b/src/UiPath.CoreIpc.Tests/Implementation/ComputingService.cs
@@ -1,6 +1,6 @@
using Microsoft.Extensions.Logging;
-namespace UiPath.CoreIpc.Tests;
+namespace UiPath.Ipc.Tests;
public interface IInvalid : IDisposable
{
diff --git a/src/UiPath.CoreIpc.Tests/Implementation/IpcHelpers.cs b/src/UiPath.CoreIpc.Tests/Implementation/IpcHelpers.cs
index 41a9292f..b33b54a6 100644
--- a/src/UiPath.CoreIpc.Tests/Implementation/IpcHelpers.cs
+++ b/src/UiPath.CoreIpc.Tests/Implementation/IpcHelpers.cs
@@ -1,9 +1,9 @@
using Microsoft.Extensions.Logging;
using System.Net;
using System.Net.WebSockets;
-using UiPath.CoreIpc.Tests;
+using UiPath.Ipc.Tests;
-namespace UiPath.CoreIpc;
+namespace UiPath.Ipc;
public static class IpcHelpers
{
diff --git a/src/UiPath.CoreIpc.Tests/Implementation/OneWayStreamWrapper.cs b/src/UiPath.CoreIpc.Tests/Implementation/OneWayStreamWrapper.cs
index b63c41c6..1e2bb7b0 100644
--- a/src/UiPath.CoreIpc.Tests/Implementation/OneWayStreamWrapper.cs
+++ b/src/UiPath.CoreIpc.Tests/Implementation/OneWayStreamWrapper.cs
@@ -1,7 +1,7 @@
// Copyright (c) Andrew Arnott. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-namespace UiPath.CoreIpc.Tests;
+namespace UiPath.Ipc.Tests;
internal class OneWayStreamWrapper : Stream
{
diff --git a/src/UiPath.CoreIpc.Tests/Implementation/SystemService.cs b/src/UiPath.CoreIpc.Tests/Implementation/SystemService.cs
index 049f4e36..5b952638 100644
--- a/src/UiPath.CoreIpc.Tests/Implementation/SystemService.cs
+++ b/src/UiPath.CoreIpc.Tests/Implementation/SystemService.cs
@@ -1,11 +1,14 @@
using System.Globalization;
+using System.IO.Pipes;
+using System.Reflection;
+using System.Runtime.InteropServices;
using System.Text;
-namespace UiPath.CoreIpc.Tests;
+namespace UiPath.Ipc.Tests;
public interface ISystemService
{
- Task DoNothing(CancellationToken cancellationToken = default);
+ Task FireAndForget(CancellationToken cancellationToken = default);
Task VoidThreadName(CancellationToken cancellationToken = default);
Task VoidSyncThrow(CancellationToken cancellationToken = default);
Task GetThreadName(CancellationToken cancellationToken = default);
@@ -22,6 +25,8 @@ public interface ISystemService
Task Download(string text, CancellationToken cancellationToken = default);
Task Echo(Stream input, CancellationToken cancellationToken = default);
Task UploadNoRead(Stream memoryStream, int delay = 0, CancellationToken cancellationToken = default);
+ Task CancelIoPipe(CancelIoPipeMessage message = null, CancellationToken cancellationToken = default);
+ Task Delay(int delay = 0, CancellationToken cancellationToken = default);
}
public class SystemMessage : Message
@@ -29,6 +34,10 @@ public class SystemMessage : Message
public string Text { get; set; }
public int Delay { get; set; }
}
+public class CancelIoPipeMessage : Message
+{
+ public int[]? MsDelays { get; set; }
+}
public class SystemService : ISystemService
{
public SystemService()
@@ -66,18 +75,18 @@ public async Task SendMessage(SystemMessage message, CancellationToken c
return returnValue;
}
- public bool DidNothing { get; set; }
+ public bool FireAndForgetDone { get; set; }
- public async Task DoNothing(CancellationToken cancellationToken = default)
+ public async Task FireAndForget(CancellationToken cancellationToken = default)
{
const int Timeout =
#if CI
- 100;
+ 400;
#else
- 10;
+ 40;
#endif
await Task.Delay(Timeout);
- DidNothing = true;
+ FireAndForgetDone = true;
}
public async Task GetGuid(Guid guid, CancellationToken cancellationToken = default)
@@ -172,4 +181,35 @@ public async Task Echo(Stream input, CancellationToken cancellationToken
result.Position = 0;
return result;
}
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ public static extern bool CancelIoEx(IntPtr handle, IntPtr lpOverlapped);
+ public async Task CancelIoPipe(CancelIoPipeMessage message = null, CancellationToken cancellationToken = default)
+ {
+ Debug.WriteLine("###################### CancelIoPipe");
+ await Task.Delay(50);
+#if WINDOWS
+ var serverFieldInfo = message.Client.GetType().GetField("_server", BindingFlags.NonPublic | BindingFlags.Instance);
+ var pipeStream = serverFieldInfo.GetValue(message.Client) as PipeStream;
+
+ var canceled = CancelIoEx(pipeStream.SafePipeHandle.DangerousGetHandle(), IntPtr.Zero);
+
+ foreach (var msDelay in message.MsDelays ?? [])
+ {
+ await Task.Delay(msDelay);
+ canceled = CancelIoEx(pipeStream.SafePipeHandle.DangerousGetHandle(), IntPtr.Zero);
+ }
+
+ await Task.Delay(50);
+ return canceled;
+#else
+ return false;
+#endif
+ }
+
+ public async Task Delay(int delay = 0, CancellationToken cancellationToken = default)
+ {
+ await Task.Delay(delay, cancellationToken);
+ return true;
+ }
}
\ No newline at end of file
diff --git a/src/UiPath.CoreIpc.Tests/NamedPipeTests.cs b/src/UiPath.CoreIpc.Tests/NamedPipeTests.cs
index e81f1eaa..36eb2f23 100644
--- a/src/UiPath.CoreIpc.Tests/NamedPipeTests.cs
+++ b/src/UiPath.CoreIpc.Tests/NamedPipeTests.cs
@@ -1,19 +1,20 @@
-using System.IO.Pipes;
+using System.IO;
+using System.IO.Pipes;
using System.Security.Principal;
-namespace UiPath.CoreIpc.Tests;
+namespace UiPath.Ipc.Tests;
public class SystemNamedPipeTests : SystemTests>
{
string _pipeName = "system";
protected override ServiceHostBuilder Configure(ServiceHostBuilder serviceHostBuilder) =>
- serviceHostBuilder.UseNamedPipes(Configure(new NamedPipeSettings(_pipeName+GetHashCode())));
- protected override NamedPipeClientBuilder CreateSystemClientBuilder() =>
- new NamedPipeClientBuilder(_pipeName+GetHashCode()).AllowImpersonation();
+ serviceHostBuilder.UseNamedPipes(Configure(new NamedPipeSettings(_pipeName + GetHashCode())));
+ protected override NamedPipeClientBuilder CreateSystemClientBuilder() =>
+ new NamedPipeClientBuilder(_pipeName + GetHashCode()).AllowImpersonation();
[Fact]
public void PipeExists()
{
IOHelpers.PipeExists(System.Guid.NewGuid().ToString()).ShouldBeFalse();
- IOHelpers.PipeExists("system"+GetHashCode(), 50).ShouldBeTrue();
+ IOHelpers.PipeExists("system" + GetHashCode(), 50).ShouldBeTrue();
}
[Fact]
public Task ServerName() => SystemClientBuilder().ValidateAndBuild().GetGuid(System.Guid.Empty);
@@ -36,7 +37,42 @@ public async Task PipeSecurityForWindows()
.AddEndpoint()
.ValidateAndBuild();
_ = protectedService.RunAsync();
- await CreateSystemService().DoNothing().ShouldThrowAsync();
+ await CreateSystemService().FireAndForget().ShouldThrowAsync();
+ }
+
+ [Theory]
+ [InlineData(new int[0])]
+ [InlineData(100)]
+ [InlineData(1100)]
+ [InlineData(100, 100)]
+ public async Task PipeCancelIoOnServer_AnyNoOfTimes(params int[] msDelays)
+ {
+ bool cancelIoResult = false;
+
+ // Any number of kernel32.CancelIoEx calls should not cause the client to give up on the connection.
+ var act = async () => cancelIoResult = await _systemClient.CancelIoPipe(new() { MsDelays = msDelays });
+ await act.ShouldNotThrowAsync();
+
+ //Make sure the connection is still working
+ (await _systemClient.Delay()).ShouldBeTrue();
+
+ cancelIoResult.ShouldBeTrue();
+ }
+
+ [Fact]
+ public async Task PipeCancelIoOnClient()
+ {
+ (await _systemClient.Delay()).ShouldBeTrue();
+
+ var delayTask = _systemClient.Delay(500);
+ await Task.Delay(100);
+ var pipeStream = ((IpcProxy)_systemClient).Connection.Network as PipeStream;
+ SystemService.CancelIoEx(pipeStream.SafePipeHandle.DangerousGetHandle(), IntPtr.Zero).ShouldBeTrue();
+
+ (await delayTask).ShouldBeTrue();
+
+ //Make sure the connection is still working
+ (await _systemClient.Delay()).ShouldBeTrue();
}
#endif
}
diff --git a/src/UiPath.CoreIpc.Tests/NestedStreamTests.cs b/src/UiPath.CoreIpc.Tests/NestedStreamTests.cs
index b30d6f93..a96af00a 100644
--- a/src/UiPath.CoreIpc.Tests/NestedStreamTests.cs
+++ b/src/UiPath.CoreIpc.Tests/NestedStreamTests.cs
@@ -1,6 +1,6 @@
using System.IO.Compression;
-namespace UiPath.CoreIpc.Tests;
+namespace UiPath.Ipc.Tests;
public class NestedStreamTests
{
@@ -358,7 +358,7 @@ public async Task ReadAsync_ValidatesArguments()
await Assert.ThrowsAsync(() => this.stream.ReadAsync(buffer, 1, buffer.Length));
}
}
-public static class StreamExtensions
+internal static class StreamExtensions
{
///
/// Creates a that can read no more than a given number of bytes from an underlying stream.
diff --git a/src/UiPath.CoreIpc.Tests/SystemTests.cs b/src/UiPath.CoreIpc.Tests/SystemTests.cs
index e33832f4..232c1ac4 100644
--- a/src/UiPath.CoreIpc.Tests/SystemTests.cs
+++ b/src/UiPath.CoreIpc.Tests/SystemTests.cs
@@ -1,11 +1,11 @@
using System.Text;
-namespace UiPath.CoreIpc.Tests;
+namespace UiPath.Ipc.Tests;
public abstract class SystemTests : TestBase where TBuilder : ServiceClientBuilder
{
protected ServiceHost _systemHost;
- protected ISystemService _systemClient;
+ protected readonly ISystemService _systemClient;
protected readonly SystemService _systemService;
public SystemTests()
{
@@ -55,10 +55,10 @@ public async Task ServerTimeout()
[Fact]
public async Task Void()
{
- _systemService.DidNothing = false;
- await _systemClient.DoNothing();
- _systemService.DidNothing.ShouldBeFalse();
- while (!_systemService.DidNothing)
+ _systemService.FireAndForgetDone = false;
+ await _systemClient.FireAndForget();
+ _systemService.FireAndForgetDone.ShouldBeFalse();
+ while (!_systemService.FireAndForgetDone)
{
await Task.Delay(10);
Trace.WriteLine(this + " Void");
@@ -194,7 +194,7 @@ public async Task DownloadNoRead()
await Guid();
}
protected abstract TBuilder CreateSystemClientBuilder();
- protected TBuilder SystemClientBuilder() => CreateSystemClientBuilder().SerializeParametersAsObjects().RequestTimeout(RequestTimeout).Logger(_serviceProvider);
+ protected TBuilder SystemClientBuilder() => CreateSystemClientBuilder().RequestTimeout(RequestTimeout).Logger(_serviceProvider);
[Fact]
public async Task BeforeCall()
{
@@ -202,15 +202,15 @@ public async Task BeforeCall()
var proxy = SystemClientBuilder().BeforeCall(async (c, _) =>
{
newConnection = c.NewConnection;
- c.Method.ShouldBe(typeof(ISystemService).GetMethod(nameof(ISystemService.DoNothing)));
+ c.Method.ShouldBe(typeof(ISystemService).GetMethod(nameof(ISystemService.FireAndForget)));
c.Arguments.Single().ShouldBe(""); // cancellation token
}).ValidateAndBuild();
newConnection.ShouldBeFalse();
- await proxy.DoNothing();
+ await proxy.FireAndForget();
newConnection.ShouldBeTrue();
- await proxy.DoNothing();
+ await proxy.FireAndForget();
newConnection.ShouldBeFalse();
var ipcProxy = (IpcProxy)proxy;
var closed = false;
@@ -218,10 +218,10 @@ public async Task BeforeCall()
ipcProxy.CloseConnection();
closed.ShouldBeTrue();
newConnection.ShouldBeFalse();
- await proxy.DoNothing();
+ await proxy.FireAndForget();
newConnection.ShouldBeTrue();
- await proxy.DoNothing();
+ await proxy.FireAndForget();
newConnection.ShouldBeFalse();
ipcProxy.CloseConnection();
}
diff --git a/src/UiPath.CoreIpc.Tests/TcpTests..cs b/src/UiPath.CoreIpc.Tests/TcpTests..cs
index cca919c5..9519b1aa 100644
--- a/src/UiPath.CoreIpc.Tests/TcpTests..cs
+++ b/src/UiPath.CoreIpc.Tests/TcpTests..cs
@@ -1,6 +1,6 @@
using System.Net;
-using UiPath.CoreIpc.Tcp;
-namespace UiPath.CoreIpc.Tests;
+using UiPath.Ipc.Tcp;
+namespace UiPath.Ipc.Tests;
public class SystemTcpTests : SystemTests>
{
int _port = 3131 + GetCount();
diff --git a/src/UiPath.CoreIpc.Tests/TestBase.cs b/src/UiPath.CoreIpc.Tests/TestBase.cs
index 98d75a4e..b38fb183 100644
--- a/src/UiPath.CoreIpc.Tests/TestBase.cs
+++ b/src/UiPath.CoreIpc.Tests/TestBase.cs
@@ -1,6 +1,6 @@
using Nito.AsyncEx;
-namespace UiPath.CoreIpc.Tests;
+namespace UiPath.Ipc.Tests;
public abstract class TestBase : IDisposable
{
@@ -8,9 +8,10 @@ public abstract class TestBase : IDisposable
protected static int Count = -1;
public static readonly TimeSpan RequestTimeout =
#if CI
- TimeSpan.FromSeconds(2) +
+ TimeSpan.FromSeconds(3) +
#endif
- (Debugger.IsAttached ? TimeSpan.FromDays(1) : TimeSpan.FromSeconds(2));
+ TimeSpan.FromSeconds(3);
+ // (Debugger.IsAttached ? TimeSpan.FromDays(1) : TimeSpan.FromSeconds(2));
protected readonly IServiceProvider _serviceProvider;
protected readonly AsyncContext _guiThread = new AsyncContextThread().Context;
diff --git a/src/UiPath.CoreIpc.Tests/UiPath.CoreIpc.Tests.csproj b/src/UiPath.CoreIpc.Tests/UiPath.CoreIpc.Tests.csproj
index eaf03da6..5b773092 100644
--- a/src/UiPath.CoreIpc.Tests/UiPath.CoreIpc.Tests.csproj
+++ b/src/UiPath.CoreIpc.Tests/UiPath.CoreIpc.Tests.csproj
@@ -2,17 +2,19 @@
net6.0;net461;net6.0-windows
+ UiPath.Ipc.Tests
$(NoWarn);1998
$(DefineConstants);$(DefineConstantsEx)
latest
true
+ annotations
-
-
-
+
+
+
@@ -25,6 +27,6 @@
-
+
\ No newline at end of file
diff --git a/src/UiPath.CoreIpc.Tests/ValidationTests.cs b/src/UiPath.CoreIpc.Tests/ValidationTests.cs
index a1a0197c..543c4194 100644
--- a/src/UiPath.CoreIpc.Tests/ValidationTests.cs
+++ b/src/UiPath.CoreIpc.Tests/ValidationTests.cs
@@ -1,4 +1,4 @@
-namespace UiPath.CoreIpc.Tests;
+namespace UiPath.Ipc.Tests;
public class ValidationTests
{
diff --git a/src/UiPath.CoreIpc.Tests/WebSocketTests.cs b/src/UiPath.CoreIpc.Tests/WebSocketTests.cs
index 0661160c..ad1e920d 100644
--- a/src/UiPath.CoreIpc.Tests/WebSocketTests.cs
+++ b/src/UiPath.CoreIpc.Tests/WebSocketTests.cs
@@ -1,8 +1,8 @@
-using UiPath.CoreIpc.WebSockets;
-namespace UiPath.CoreIpc.Tests;
+using UiPath.Ipc.WebSockets;
+namespace UiPath.Ipc.Tests;
public class SystemWebSocketTests : SystemTests>
{
- int _port = 1313 + GetCount();
+ int _port = 51313 + GetCount();
HttpSysWebSocketsListener _listener;
protected override ServiceHostBuilder Configure(ServiceHostBuilder serviceHostBuilder)
{
diff --git a/src/UiPath.CoreIpc/CancellationTokenSourcePool.cs b/src/UiPath.CoreIpc/CancellationTokenSourcePool.cs
index a6d0b3f8..0d517d86 100644
--- a/src/UiPath.CoreIpc/CancellationTokenSourcePool.cs
+++ b/src/UiPath.CoreIpc/CancellationTokenSourcePool.cs
@@ -1,4 +1,4 @@
-namespace UiPath.CoreIpc;
+namespace UiPath.Ipc;
// https://github.com/dotnet/aspnetcore/blob/main/src/Shared/CancellationTokenSourcePool.cs
internal static class CancellationTokenSourcePool
{
diff --git a/src/UiPath.CoreIpc/Client/ClientConnectionsRegistry.cs b/src/UiPath.CoreIpc/Client/ClientConnectionsRegistry.cs
index 14b708fc..9f5bcc70 100644
--- a/src/UiPath.CoreIpc/Client/ClientConnectionsRegistry.cs
+++ b/src/UiPath.CoreIpc/Client/ClientConnectionsRegistry.cs
@@ -1,4 +1,4 @@
-namespace UiPath.CoreIpc;
+namespace UiPath.Ipc;
static class ClientConnectionsRegistry
{
@@ -35,7 +35,6 @@ internal static ClientConnection Remove(IConnectionKey connectionKey)
}
interface IConnectionKey : IEquatable
{
- string SslServer { get; }
ClientConnection CreateClientConnection();
}
abstract class ClientConnection : IDisposable
diff --git a/src/UiPath.CoreIpc/Client/ServiceClient.cs b/src/UiPath.CoreIpc/Client/ServiceClient.cs
index 8ee847f5..2561d267 100644
--- a/src/UiPath.CoreIpc/Client/ServiceClient.cs
+++ b/src/UiPath.CoreIpc/Client/ServiceClient.cs
@@ -1,5 +1,4 @@
-using System.Net.Security;
-namespace UiPath.CoreIpc;
+namespace UiPath.Ipc;
using ConnectionFactory = Func>;
using BeforeCallHandler = Func;
@@ -24,23 +23,19 @@ class ServiceClient : IServiceClient, IConnectionKey where TInterfac
private Server _server;
private ClientConnection _clientConnection;
- internal ServiceClient(ISerializer serializer, TimeSpan requestTimeout, ILogger logger, ConnectionFactory connectionFactory, string sslServer = null, BeforeCallHandler beforeCall = null, bool objectParameters = false, EndpointSettings serviceEndpoint = null)
+ internal ServiceClient(ISerializer serializer, TimeSpan requestTimeout, ILogger logger, ConnectionFactory connectionFactory, BeforeCallHandler beforeCall = null, EndpointSettings serviceEndpoint = null)
{
- ObjectParameters = objectParameters;
_serializer = serializer;
_requestTimeout = requestTimeout;
_logger = logger;
_connectionFactory = connectionFactory;
- SslServer = sslServer;
_beforeCall = beforeCall;
_serviceEndpoint = serviceEndpoint;
}
protected int HashCode { get; init; }
- public string SslServer { get; init; }
public virtual string Name => _connection?.Name;
private bool LogEnabled => _logger.Enabled();
Connection IServiceClient.Connection => _connection;
- public bool ObjectParameters { get; init; }
public TInterface CreateProxy()
{
@@ -48,7 +43,7 @@ public TInterface CreateProxy()
(proxy as IpcProxy).ServiceClient = this;
return proxy;
}
-
+
public override int GetHashCode() => HashCode;
private void OnNewConnection(Connection connection, bool alreadyHasServer = false)
@@ -98,7 +93,7 @@ async Task Invoke()
await _beforeCall(new(newConnection, method, args), token);
}
var requestId = _connection.NewRequestId();
- var request = new Request(typeof(TInterface).Name, requestId, methodName, serializedArguments, ObjectParameters ? args : null, messageTimeout.TotalSeconds)
+ var request = new Request(typeof(TInterface).Name, requestId, methodName, serializedArguments, messageTimeout.TotalSeconds)
{
UploadStream = uploadStream
};
@@ -106,17 +101,12 @@ async Task Invoke()
{
Log($"IpcClient calling {methodName} {requestId} {Name}.");
}
- if (ObjectParameters && !method.ReturnType.IsGenericType)
- {
- await _connection.Send(request, token);
- return default;
- }
var response = await _connection.RemoteCall(request, token);
if (LogEnabled)
{
Log($"IpcClient called {methodName} {requestId} {Name}.");
}
- return response.Deserialize(_serializer, ObjectParameters);
+ return response.Deserialize(_serializer);
}
catch (Exception ex)
{
@@ -129,10 +119,8 @@ async Task Invoke()
}
void SerializeArguments()
{
- if (!ObjectParameters)
- {
- serializedArguments = new string[args.Length];
- }
+ serializedArguments = new string[args.Length];
+
for (int index = 0; index < args.Length; index++)
{
switch (args[index])
@@ -150,10 +138,8 @@ void SerializeArguments()
args[index] = "";
break;
}
- if (!ObjectParameters)
- {
- serializedArguments[index] = _serializer.Serialize(args[index]);
- }
+
+ serializedArguments[index] = _serializer.Serialize(args[index]);
}
}
}
@@ -201,9 +187,8 @@ private async Task Connect(CancellationToken cancellationToken)
{
clientConnection.Dispose();
throw;
- }
- var stream = SslServer == null ? network : await AuthenticateAsClient(network);
- OnNewConnection(new(stream, _serializer, _logger, Name));
+ }
+ OnNewConnection(new(network, _serializer, _logger, Name));
if (LogEnabled)
{
Log($"CreateConnection {Name}.");
@@ -215,21 +200,6 @@ private async Task Connect(CancellationToken cancellationToken)
clientConnection.Release();
}
return true;
- async Task AuthenticateAsClient(Stream network)
- {
- var sslStream = new SslStream(network);
- try
- {
- await sslStream.AuthenticateAsClientAsync(SslServer);
- }
- catch
- {
- sslStream.Dispose();
- throw;
- }
- Debug.Assert(sslStream.IsEncrypted && sslStream.IsSigned);
- return sslStream;
- }
}
private void ReuseClientConnection(ClientConnection clientConnection)
@@ -287,7 +257,7 @@ protected virtual void Dispose(bool disposing)
public override string ToString() => Name;
- public virtual bool Equals(IConnectionKey other) => SslServer == other.SslServer;
+ public virtual bool Equals(IConnectionKey other) => true;
public virtual ClientConnection CreateClientConnection() => throw new NotImplementedException();
}
diff --git a/src/UiPath.CoreIpc/Client/ServiceClientBuilder.cs b/src/UiPath.CoreIpc/Client/ServiceClientBuilder.cs
index db59c9f7..afbf26e8 100644
--- a/src/UiPath.CoreIpc/Client/ServiceClientBuilder.cs
+++ b/src/UiPath.CoreIpc/Client/ServiceClientBuilder.cs
@@ -1,4 +1,4 @@
-namespace UiPath.CoreIpc;
+namespace UiPath.Ipc;
using ConnectionFactory = Func>;
using BeforeCallHandler = Func;
@@ -13,8 +13,6 @@ public abstract class ServiceClientBuilder where TInterfac
protected BeforeCallHandler _beforeCall;
protected object _callbackInstance;
protected TaskScheduler _taskScheduler;
- protected string _sslServer;
- protected bool _objectParameters;
protected ServiceClientBuilder(Type callbackContract, IServiceProvider serviceProvider)
{
@@ -32,16 +30,6 @@ public TDerived ConnectionFactory(ConnectionFactory connectionFactory)
return (TDerived)this;
}
- public TDerived EncryptAndSign(string certificateServerName)
- {
- if (string.IsNullOrWhiteSpace(certificateServerName))
- {
- throw new ArgumentException($"'{nameof(certificateServerName)}' must match the name on the server's certificate.", nameof(certificateServerName));
- }
- _sslServer = certificateServerName;
- return (TDerived)this;
- }
-
public TDerived BeforeCall(BeforeCallHandler beforeCall)
{
_beforeCall = beforeCall;
@@ -53,18 +41,6 @@ public TDerived Logger(ILogger logger)
_logger = logger;
return (TDerived)this;
}
- ///
- /// By default, method parameters are serialized as json strings. Setting this allows serialization as json objects.
- /// This should improve performance for large strings, but decrease it for many small objects.
- /// Setting it breaks compatibility with older servers.
- /// So a proxy with this setting will only be able to connect to servers that understand the new encoding.
- ///
- /// this
- public TDerived SerializeParametersAsObjects()
- {
- _objectParameters = true;
- return (TDerived)this;
- }
public TDerived Logger(IServiceProvider serviceProvider) => Logger(serviceProvider.GetRequiredService>());
diff --git a/src/UiPath.CoreIpc/Connection.cs b/src/UiPath.CoreIpc/Connection.cs
index e4404147..f5c59229 100644
--- a/src/UiPath.CoreIpc/Connection.cs
+++ b/src/UiPath.CoreIpc/Connection.cs
@@ -1,6 +1,11 @@
-namespace UiPath.CoreIpc;
+namespace UiPath.Ipc;
using static TaskCompletionPool;
using static IOHelpers;
+using System.IO.Pipes;
+using System.IO;
+using System.Threading;
+using Microsoft.Extensions.Logging;
+
public sealed class Connection : IDisposable
{
private static readonly IOException ClosedException = new("Connection closed.");
@@ -75,7 +80,6 @@ internal async ValueTask RemoteCall(Request request, CancellationToken
}
internal ValueTask Send(Request request, CancellationToken token)
{
- Debug.Assert(request.Parameters == null || request.ObjectParameters == null);
var uploadStream = request.UploadStream;
var requestBytes = SerializeToStream(request);
return uploadStream == null ?
@@ -95,7 +99,6 @@ Task CancelServerCall(string requestId) =>
}
internal ValueTask Send(Response response, CancellationToken cancellationToken)
{
- Debug.Assert(response.Data == null || response.ObjectData == null);
var responseBytes = SerializeToStream(response);
return response.DownloadStream == null ?
SendMessage(MessageType.Response, responseBytes, cancellationToken) :
@@ -183,14 +186,32 @@ private async ValueTask ReadBuffer(int length)
{
int offset = 0;
int toRead = length;
+
do
{
- var read = await Network.ReadAsync(
+ int read;
+ try
+ {
+ read = await Network.ReadAsync(
#if NET461
- _buffer, offset, toRead);
+ _buffer, offset, toRead);
#else
- _buffer.AsMemory(offset, toRead));
+ _buffer.AsMemory(offset, toRead));
#endif
+ }
+ catch (OperationCanceledException ex) when (Network is PipeStream)
+ {
+ // Originally we decided to throw this exception the 2nd time we caught it, but later it was discovered that the NodeJS runtime continuosly retries.
+
+ // In some Windows client environments, OperationCanceledException is sporadically thrown on named pipe ReadAsync operation (ERROR_OPERATION_ABORTED on overlapped ReadFile)
+ // The cause has not yet been discovered(os specific, antiviruses, monitoring application), and we have implemented a retry system
+ // ROBO-3083
+
+ Logger.LogException(ex, $"Retrying ReadAsync for {Network.GetType()}");
+ await Task.Delay(10); //Without this delay, on net framework can get OperationCanceledException on the second ReadAsync call
+ continue;
+ }
+
if (read == 0)
{
return false;
@@ -319,7 +340,7 @@ private void OnCancellationReceived(string requestId)
{
CancellationReceived(requestId);
}
- catch(Exception ex)
+ catch (Exception ex)
{
Log(ex);
}
diff --git a/src/UiPath.CoreIpc/Dtos.cs b/src/UiPath.CoreIpc/Dtos.cs
index cbf278ba..ea7e66a8 100644
--- a/src/UiPath.CoreIpc/Dtos.cs
+++ b/src/UiPath.CoreIpc/Dtos.cs
@@ -1,16 +1,16 @@
-using System.Text;
+using System.Diagnostics.CodeAnalysis;
+using System.Text;
using Newtonsoft.Json;
-namespace UiPath.CoreIpc;
+namespace UiPath.Ipc;
public class Message
{
- internal bool ObjectParameters { get; set; }
internal Type CallbackContract { get; set; }
[JsonIgnore]
public IClient Client { get; set; }
[JsonIgnore]
public TimeSpan RequestTimeout { get; set; }
public TCallbackInterface GetCallback() where TCallbackInterface : class =>
- Client.GetCallback(CallbackContract, ObjectParameters);
+ Client.GetCallback(CallbackContract);
public void ImpersonateClient(Action action) => Client.Impersonate(action);
}
public class Message : Message
@@ -18,34 +18,43 @@ public class Message : Message
public Message(TPayload payload) => Payload = payload;
public TPayload Payload { get; }
}
-record Request(string Endpoint, string Id, string MethodName, string[] Parameters, object[] ObjectParameters, double TimeoutInSeconds)
+record Request(string Endpoint, string Id, string MethodName, string[] Parameters, double TimeoutInSeconds)
{
internal Stream UploadStream { get; set; }
public override string ToString() => $"{Endpoint} {MethodName} {Id}.";
- internal bool HasObjectParameters => ObjectParameters is not null;
internal TimeSpan GetTimeout(TimeSpan defaultTimeout) => TimeoutInSeconds == 0 ? defaultTimeout : TimeSpan.FromSeconds(TimeoutInSeconds);
}
record CancellationRequest(string RequestId);
-record Response(string RequestId, string Data = null, object ObjectData = null, Error Error = null)
+record Response(string RequestId, string Data = null, Error Error = null)
{
internal Stream DownloadStream { get; set; }
public static Response Fail(Request request, Exception ex) => new(request.Id, Error: ex.ToError());
public static Response Success(Request request, string data) => new(request.Id, data);
public static Response Success(Request request, Stream downloadStream) => new(request.Id) { DownloadStream = downloadStream };
- public TResult Deserialize(ISerializer serializer, bool objectParameters)
+ public TResult Deserialize(ISerializer serializer)
{
if (Error != null)
{
throw new RemoteException(Error);
}
- return (TResult)(DownloadStream ?? (objectParameters ?
- serializer.Deserialize(ObjectData, typeof(TResult)) : serializer.Deserialize(Data ?? "", typeof(TResult))));
+ return (TResult)(DownloadStream ?? serializer.Deserialize(Data ?? "", typeof(TResult)));
}
}
[Serializable]
public record Error(string Message, string StackTrace, string Type, Error InnerError)
{
+ [return: NotNullIfNotNull("exception")]
+ public static Error? FromException(Exception? exception)
+ => exception is null
+ ? null
+ : new(
+ Message: exception.Message,
+ StackTrace: exception.StackTrace ?? exception.GetBaseException().StackTrace,
+ Type: GetExceptionType(exception),
+ InnerError: FromException(exception.InnerException));
public override string ToString() => new RemoteException(this).ToString();
+
+ private static string GetExceptionType(Exception exception) => (exception as RemoteException)?.Type ?? exception.GetType().FullName;
}
[Serializable]
public class RemoteException : Exception
diff --git a/src/UiPath.CoreIpc/Helpers.cs b/src/UiPath.CoreIpc/Helpers.cs
index 58c39029..65918e0e 100644
--- a/src/UiPath.CoreIpc/Helpers.cs
+++ b/src/UiPath.CoreIpc/Helpers.cs
@@ -6,7 +6,7 @@
using System.Runtime.InteropServices;
using System.Security.AccessControl;
using System.Security.Principal;
-namespace UiPath.CoreIpc;
+namespace UiPath.Ipc;
using static CancellationTokenSourcePool;
public static class Helpers
{
@@ -19,13 +19,13 @@ public static async Task ConnectAsync(this TcpClient tcpClient, IPAddress addres
await tcpClient.ConnectAsync(address, port);
}
#endif
- public static Error ToError(this Exception ex) => new(ex.Message, ex.StackTrace ?? ex.GetBaseException().StackTrace, GetExceptionType(ex), ex.InnerException?.ToError());
+ internal static Error ToError(this Exception ex) => new(ex.Message, ex.StackTrace ?? ex.GetBaseException().StackTrace, GetExceptionType(ex), ex.InnerException?.ToError());
private static string GetExceptionType(Exception exception) => (exception as RemoteException)?.Type ?? exception.GetType().FullName;
- public static bool Enabled(this ILogger logger) => logger != null && logger.IsEnabled(LogLevel.Information);
+ internal static bool Enabled(this ILogger logger) => logger != null && logger.IsEnabled(LogLevel.Information);
[Conditional("DEBUG")]
- public static void AssertDisposed(this SemaphoreSlim semaphore) => semaphore.AssertFieldNull("m_waitHandle");
+ internal static void AssertDisposed(this SemaphoreSlim semaphore) => semaphore.AssertFieldNull("m_waitHandle");
[Conditional("DEBUG")]
- public static void AssertDisposed(this CancellationTokenSource cts)
+ internal static void AssertDisposed(this CancellationTokenSource cts)
{
#if NET461
cts.AssertFieldNull("m_kernelEvent");
@@ -38,10 +38,10 @@ public static void AssertDisposed(this CancellationTokenSource cts)
[Conditional("DEBUG")]
static void AssertFieldNull(this object obj, string field) =>
Debug.Assert(obj.GetType().GetField(field, BindingFlags.Instance | BindingFlags.NonPublic).GetValue(obj) == null);
- public static TDelegate MakeGenericDelegate(this MethodInfo genericMethod, Type genericArgument) where TDelegate : Delegate =>
+ internal static TDelegate MakeGenericDelegate(this MethodInfo genericMethod, Type genericArgument) where TDelegate : Delegate =>
(TDelegate)genericMethod.MakeGenericMethod(genericArgument).CreateDelegate(typeof(TDelegate));
- public static MethodInfo GetStaticMethod(this Type type, string name) => type.GetMethod(name, BindingFlags.Static | BindingFlags.NonPublic);
- public static MethodInfo GetInterfaceMethod(this Type type, string name)
+ internal static MethodInfo GetStaticMethod(this Type type, string name) => type.GetMethod(name, BindingFlags.Static | BindingFlags.NonPublic);
+ internal static MethodInfo GetInterfaceMethod(this Type type, string name)
{
var method = type.GetMethod(name, InstanceFlags) ??
type.GetInterfaces().Select(t => t.GetMethod(name, InstanceFlags)).FirstOrDefault(m => m != null) ??
@@ -52,15 +52,15 @@ public static MethodInfo GetInterfaceMethod(this Type type, string name)
}
return method;
}
- public static IEnumerable GetInterfaceMethods(this Type type) =>
+ internal static IEnumerable GetInterfaceMethods(this Type type) =>
type.GetMethods().Concat(type.GetInterfaces().SelectMany(i => i.GetMethods()));
- public static object GetDefaultValue(this ParameterInfo parameter) => parameter switch
+ internal static object GetDefaultValue(this ParameterInfo parameter) => parameter switch
{
{ HasDefaultValue: false } => null,
{ ParameterType: { IsValueType: true }, DefaultValue: null } => Activator.CreateInstance(parameter.ParameterType),
_ => parameter.DefaultValue
};
- public static ReadOnlyDictionary ToReadOnlyDictionary(this IDictionary dictionary) => new(dictionary);
+ internal static ReadOnlyDictionary ToReadOnlyDictionary(this IDictionary dictionary) => new(dictionary);
public static void LogException(this ILogger logger, Exception ex, object tag)
{
var message = $"{tag} # {ex}";
@@ -167,7 +167,7 @@ private static async ValueTask WriteMessageCore(this Stream stream, RecyclableMe
internal static Task WriteBuffer(this Stream stream, byte[] buffer, CancellationToken cancellationToken) =>
stream.WriteAsync(buffer, 0, buffer.Length, cancellationToken);
}
-public static class Validator
+internal static class Validator
{
public static void Validate(ServiceHostBuilder serviceHostBuilder)
{
@@ -267,7 +267,7 @@ private static void CheckDerivedStream(MethodInfo method, Type type)
}
}
}
-public readonly struct TimeoutHelper : IDisposable
+internal readonly struct TimeoutHelper : IDisposable
{
private static readonly Action