Skip to content

Commit 4b29ac9

Browse files
GetProxy simplification
1 parent be30f9c commit 4b29ac9

File tree

15 files changed

+94
-43
lines changed

15 files changed

+94
-43
lines changed

src/Playground/Program.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,6 @@ private static async Task Main(string[] args)
8787
},
8888
Scheduler = clientScheduler
8989
}
90-
.GetProxyFactory()
9190
.GetProxy<Contracts.IServerOperations>();
9291

9392
await proxy1.Register();

src/UiPath.CoreIpc.BackCompat/Clients/NamedPipeClientBuilder.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
using UiPath.Ipc;
2-
using UiPath.Ipc.Transport.NamedPipe;
1+
using UiPath.Ipc.Transport.NamedPipe;
32

43
namespace UiPath.Ipc.BackCompat;
54

@@ -68,6 +67,5 @@ protected override TInterface BuildCore(EndpointSettings? serviceEndpoint)
6867
BeforeCall = BeforeCall,
6968
Callbacks = serviceEndpoint.ToEndpointCollection()
7069
}
71-
.GetProxyFactory()
7270
.GetProxy<TInterface>();
7371
}

src/UiPath.CoreIpc.BackCompat/Clients/TcpClientBuilder.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using System.Net;
2-
using UiPath.Ipc;
32
using UiPath.Ipc.Transport.Tcp;
43

54
namespace UiPath.Ipc.BackCompat;
@@ -31,7 +30,6 @@ protected override TInterface BuildCore(EndpointSettings? serviceEndpoint)
3130
BeforeCall = BeforeCall,
3231
Callbacks = serviceEndpoint.ToEndpointCollection()
3332
}
34-
.GetProxyFactory()
3533
.GetProxy<TInterface>();
3634
}
3735

src/UiPath.CoreIpc.BackCompat/Clients/WebSocketClientBuilder.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
using UiPath.Ipc;
2-
using UiPath.Ipc.Transport.WebSocket;
1+
using UiPath.Ipc.Transport.WebSocket;
32

43
namespace UiPath.Ipc.BackCompat;
54

@@ -25,7 +24,6 @@ protected override TInterface BuildCore(EndpointSettings? serviceEndpoint)
2524
BeforeCall = BeforeCall,
2625
Callbacks = serviceEndpoint.ToEndpointCollection(),
2726
}
28-
.GetProxyFactory()
2927
.GetProxy<TInterface>();
3028
}
3129

src/UiPath.CoreIpc/Client/ServiceClient.cs

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
namespace UiPath.Ipc;
22

3+
using System.Linq.Expressions;
4+
using ServiceClientProperFactory = Func<ClientBase, Type, ServiceClient>;
5+
36
internal abstract class ServiceClient : IDisposable
47
{
58
#region " NonGeneric-Generic adapter cache "
@@ -26,6 +29,7 @@ private static InvokeDelegate CreateInvokeDelegate(Type returnType)
2629
public event EventHandler? ConnectionClosed;
2730

2831
private readonly Type _interfaceType;
32+
private readonly ContextfulLazy<IpcProxy> _proxy = new();
2933

3034
protected ServiceClient(Type interfaceType)
3135
{
@@ -39,11 +43,19 @@ protected ServiceClient(Type interfaceType)
3943

4044
protected abstract Task<(Connection connection, bool newlyConnected)> EnsureConnection(CancellationToken ct);
4145

42-
public T CreateProxy<T>() where T : class
46+
public T GetProxy<T>() where T : class
4347
{
44-
var proxy = DispatchProxy.Create<T, IpcProxy>();
45-
(proxy as IpcProxy)!.ServiceClient = this;
46-
return proxy;
48+
if (!_interfaceType.IsAssignableTo(typeof(T)))
49+
{
50+
throw new ArgumentOutOfRangeException($"The provided generic argument T is not assignable to the proxy type. T is {typeof(T).Name}. The proxy type is {_interfaceType.Name}.");
51+
}
52+
53+
return (_proxy.GetValue(() =>
54+
{
55+
var proxy = (DispatchProxy.Create<T, IpcProxy>() as IpcProxy)!;
56+
proxy.ServiceClient = this;
57+
return proxy;
58+
}) as T)!;
4759
}
4860

4961
private Task<TResult> Invoke<TResult>(MethodInfo method, object?[] args)
@@ -139,6 +151,40 @@ private void Dispose(bool disposing)
139151
public override string ToString() => DebugName;
140152
}
141153

154+
internal static class ServiceClientProper
155+
{
156+
private static readonly ConcurrentDictionary<Type, ServiceClientProperFactory> CachedFactories = new();
157+
private static ServiceClientProperFactory GetFactory(Type clientType) => CachedFactories.GetOrAdd(clientType, CreateFactory);
158+
private static ServiceClientProperFactory CreateFactory(Type clientType)
159+
{
160+
if (clientType
161+
.GetInterfaces()
162+
.SingleOrDefault(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IClient<,>))
163+
?.GetGenericArguments()
164+
is not [var clientStateType, var clientType2] || clientType2 != clientType)
165+
{
166+
throw new ArgumentOutOfRangeException(nameof(clientType), "The client implements 0 or more than 1 IClient<,> interfaces or the single interface's 2nd generic argument is not the client type itself.");
167+
}
168+
169+
var ctor = typeof(ServiceClientProper<,>)
170+
.MakeGenericType(clientStateType, clientType)
171+
.GetConstructor([clientType, typeof(Type)])!;
172+
173+
var paramofClientBase = Expression.Parameter(typeof(ClientBase));
174+
var paramofType = Expression.Parameter(typeof(Type));
175+
return Expression.Lambda<ServiceClientProperFactory>(
176+
Expression.New(
177+
ctor,
178+
Expression.Convert(paramofClientBase, clientType),
179+
paramofType),
180+
paramofClientBase,
181+
paramofType).Compile();
182+
}
183+
184+
public static ServiceClient Create(ClientBase client, Type proxyType)
185+
=> GetFactory(client.GetType())(client, proxyType);
186+
}
187+
142188
internal sealed class ServiceClientProper<TClient, TClientState> : ServiceClient
143189
where TClient : ClientBase, IClient<TClientState, TClient>
144190
where TClientState : class, IClientState<TClient, TClientState>, new()

src/UiPath.CoreIpc/Extensibility/ClientBase.cs

Lines changed: 5 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
using UiPath.Ipc.Transport.Tcp;
2-
3-
namespace UiPath.Ipc;
1+
namespace UiPath.Ipc;
42

53
public abstract record ClientBase : EndpointConfig
64
{
5+
private readonly ConcurrentDictionary<Type, ServiceClient> _clients = new();
6+
private ServiceClient GetServiceClient(Type proxyType) => _clients.GetOrAdd(proxyType, ServiceClientProper.Create(this, proxyType));
7+
78
public IServiceProvider? ServiceProvider { get; init; }
89
public EndpointCollection? Callbacks { get; init; }
910
public ILogger? Logger { get; init; }
@@ -16,9 +17,7 @@ public abstract record ClientBase : EndpointConfig
1617
public virtual void Validate() { }
1718

1819
public TProxy GetProxy<TProxy>() where TProxy : class
19-
=> new ServiceClientProper<TClient, TClientState>(_client, typeof(TProxy))
20-
.CreateProxy<TProxy>();
21-
20+
=> GetServiceClient(typeof(TProxy)).GetProxy<TProxy>();
2221

2322
internal void ValidateInternal()
2423
{
@@ -62,27 +61,6 @@ public interface IClient<TState, TSelf>
6261
where TSelf : ClientBase, IClient<TState, TSelf>
6362
where TState : class, IClientState<TSelf, TState>, new() { }
6463

65-
public static class ClientExtensions
66-
{
67-
public static ProxyFactory<TClient, TClientState> GetProxyFactory<TClient, TClientState>(this IClient<TClientState, TClient> client)
68-
where TClient : ClientBase, IClient<TClientState, TClient>
69-
where TClientState : class, IClientState<TClient, TClientState>, new()
70-
=> new(client as TClient ?? throw new ArgumentOutOfRangeException(nameof(client)));
71-
72-
public readonly struct ProxyFactory<TClient, TClientState>
73-
where TClient : ClientBase, IClient<TClientState, TClient>
74-
where TClientState : class, IClientState<TClient, TClientState>, new()
75-
{
76-
private readonly TClient _client;
77-
78-
internal ProxyFactory(TClient client) => _client = client;
79-
80-
public TProxy GetProxy<TProxy>() where TProxy : class
81-
=> new ServiceClientProper<TClient, TClientState>(_client, typeof(TProxy))
82-
.CreateProxy<TProxy>();
83-
}
84-
}
85-
8664
public interface IClientState<TClient, TSelf> : IDisposable
8765
where TSelf : class, IClientState<TClient, TSelf>, new()
8866
where TClient : ClientBase, IClient<TSelf, TClient>

src/UiPath.CoreIpc/GlobalUsings.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@
55
global using Accept = System.Func<System.Threading.CancellationToken, System.Threading.Tasks.Task<System.Net.WebSockets.WebSocket>>;
66
global using Network = UiPath.Ipc.Extensibility.OneOf<UiPath.Ipc.IAsyncStream, System.IO.Stream>;
77
global using ContractToSettingsMap = System.Collections.Generic.Dictionary<string, UiPath.Ipc.EndpointSettings>;
8-
global using AccessControlDelegate = System.Action<System.IO.Pipes.PipeSecurity>;
8+
global using AccessControlDelegate = System.Action<System.IO.Pipes.PipeSecurity>;
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)