From 7e6dc6415d84f4b759048998fd3c0ac84ebead7b Mon Sep 17 00:00:00 2001 From: yallie Date: Sat, 29 Jun 2024 03:13:36 +0300 Subject: [PATCH 1/4] Added a simulated missing method exception test. --- CoreRemoting.Tests/RemotingServicesTests.cs | 2 +- CoreRemoting.Tests/RpcTests.cs | 123 +++++++++++------- .../Tools/CustomMessageBuilder.cs | 48 +++++++ CoreRemoting.Tests/Tools/IEnumTestService.cs | 5 + CoreRemoting/Properties/AssemblyInfo.cs | 3 + CoreRemoting/RemotingClient.cs | 4 +- CoreRemoting/RemotingSession.cs | 2 +- 7 files changed, 137 insertions(+), 50 deletions(-) create mode 100644 CoreRemoting.Tests/Tools/CustomMessageBuilder.cs create mode 100644 CoreRemoting/Properties/AssemblyInfo.cs diff --git a/CoreRemoting.Tests/RemotingServicesTests.cs b/CoreRemoting.Tests/RemotingServicesTests.cs index a99f1e5..fc9d87a 100644 --- a/CoreRemoting.Tests/RemotingServicesTests.cs +++ b/CoreRemoting.Tests/RemotingServicesTests.cs @@ -51,7 +51,7 @@ public void Marshal_should_register_a_service_instance() var testService = new TestService(); using var server = new RemotingServer(); - server.Start(); + server.Start(); string serviceName = RemotingServices.Marshal(testService, "test", typeof(ITestService), server.UniqueServerInstanceName); diff --git a/CoreRemoting.Tests/RpcTests.cs b/CoreRemoting.Tests/RpcTests.cs index 47bc59b..71e497a 100644 --- a/CoreRemoting.Tests/RpcTests.cs +++ b/CoreRemoting.Tests/RpcTests.cs @@ -14,12 +14,12 @@ public class RpcTests : IClassFixture private readonly ServerFixture _serverFixture; private readonly ITestOutputHelper _testOutputHelper; private bool _remoteServiceCalled; - + public RpcTests(ServerFixture serverFixture, ITestOutputHelper testOutputHelper) { _serverFixture = serverFixture; _testOutputHelper = testOutputHelper; - + _serverFixture.TestService.TestMethodFake = arg => { _remoteServiceCalled = true; @@ -36,10 +36,10 @@ void ClientAction() { var stopWatch = new Stopwatch(); stopWatch.Start(); - + using var client = new RemotingClient(new ClientConfig() { - ConnectionTimeout = 0, + ConnectionTimeout = 0, MessageEncryption = false, ServerPort = _serverFixture.Server.Config.NetworkPort }); @@ -48,38 +48,38 @@ void ClientAction() _testOutputHelper.WriteLine($"Creating client took {stopWatch.ElapsedMilliseconds} ms"); stopWatch.Reset(); stopWatch.Start(); - + client.Connect(); stopWatch.Stop(); _testOutputHelper.WriteLine($"Establishing connection took {stopWatch.ElapsedMilliseconds} ms"); stopWatch.Reset(); stopWatch.Start(); - + var proxy = client.CreateProxy(); - + stopWatch.Stop(); _testOutputHelper.WriteLine($"Creating proxy took {stopWatch.ElapsedMilliseconds} ms"); stopWatch.Reset(); stopWatch.Start(); - + var result = proxy.TestMethod("test"); stopWatch.Stop(); _testOutputHelper.WriteLine($"Remote method invocation took {stopWatch.ElapsedMilliseconds} ms"); stopWatch.Reset(); stopWatch.Start(); - + var result2 = proxy.TestMethod("test"); stopWatch.Stop(); _testOutputHelper.WriteLine($"Second remote method invocation took {stopWatch.ElapsedMilliseconds} ms"); - + Assert.Equal("test", result); Assert.Equal("test", result2); - + proxy.MethodWithOutParameter(out int methodCallCount); - + Assert.Equal(1, methodCallCount); } catch (Exception e) @@ -92,26 +92,26 @@ void ClientAction() var clientThread = new Thread(ClientAction); clientThread.Start(); clientThread.Join(); - + Assert.True(_remoteServiceCalled); - Assert.Equal(0, _serverFixture.ServerErrorCount); + Assert.Equal(0, _serverFixture.ServerErrorCount); } - + [Fact] public void Call_on_Proxy_should_be_invoked_on_remote_service_with_MessageEncryption() { _serverFixture.Server.Config.MessageEncryption = true; - + void ClientAction() { try { var stopWatch = new Stopwatch(); stopWatch.Start(); - + using var client = new RemotingClient(new ClientConfig() { - ConnectionTimeout = 0, + ConnectionTimeout = 0, ServerPort = _serverFixture.Server.Config.NetworkPort, MessageEncryption = true }); @@ -120,33 +120,33 @@ void ClientAction() _testOutputHelper.WriteLine($"Creating client took {stopWatch.ElapsedMilliseconds} ms"); stopWatch.Reset(); stopWatch.Start(); - + client.Connect(); stopWatch.Stop(); _testOutputHelper.WriteLine($"Establishing connection took {stopWatch.ElapsedMilliseconds} ms"); stopWatch.Reset(); stopWatch.Start(); - + var proxy = client.CreateProxy(); - + stopWatch.Stop(); _testOutputHelper.WriteLine($"Creating proxy took {stopWatch.ElapsedMilliseconds} ms"); stopWatch.Reset(); stopWatch.Start(); - + var result = proxy.TestMethod("test"); stopWatch.Stop(); _testOutputHelper.WriteLine($"Remote method invocation took {stopWatch.ElapsedMilliseconds} ms"); stopWatch.Reset(); stopWatch.Start(); - + var result2 = proxy.TestMethod("test"); stopWatch.Stop(); _testOutputHelper.WriteLine($"Second remote method invocation took {stopWatch.ElapsedMilliseconds} ms"); - + Assert.Equal("test", result); Assert.Equal("test", result2); } @@ -160,9 +160,9 @@ void ClientAction() var clientThread = new Thread(ClientAction); clientThread.Start(); clientThread.Join(); - + _serverFixture.Server.Config.MessageEncryption = true; - + Assert.True(_remoteServiceCalled); Assert.Equal(0, _serverFixture.ServerErrorCount); } @@ -179,7 +179,7 @@ void ClientAction() using var client = new RemotingClient( new ClientConfig() { - ConnectionTimeout = 0, + ConnectionTimeout = 0, MessageEncryption = false, ServerPort = _serverFixture.Server.Config.NetworkPort, }); @@ -199,21 +199,21 @@ void ClientAction() var clientThread = new Thread(ClientAction); clientThread.Start(); clientThread.Join(); - + Assert.Equal("test", argumentFromServer); Assert.Equal(0, _serverFixture.ServerErrorCount); } - + [Fact] public void Events_should_work_remotly() { bool serviceEventCalled = false; bool customDelegateEventCalled = false; - + using var client = new RemotingClient( new ClientConfig() { - ConnectionTimeout = 0, + ConnectionTimeout = 0, SendTimeout = 0, MessageEncryption = false, ServerPort = _serverFixture.Server.Config.NetworkPort, @@ -237,18 +237,18 @@ public void Events_should_work_remotly() customDelegateEventCalled = true; customDelegateEventResetEvent.Set(); }; - + proxy.FireServiceEvent(); proxy.FireCustomDelegateEvent(); serviceEventResetEvent.Wait(1000); customDelegateEventResetEvent.Wait(1000); - + Assert.True(serviceEventCalled); Assert.True(customDelegateEventCalled); Assert.Equal(0, _serverFixture.ServerErrorCount); } - + [Fact] public void External_types_should_work_as_remote_service_parameters() { @@ -266,7 +266,7 @@ void ClientAction() { using var client = new RemotingClient(new ClientConfig() { - ConnectionTimeout = 0, + ConnectionTimeout = 0, MessageEncryption = false, ServerPort = _serverFixture.Server.Config.NetworkPort, }); @@ -274,7 +274,7 @@ void ClientAction() client.Connect(); var proxy = client.CreateProxy(); - proxy.TestExternalTypeParameter(new DataClass() {Value = 42}); + proxy.TestExternalTypeParameter(new DataClass() { Value = 42 }); Assert.Equal(42, parameterValue.Value); } @@ -288,17 +288,17 @@ void ClientAction() var clientThread = new Thread(ClientAction); clientThread.Start(); clientThread.Join(); - + Assert.True(_remoteServiceCalled); Assert.Equal(0, _serverFixture.ServerErrorCount); } - + [Fact] public void Generic_methods_should_be_called_correctly() { using var client = new RemotingClient(new ClientConfig() { - ConnectionTimeout = 0, + ConnectionTimeout = 0, MessageEncryption = false, ServerPort = _serverFixture.Server.Config.NetworkPort, }); @@ -307,16 +307,16 @@ public void Generic_methods_should_be_called_correctly() var proxy = client.CreateProxy(); var result = proxy.Echo("Yay"); - + Assert.Equal("Yay", result); } - + [Fact] public void Inherited_methods_should_be_called_correctly() { using var client = new RemotingClient(new ClientConfig() { - ConnectionTimeout = 0, + ConnectionTimeout = 0, MessageEncryption = false, ServerPort = _serverFixture.Server.Config.NetworkPort, }); @@ -325,16 +325,16 @@ public void Inherited_methods_should_be_called_correctly() var proxy = client.CreateProxy(); var result = proxy.BaseMethod(); - + Assert.True(result); } - + [Fact] public void Enum_arguments_should_be_passed_correctly() { using var client = new RemotingClient(new ClientConfig() { - ConnectionTimeout = 0, + ConnectionTimeout = 0, MessageEncryption = false, ServerPort = _serverFixture.Server.Config.NetworkPort }); @@ -344,9 +344,40 @@ public void Enum_arguments_should_be_passed_correctly() var resultFirst = proxy.Echo(TestEnum.First); var resultSecond = proxy.Echo(TestEnum.Second); - + Assert.Equal(TestEnum.First, resultFirst); Assert.Equal(TestEnum.Second, resultSecond); } + + [Fact] + public void Missing_method_throws_MissingMethodException() + { + using var client = new RemotingClient(new ClientConfig() + { + ConnectionTimeout = 0, + InvocationTimeout = 0, + MessageEncryption = false, + ServerPort = _serverFixture.Server.Config.NetworkPort + }); + + // simulate MissingMethodException + var mb = new CustomMessageBuilder + { + ProcessMethodCallMessage = m => + { + if (m.MethodName == "TestMethod") + { + m.MethodName = "Missing Method"; + } + } + }; + + client.MethodCallMessageBuilder = mb; + client.Connect(); + + var proxy = client.CreateProxy(); + var result = proxy.TestMethod(null); + Assert.Fail(); + } } } \ No newline at end of file diff --git a/CoreRemoting.Tests/Tools/CustomMessageBuilder.cs b/CoreRemoting.Tests/Tools/CustomMessageBuilder.cs new file mode 100644 index 0000000..338e02b --- /dev/null +++ b/CoreRemoting.Tests/Tools/CustomMessageBuilder.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using CoreRemoting.RpcMessaging; +using CoreRemoting.Serialization; + +namespace CoreRemoting.Tests.Tools +{ + /// + /// Custom client-side RPC message processor. + /// + public class CustomMessageBuilder : IMethodCallMessageBuilder + { + public CustomMessageBuilder() + { + Builder = new MethodCallMessageBuilder(); + } + + public Action ProcessMethodCallMessage { get; set; } = m => { }; + + public Action> ProcessMethodParameterInfos { get; set; } = m => { }; + + public Action ProcessMethodCallResultMessage { get; set; } = m => { }; + + private MethodCallMessageBuilder Builder { get; set; } + + public MethodCallMessage BuildMethodCallMessage(ISerializerAdapter serializer, string remoteServiceName, MethodInfo targetMethod, object[] args) + { + var m = Builder.BuildMethodCallMessage(serializer, remoteServiceName, targetMethod, args); + ProcessMethodCallMessage(m); + return m; + } + + public IEnumerable BuildMethodParameterInfos(ISerializerAdapter serializer, MethodInfo targetMethod, object[] args) + { + var m = Builder.BuildMethodParameterInfos(serializer, targetMethod, args); + ProcessMethodParameterInfos(m); + return m; + } + + public MethodCallResultMessage BuildMethodCallResultMessage(ISerializerAdapter serializer, Guid uniqueCallKey, MethodInfo method, object[] args, object returnValue) + { + var m = Builder.BuildMethodCallResultMessage(serializer, uniqueCallKey, method, args, returnValue); + ProcessMethodCallResultMessage(m); + return m; + } + } +} diff --git a/CoreRemoting.Tests/Tools/IEnumTestService.cs b/CoreRemoting.Tests/Tools/IEnumTestService.cs index d7c7478..8cbac5f 100644 --- a/CoreRemoting.Tests/Tools/IEnumTestService.cs +++ b/CoreRemoting.Tests/Tools/IEnumTestService.cs @@ -9,4 +9,9 @@ public enum TestEnum public interface IEnumTestService { TestEnum Echo(TestEnum inputValue); + + TestEnum Echo2(TestEnum input) + { + return input; + } } \ No newline at end of file diff --git a/CoreRemoting/Properties/AssemblyInfo.cs b/CoreRemoting/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..fc984af --- /dev/null +++ b/CoreRemoting/Properties/AssemblyInfo.cs @@ -0,0 +1,3 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("CoreRemoting.Tests")] \ No newline at end of file diff --git a/CoreRemoting/RemotingClient.cs b/CoreRemoting/RemotingClient.cs index 1524a1d..5217fd1 100644 --- a/CoreRemoting/RemotingClient.cs +++ b/CoreRemoting/RemotingClient.cs @@ -147,12 +147,12 @@ private void OnDisconnected() /// /// Gets the proxy generator instance. /// - private static readonly ProxyGenerator ProxyGenerator = new ProxyGenerator(); + private static readonly ProxyGenerator ProxyGenerator = new ProxyGenerator(); /// /// Gets a utility object for building remoting messages. /// - internal IMethodCallMessageBuilder MethodCallMessageBuilder { get; } + internal IMethodCallMessageBuilder MethodCallMessageBuilder { get; set; } /// /// Gets a utility object to provide encryption of remoting messages. diff --git a/CoreRemoting/RemotingSession.cs b/CoreRemoting/RemotingSession.cs index c355f88..2e4a9f7 100644 --- a/CoreRemoting/RemotingSession.cs +++ b/CoreRemoting/RemotingSession.cs @@ -419,7 +419,7 @@ private void ProcessRpcMessage(WireMessage request) parameterValues = MapArguments(parameterValues, parameterTypes); MethodInfo method; - + if (callMessage.GenericArgumentTypeNames != null && callMessage.GenericArgumentTypeNames.Length > 0) { var methods = From a9c8041a16a143e7489fef0fa36352b92f360e5c Mon Sep 17 00:00:00 2001 From: yallie Date: Sat, 29 Jun 2024 22:41:57 +0300 Subject: [PATCH 2/4] Extracted GetMethodInfo method from ProcessRpcMessage. --- CoreRemoting.Tests/RpcTests.cs | 4 +- CoreRemoting.Tests/Tools/IEnumTestService.cs | 5 - CoreRemoting/RemotingSession.cs | 116 ++++++++++--------- 3 files changed, 63 insertions(+), 62 deletions(-) diff --git a/CoreRemoting.Tests/RpcTests.cs b/CoreRemoting.Tests/RpcTests.cs index 71e497a..efe7778 100644 --- a/CoreRemoting.Tests/RpcTests.cs +++ b/CoreRemoting.Tests/RpcTests.cs @@ -376,8 +376,8 @@ public void Missing_method_throws_MissingMethodException() client.Connect(); var proxy = client.CreateProxy(); - var result = proxy.TestMethod(null); - Assert.Fail(); + //var result = proxy.TestMethod(null); + //Assert.Fail(); } } } \ No newline at end of file diff --git a/CoreRemoting.Tests/Tools/IEnumTestService.cs b/CoreRemoting.Tests/Tools/IEnumTestService.cs index 8cbac5f..d7c7478 100644 --- a/CoreRemoting.Tests/Tools/IEnumTestService.cs +++ b/CoreRemoting.Tests/Tools/IEnumTestService.cs @@ -9,9 +9,4 @@ public enum TestEnum public interface IEnumTestService { TestEnum Echo(TestEnum inputValue); - - TestEnum Echo2(TestEnum input) - { - return input; - } } \ No newline at end of file diff --git a/CoreRemoting/RemotingSession.cs b/CoreRemoting/RemotingSession.cs index 2e4a9f7..89c3aa4 100644 --- a/CoreRemoting/RemotingSession.cs +++ b/CoreRemoting/RemotingSession.cs @@ -385,15 +385,15 @@ private void ProcessRpcMessage(WireMessage request) sharedSecret: sharedSecret, sendersPublicKeyBlob: _clientPublicKeyBlob, sendersPublicKeySize: _keyPair?.KeySize ?? 0); - + var callMessage = _server.Serializer .Deserialize(decryptedRawMessage); - ServerRpcContext serverRpcContext = + ServerRpcContext serverRpcContext = new ServerRpcContext { - UniqueCallKey = + UniqueCallKey = request.UniqueCallKey == null ? Guid.Empty : new Guid(request.UniqueCallKey), @@ -403,7 +403,7 @@ private void ProcessRpcMessage(WireMessage request) }; var serializedResult = new byte[] { }; - + var service = _server.ServiceRegistry.GetService(callMessage.ServiceName); var serviceInterfaceType = _server.ServiceRegistry.GetServiceInterfaceType(callMessage.ServiceName); @@ -411,62 +411,14 @@ private void ProcessRpcMessage(WireMessage request) CallContext.RestoreFromSnapshot(callMessage.CallContextSnapshot); serverRpcContext.ServiceInstance = service; - + callMessage.UnwrapParametersFromDeserializedMethodCallMessage( - out var parameterValues, + out var parameterValues, out var parameterTypes); parameterValues = MapArguments(parameterValues, parameterTypes); - MethodInfo method; - - if (callMessage.GenericArgumentTypeNames != null && callMessage.GenericArgumentTypeNames.Length > 0) - { - var methods = - serviceInterfaceType.GetMethods().ToList(); - - foreach (var inheritedInterface in serviceInterfaceType.GetInterfaces()) - { - methods.AddRange(inheritedInterface.GetMethods()); - } - - method = - methods.SingleOrDefault(m => - m.IsGenericMethod && - m.Name.Equals(callMessage.MethodName, StringComparison.Ordinal)); - - if (method != null) - { - Type[] genericArguments = - callMessage.GenericArgumentTypeNames - .Select(typeName => Type.GetType(typeName)) - .ToArray(); - - method = method.MakeGenericMethod(genericArguments); - } - } - else - { - method = - serviceInterfaceType.GetMethod( - name: callMessage.MethodName, - types: parameterTypes); - - if (method == null) - { - foreach (var inheritedInterface in serviceInterfaceType.GetInterfaces()) - { - method = - inheritedInterface.GetMethod( - name: callMessage.MethodName, - types: parameterTypes); - - if (method != null) - break; - } - } - } - + var method = GetMethodInfo(callMessage, serviceInterfaceType, parameterTypes); if (method == null) throw new MissingMethodException( className: callMessage.ServiceName, @@ -587,6 +539,60 @@ private void ProcessRpcMessage(WireMessage request) CurrentSession.Value = null; } + private MethodInfo GetMethodInfo(MethodCallMessage callMessage, Type serviceInterfaceType, Type[] parameterTypes) + { + MethodInfo method; + + if (callMessage.GenericArgumentTypeNames != null && callMessage.GenericArgumentTypeNames.Length > 0) + { + var methods = + serviceInterfaceType.GetMethods().ToList(); + + foreach (var inheritedInterface in serviceInterfaceType.GetInterfaces()) + { + methods.AddRange(inheritedInterface.GetMethods()); + } + + method = + methods.SingleOrDefault(m => + m.IsGenericMethod && + m.Name.Equals(callMessage.MethodName, StringComparison.Ordinal)); + + if (method != null) + { + Type[] genericArguments = + callMessage.GenericArgumentTypeNames + .Select(typeName => Type.GetType(typeName)) + .ToArray(); + + method = method.MakeGenericMethod(genericArguments); + } + } + else + { + method = + serviceInterfaceType.GetMethod( + name: callMessage.MethodName, + types: parameterTypes); + + if (method == null) + { + foreach (var inheritedInterface in serviceInterfaceType.GetInterfaces()) + { + method = + inheritedInterface.GetMethod( + name: callMessage.MethodName, + types: parameterTypes); + + if (method != null) + break; + } + } + } + + return method; + } + /// /// Maps non serializable arguments into a serializable form. /// From 98e0c1969a3031a5076059e2ddb42e9447772e37 Mon Sep 17 00:00:00 2001 From: yallie Date: Sat, 29 Jun 2024 23:18:21 +0300 Subject: [PATCH 3/4] Added dotnet workflow. --- .github/workflows/dotnet.yml | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 .github/workflows/dotnet.yml diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml new file mode 100644 index 0000000..789431e --- /dev/null +++ b/.github/workflows/dotnet.yml @@ -0,0 +1,35 @@ +name: .NET + +on: + push: +# branches: +# - master +# - release/* + pull_request: + branches: + - master + - release/* + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - name: Checkout source + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: | + 6.0.x + 7.0.x + 8.0.x + - name: Restore dependencies + run: dotnet restore + - name: Build + run: dotnet build --no-restore + - name: Test + run: dotnet test --no-build --verbosity normal From f0779f733de354aae8badb1040b2fa76b8761491 Mon Sep 17 00:00:00 2001 From: yallie Date: Sun, 30 Jun 2024 00:02:35 +0300 Subject: [PATCH 4/4] Service resolution and method search on the server should report errors back to the client. --- CoreRemoting.Tests/RpcTests.cs | 32 +++++- CoreRemoting/RemotingSession.cs | 166 ++++++++++++++++++-------------- 2 files changed, 122 insertions(+), 76 deletions(-) diff --git a/CoreRemoting.Tests/RpcTests.cs b/CoreRemoting.Tests/RpcTests.cs index efe7778..124ee9a 100644 --- a/CoreRemoting.Tests/RpcTests.cs +++ b/CoreRemoting.Tests/RpcTests.cs @@ -350,12 +350,13 @@ public void Enum_arguments_should_be_passed_correctly() } [Fact] - public void Missing_method_throws_MissingMethodException() + public void Missing_method_throws_RemoteInvocationException() { using var client = new RemotingClient(new ClientConfig() { ConnectionTimeout = 0, InvocationTimeout = 0, + SendTimeout = 0, MessageEncryption = false, ServerPort = _serverFixture.Server.Config.NetworkPort }); @@ -376,8 +377,33 @@ public void Missing_method_throws_MissingMethodException() client.Connect(); var proxy = client.CreateProxy(); - //var result = proxy.TestMethod(null); - //Assert.Fail(); + var ex = Assert.Throws(() => proxy.TestMethod(null)); + + // a localized message similar to "Method 'Missing method' not found" + Assert.NotNull(ex); + Assert.Contains("Missing Method", ex.Message); + } + + [Fact] + public void Missing_service_throws_RemoteInvocationException() + { + using var client = new RemotingClient(new ClientConfig() + { + ConnectionTimeout = 0, + InvocationTimeout = 0, + SendTimeout = 0, + MessageEncryption = false, + ServerPort = _serverFixture.Server.Config.NetworkPort + }); + + client.Connect(); + + var proxy = client.CreateProxy(); + var ex = Assert.Throws(() => proxy.Dispose()); + + // a localized message similar to "Service 'System.IDisposable' is not registered" + Assert.NotNull(ex); + Assert.Contains("IDisposable", ex.Message); } } } \ No newline at end of file diff --git a/CoreRemoting/RemotingSession.cs b/CoreRemoting/RemotingSession.cs index 89c3aa4..82905ff 100644 --- a/CoreRemoting/RemotingSession.cs +++ b/CoreRemoting/RemotingSession.cs @@ -402,82 +402,38 @@ private void ProcessRpcMessage(WireMessage request) Session = this }; - var serializedResult = new byte[] { }; - - var service = _server.ServiceRegistry.GetService(callMessage.ServiceName); - var serviceInterfaceType = - _server.ServiceRegistry.GetServiceInterfaceType(callMessage.ServiceName); - - CallContext.RestoreFromSnapshot(callMessage.CallContextSnapshot); - - serverRpcContext.ServiceInstance = service; - - callMessage.UnwrapParametersFromDeserializedMethodCallMessage( - out var parameterValues, - out var parameterTypes); - - parameterValues = MapArguments(parameterValues, parameterTypes); - - var method = GetMethodInfo(callMessage, serviceInterfaceType, parameterTypes); - if (method == null) - throw new MissingMethodException( - className: callMessage.ServiceName, - methodName: callMessage.MethodName); - - var oneWay = method.GetCustomAttribute() != null; - - if (_server.Config.AuthenticationRequired && !_isAuthenticated) - throw new NetworkException("Session is not authenticated."); - - object result = null; + var serializedResult = Array.Empty(); + var method = default(MethodInfo); + var parameterValues = Array.Empty(); + var parameterTypes = Array.Empty(); + var oneWay = false; try { - CurrentSession.Value = this; + var service = _server.ServiceRegistry.GetService(callMessage.ServiceName); + var serviceInterfaceType = + _server.ServiceRegistry.GetServiceInterfaceType(callMessage.ServiceName); - ((RemotingServer)_server).OnBeforeCall(serverRpcContext); + CallContext.RestoreFromSnapshot(callMessage.CallContextSnapshot); - result = method.Invoke(service, parameterValues); + serverRpcContext.ServiceInstance = service; - var returnType = method.ReturnType; + callMessage.UnwrapParametersFromDeserializedMethodCallMessage( + out parameterValues, + out parameterTypes); - if (result != null) - { - // Wait for result value if result is a Task - if (typeof(Task).IsAssignableFrom(returnType)) - { - var resultTask = (Task)result; - resultTask.Wait(); + parameterValues = MapArguments(parameterValues, parameterTypes); - if (returnType.IsGenericType) - { - result = returnType.GetProperty("Result")?.GetValue(resultTask); - } - else // ordinary non-generic task - { - result = null; - } - } - else if (returnType.GetCustomAttribute() != null) - { - var isRegisteredService = - returnType.IsInterface && - _server.ServiceRegistry - .GetAllRegisteredTypes().Any(s => - returnType.AssemblyQualifiedName != null && - returnType.AssemblyQualifiedName.Equals(s.AssemblyQualifiedName)); - - if (!isRegisteredService) - { - throw new InvalidOperationException( - $"Type '{returnType.AssemblyQualifiedName}' is not a registered service."); - } + method = GetMethodInfo(callMessage, serviceInterfaceType, parameterTypes); + if (method == null) + throw new MissingMethodException( + className: callMessage.ServiceName, + methodName: callMessage.MethodName); - result = new ServiceReference( - serviceInterfaceTypeName: returnType.FullName + ", " + returnType.Assembly.GetName().Name, - serviceName: returnType.FullName); - } - } + oneWay = method.GetCustomAttribute() != null; + + if (_server.Config.AuthenticationRequired && !_isAuthenticated) + throw new NetworkException("Session is not authenticated."); } catch (Exception ex) { @@ -486,21 +442,85 @@ private void ProcessRpcMessage(WireMessage request) message: ex.Message, innerEx: ex.GetType().IsSerializable ? ex : null); - ((RemotingServer)_server).OnAfterCall(serverRpcContext); - if (oneWay) return; serializedResult = _server.Serializer.Serialize(serverRpcContext.Exception); } - finally - { - CurrentSession.Value = null; - } + + object result = null; if (serverRpcContext.Exception == null) { + try + { + CurrentSession.Value = this; + + ((RemotingServer)_server).OnBeforeCall(serverRpcContext); + + result = method.Invoke(serverRpcContext.ServiceInstance, parameterValues); + + var returnType = method.ReturnType; + + if (result != null) + { + // Wait for result value if result is a Task + if (typeof(Task).IsAssignableFrom(returnType)) + { + var resultTask = (Task)result; + resultTask.Wait(); + + if (returnType.IsGenericType) + { + result = returnType.GetProperty("Result")?.GetValue(resultTask); + } + else // ordinary non-generic task + { + result = null; + } + } + else if (returnType.GetCustomAttribute() != null) + { + var isRegisteredService = + returnType.IsInterface && + _server.ServiceRegistry + .GetAllRegisteredTypes().Any(s => + returnType.AssemblyQualifiedName != null && + returnType.AssemblyQualifiedName.Equals(s.AssemblyQualifiedName)); + + if (!isRegisteredService) + { + throw new InvalidOperationException( + $"Type '{returnType.AssemblyQualifiedName}' is not a registered service."); + } + + result = new ServiceReference( + serviceInterfaceTypeName: returnType.FullName + ", " + returnType.Assembly.GetName().Name, + serviceName: returnType.FullName); + } + } + } + catch (Exception ex) + { + serverRpcContext.Exception = + new RemoteInvocationException( + message: ex.Message, + innerEx: ex.GetType().IsSerializable ? ex : null); + + ((RemotingServer)_server).OnAfterCall(serverRpcContext); + + if (oneWay) + return; + + serializedResult = + _server.Serializer.Serialize(serverRpcContext.Exception); + } + finally + { + CurrentSession.Value = null; + } + if (!oneWay) { serverRpcContext.MethodCallResultMessage =